Ejemplo n.º 1
0
        public void IssueAssetsBlockSerializerTest()
        {
            ulong syncBlockHeight = 1;
            uint  nonce           = 4;

            byte[] powHash     = BinaryHelper.GetPowHash(1234);
            ushort version     = 1;
            ulong  blockHeight = 9;

            byte[] body;

            ulong  uptodateFunds = 10001;
            ushort ownedNonBlindedAssetGroupsCount = 3, ownedBlindedAssetGroupsCount = 3;
            ushort ownedNonBlindedAssetIdsCount = 5, ownedAssetCommitmentsCount = 5;

            uint[]     nonBlindedGroupIds    = new uint[ownedNonBlindedAssetGroupsCount];
            byte[][][] ownedAssetIds         = new byte[ownedNonBlindedAssetGroupsCount][][];
            ulong[][]  ownedAssetAmounts     = new ulong[ownedNonBlindedAssetGroupsCount][];
            uint[]     blindedGroupIds       = new uint[ownedBlindedAssetGroupsCount];
            byte[][][] ownedAssetCommitments = new byte[ownedBlindedAssetGroupsCount][][];

            ushort issuanceNonBlindedGroupsCount = 2, issuanceBlindedGroupsCount = 2;
            ushort issuedNonBlindedAssetsCount = 10, issuedBlindedAssetsCount = 10;

            uint[]     issuanceNonBlindedGroupIds = new uint[issuanceNonBlindedGroupsCount], issuanceBlindedGroupIds = new uint[issuanceBlindedGroupsCount];
            byte[][][] issuedNonBlindedAssetIds   = new byte[issuanceNonBlindedGroupsCount][][];
            string[][] issuedNonBlindedAssetInfos = new string[issuanceNonBlindedGroupsCount][];

            byte[][][] issuedAssetCommitments  = new byte[issuanceBlindedGroupsCount][][];
            byte[][][] issuedBlindedAssetIds   = new byte[issuanceNonBlindedGroupsCount][][];
            string[][] issuedBlindedAssetInfos = new string[issuanceNonBlindedGroupsCount][];

            byte[][][] surjectionProofCommitments = new byte[issuanceBlindedGroupsCount][][];
            byte[][][] surjectionProofE           = new byte[issuanceBlindedGroupsCount][][];
            byte[][][] surjectionProofS           = new byte[issuanceBlindedGroupsCount][][];
            byte[][][] issuanceProofMask          = new byte[issuanceBlindedGroupsCount][][];

            for (int i = 0; i < issuanceNonBlindedGroupsCount; i++)
            {
                issuanceNonBlindedGroupIds[i] = (uint)i;
                issuedNonBlindedAssetIds[i]   = new byte[issuedNonBlindedAssetsCount][];
                issuedNonBlindedAssetInfos[i] = new string[issuedNonBlindedAssetsCount];

                for (int j = 0; j < issuedNonBlindedAssetsCount; j++)
                {
                    issuedNonBlindedAssetIds[i][j]   = ConfidentialAssetsHelper.GetRandomSeed();
                    issuedNonBlindedAssetInfos[i][j] = $"Issued Asset #{i}_{j}";
                }
            }

            for (int i = 0; i < issuanceBlindedGroupsCount; i++)
            {
                issuanceBlindedGroupIds[i]    = (uint)i + 10;
                issuedAssetCommitments[i]     = new byte[issuedBlindedAssetsCount][];
                issuedBlindedAssetIds[i]      = new byte[issuedBlindedAssetsCount][];
                issuedBlindedAssetInfos[i]    = new string[issuedBlindedAssetsCount];
                surjectionProofCommitments[i] = new byte[issuedBlindedAssetsCount][];
                surjectionProofE[i]           = new byte[issuedBlindedAssetsCount][];
                surjectionProofS[i]           = new byte[issuedBlindedAssetsCount][];
                issuanceProofMask[i]          = new byte[issuedBlindedAssetsCount][];

                for (int j = 0; j < issuedBlindedAssetsCount; j++)
                {
                    issuedAssetCommitments[i][j]     = ConfidentialAssetsHelper.GetRandomSeed();
                    issuedBlindedAssetIds[i][j]      = ConfidentialAssetsHelper.GetRandomSeed();
                    issuedBlindedAssetInfos[i][j]    = $"Issued Blinded Asset #{i}_{j}";
                    surjectionProofCommitments[i][j] = ConfidentialAssetsHelper.GetRandomSeed();
                    surjectionProofE[i][j]           = ConfidentialAssetsHelper.GetRandomSeed();
                    surjectionProofS[i][j]           = ConfidentialAssetsHelper.GetRandomSeed();
                    issuanceProofMask[i][j]          = ConfidentialAssetsHelper.GetRandomSeed();
                }
            }

            string issuanceInfo = "Issuance Info";

            Random random = new Random();

            for (int i = 0; i < ownedNonBlindedAssetGroupsCount; i++)
            {
                nonBlindedGroupIds[i] = (uint)i;
                ownedAssetIds[i]      = new byte[ownedNonBlindedAssetIdsCount][];
                ownedAssetAmounts[i]  = new ulong[ownedNonBlindedAssetIdsCount];

                for (int j = 0; j < ownedNonBlindedAssetIdsCount; j++)
                {
                    ownedAssetIds[i][j]     = ConfidentialAssetsHelper.GetRandomSeed();
                    ownedAssetAmounts[i][j] = (ulong)random.Next();
                }
            }

            for (int i = 0; i < ownedBlindedAssetGroupsCount; i++)
            {
                blindedGroupIds[i]       = (uint)i + 10;
                ownedAssetCommitments[i] = new byte[ownedAssetCommitmentsCount][];

                for (int j = 0; j < ownedAssetCommitmentsCount; j++)
                {
                    ownedAssetCommitments[i][j] = ConfidentialAssetsHelper.GetRandomSeed();
                }
            }

            using (MemoryStream ms = new MemoryStream())
            {
                using (BinaryWriter bw = new BinaryWriter(ms))
                {
                    bw.Write(uptodateFunds);

                    bw.Write(issuanceNonBlindedGroupsCount);
                    bw.Write(issuanceBlindedGroupsCount);

                    for (int i = 0; i < issuanceNonBlindedGroupsCount; i++)
                    {
                        bw.Write(issuanceNonBlindedGroupIds[i]);
                        bw.Write(issuedNonBlindedAssetsCount);

                        for (int j = 0; j < issuedNonBlindedAssetsCount; j++)
                        {
                            bw.Write(issuedNonBlindedAssetIds[i][j]);
                            byte strLen = (byte)issuedNonBlindedAssetInfos[i][j].Length;
                            bw.Write(strLen);
                            bw.Write(Encoding.ASCII.GetBytes(issuedNonBlindedAssetInfos[i][j]));
                        }
                    }

                    for (int i = 0; i < issuanceBlindedGroupsCount; i++)
                    {
                        bw.Write(issuanceBlindedGroupIds[i]);
                        bw.Write(issuedBlindedAssetsCount);

                        for (int j = 0; j < issuedBlindedAssetsCount; j++)
                        {
                            bw.Write(issuedAssetCommitments[i][j]);
                        }

                        for (int j = 0; j < issuedBlindedAssetsCount; j++)
                        {
                            bw.Write(issuedBlindedAssetIds[i][j]);
                            byte strLen = (byte)issuedBlindedAssetInfos[i][j].Length;
                            bw.Write(strLen);
                            bw.Write(Encoding.ASCII.GetBytes(issuedBlindedAssetInfos[i][j]));
                        }

                        for (int j = 0; j < issuedBlindedAssetsCount; j++)
                        {
                            bw.Write((ushort)1);
                            bw.Write(surjectionProofCommitments[i][j]);
                            bw.Write(surjectionProofE[i][j]);
                            bw.Write(surjectionProofS[i][j]);
                            bw.Write(issuanceProofMask[i][j]);
                        }
                    }

                    bw.Write((byte)issuanceInfo.Length);
                    bw.Write(Encoding.ASCII.GetBytes(issuanceInfo));

                    bw.Write(ownedNonBlindedAssetGroupsCount);
                    bw.Write(ownedBlindedAssetGroupsCount);

                    for (int i = 0; i < ownedNonBlindedAssetGroupsCount; i++)
                    {
                        bw.Write(nonBlindedGroupIds[i]);
                        bw.Write(ownedNonBlindedAssetIdsCount);

                        for (int j = 0; j < ownedNonBlindedAssetIdsCount; j++)
                        {
                            bw.Write(ownedAssetIds[i][j]);
                        }

                        for (int j = 0; j < ownedNonBlindedAssetIdsCount; j++)
                        {
                            bw.Write(ownedAssetAmounts[i][j]);
                        }
                    }

                    for (int i = 0; i < ownedBlindedAssetGroupsCount; i++)
                    {
                        bw.Write(blindedGroupIds[i]);
                        bw.Write(ownedAssetCommitmentsCount);

                        for (int j = 0; j < ownedAssetCommitmentsCount; j++)
                        {
                            bw.Write(ownedAssetCommitments[i][j]);
                        }
                    }
                }

                body = ms.ToArray();
            }

            byte[] expectedPacket = BinaryHelper.GetSignedPacket(PacketType.Transactional, syncBlockHeight, nonce, powHash, version,
                                                                 BlockTypes.Transaction_IssueGroupedAssets, blockHeight, null, body, _privateKey, out byte[] expectedSignature);

            AssetsIssuanceGroup[] assetsIssuanceGroups = new AssetsIssuanceGroup[issuanceNonBlindedGroupsCount];
            for (int i = 0; i < issuanceNonBlindedGroupsCount; i++)
            {
                assetsIssuanceGroups[i] = new AssetsIssuanceGroup
                {
                    GroupId        = issuanceNonBlindedGroupIds[i],
                    AssetIssuances = new AssetIssuance[issuedNonBlindedAssetsCount]
                };

                for (int j = 0; j < issuedNonBlindedAssetsCount; j++)
                {
                    assetsIssuanceGroups[i].AssetIssuances[j] = new AssetIssuance
                    {
                        AssetId         = issuedNonBlindedAssetIds[i][j],
                        IssuedAssetInfo = issuedNonBlindedAssetInfos[i][j]
                    };
                }
            }

            BlindedAssetsIssuanceGroup[] blindedAssetsIssuanceGroups = new BlindedAssetsIssuanceGroup[issuanceBlindedGroupsCount];
            for (int i = 0; i < issuanceBlindedGroupsCount; i++)
            {
                blindedAssetsIssuanceGroups[i] = new BlindedAssetsIssuanceGroup
                {
                    GroupId          = issuanceBlindedGroupIds[i],
                    AssetCommitments = issuedAssetCommitments[i],
                    AssetIssuances   = new AssetIssuance[issuedBlindedAssetsCount],
                    IssuanceProofs   = new IssuanceProof[issuedBlindedAssetsCount]
                };

                for (int j = 0; j < issuedBlindedAssetsCount; j++)
                {
                    blindedAssetsIssuanceGroups[i].AssetIssuances[j] = new AssetIssuance
                    {
                        AssetId         = issuedBlindedAssetIds[i][j],
                        IssuedAssetInfo = issuedBlindedAssetInfos[i][j]
                    };

                    blindedAssetsIssuanceGroups[i].IssuanceProofs[j] = new IssuanceProof
                    {
                        SurjectionProof = new SurjectionProof
                        {
                            AssetCommitments = new byte[][] { surjectionProofCommitments[i][j] },
                            Rs = new BorromeanRingSignature
                            {
                                E = surjectionProofE[i][j],
                                S = new byte[][] { surjectionProofS[i][j] }
                            }
                        },
                        Mask = issuanceProofMask[i][j]
                    };
                }
            }

            AssetsGroup[] assetsGroups = new AssetsGroup[ownedNonBlindedAssetGroupsCount];
            for (int i = 0; i < ownedNonBlindedAssetGroupsCount; i++)
            {
                assetsGroups[i] = new AssetsGroup
                {
                    GroupId      = nonBlindedGroupIds[i],
                    AssetIds     = ownedAssetIds[i],
                    AssetAmounts = ownedAssetAmounts[i]
                };
            }

            BlindedAssetsGroup[] blindedAssetsGroups = new BlindedAssetsGroup[ownedBlindedAssetGroupsCount];
            for (int i = 0; i < ownedBlindedAssetGroupsCount; i++)
            {
                blindedAssetsGroups[i] = new BlindedAssetsGroup
                {
                    GroupId          = blindedGroupIds[i],
                    AssetCommitments = ownedAssetCommitments[i]
                };
            }

            IssueGroupedAssets block = new IssueGroupedAssets
            {
                SyncBlockHeight             = syncBlockHeight,
                Nonce                       = nonce,
                PowHash                     = powHash,
                BlockHeight                 = blockHeight,
                UptodateFunds               = uptodateFunds,
                AssetsIssuanceGroups        = assetsIssuanceGroups,
                BlindedAssetsIssuanceGroups = blindedAssetsIssuanceGroups,
                AssetsGroups                = assetsGroups,
                BlindedAssetsGroups         = blindedAssetsGroups,
                IssuanceInfo                = issuanceInfo
            };

            IssueAssetsSerializer serializer = new IssueAssetsSerializer();

            serializer.Initialize(block);
            serializer.SerializeBody();
            _signingService.Sign(block);

            byte[] actualPacket = serializer.GetBytes();

            Assert.Equal(expectedPacket, actualPacket);
        }
Ejemplo n.º 2
0
        protected override Memory <byte> ParseTransactional(ushort version, Memory <byte> spanBody, out TransactionalPacketBase transactionalBlockBase)
        {
            if (version == 1)
            {
                int readBytes = 0;

                ushort acceptedUnblindingAssetABsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                readBytes += sizeof(ushort);

                ushort acceptedUnblindingAssetUtxosLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                readBytes += sizeof(ushort);

                AcceptedAssetUnblindingAB[]   acceptedUnblindingAssetABs   = new AcceptedAssetUnblindingAB[acceptedUnblindingAssetABsLength];
                AcceptedAssetUnblindingUtxo[] acceptedUnblindingAssetUtxos = new AcceptedAssetUnblindingUtxo[acceptedUnblindingAssetUtxosLength];

                for (int i = 0; i < acceptedUnblindingAssetABsLength; i++)
                {
                    byte[] assetId = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                    readBytes += Globals.NODE_PUBLIC_KEY_SIZE;
                    byte[] blindingFactor = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                    readBytes += Globals.NODE_PUBLIC_KEY_SIZE;
                    byte[] sourceAddress = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                    readBytes += Globals.NODE_PUBLIC_KEY_SIZE;
                    ulong height = BinaryPrimitives.ReadUInt64LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(ulong);

                    acceptedUnblindingAssetABs[i] = new AcceptedAssetUnblindingAB
                    {
                        AcceptedAssetsUnblinding = new AcceptedAssetUnblinding
                        {
                            AssetId        = assetId,
                            BlindingFactor = blindingFactor
                        },
                        SourceAddress = sourceAddress,
                        SourceHeight  = height
                    };
                }

                for (int i = 0; i < acceptedUnblindingAssetUtxosLength; i++)
                {
                    byte[] assetId = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                    readBytes += Globals.NODE_PUBLIC_KEY_SIZE;
                    byte[] blindingFactor = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                    readBytes += Globals.NODE_PUBLIC_KEY_SIZE;
                    byte[] sourceKey = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                    readBytes += Globals.NODE_PUBLIC_KEY_SIZE;

                    acceptedUnblindingAssetUtxos[i] = new AcceptedAssetUnblindingUtxo
                    {
                        AcceptedAssetsUnblinding = new AcceptedAssetUnblinding
                        {
                            AssetId        = assetId,
                            BlindingFactor = blindingFactor
                        },
                        SourceKey = sourceKey
                    };
                }

                ushort assetsGroupsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                readBytes += sizeof(ushort);

                AssetsGroup[] assetsGroups = new AssetsGroup[assetsGroupsLength];

                for (int i = 0; i < assetsGroupsLength; i++)
                {
                    uint groupId = BinaryPrimitives.ReadUInt32LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(uint);

                    ushort totalAssetIdsCount = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(ushort);

                    byte[][] assetIds = new byte[totalAssetIdsCount][];
                    ulong[]  amounts  = new ulong[totalAssetIdsCount];

                    for (int j = 0; j < totalAssetIdsCount; i++)
                    {
                        assetIds[j] = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                        readBytes  += Globals.NODE_PUBLIC_KEY_SIZE;
                    }

                    for (int j = 0; j < totalAssetIdsCount; i++)
                    {
                        amounts[j] = BinaryPrimitives.ReadUInt64LittleEndian(spanBody.Slice(readBytes).Span);
                        readBytes += sizeof(ulong);
                    }

                    assetsGroups[i] = new AssetsGroup
                    {
                        GroupId      = groupId,
                        AssetIds     = assetIds,
                        AssetAmounts = amounts
                    };
                }


                AcceptAssets acceptAssetTransitionBlock = new AcceptAssets
                {
                    AcceptedAssetUnblindingABs   = acceptedUnblindingAssetABs,
                    AcceptedAssetUnblindingUtxos = acceptedUnblindingAssetUtxos,
                    AssetsGroups = assetsGroups
                };

                transactionalBlockBase = acceptAssetTransitionBlock;

                return(spanBody.Slice(readBytes));
            }

            throw new BlockVersionNotSupportedException(version, BlockType);
        }
Ejemplo n.º 3
0
        protected override Memory <byte> ParseTransactional(ushort version, Memory <byte> spanBody, out TransactionalPacketBase transactionalBlockBase)
        {
            IssueGroupedAssets block = null;

            if (version == 1)
            {
                int readBytes = 0;

                ushort assetsIssuanceGroupsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                readBytes += sizeof(ushort);

                ushort blindedAssetsIssuanceGroupsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                readBytes += sizeof(ushort);

                AssetsIssuanceGroup[]        assetsIssuanceGroups        = new AssetsIssuanceGroup[assetsIssuanceGroupsLength];
                BlindedAssetsIssuanceGroup[] blindedAssetsIssuanceGroups = new BlindedAssetsIssuanceGroup[blindedAssetsIssuanceGroupsLength];

                for (int i = 0; i < assetsIssuanceGroupsLength; i++)
                {
                    uint groupId = BinaryPrimitives.ReadUInt32LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(uint);

                    ushort assetIdsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(ushort);

                    AssetIssuance[] assetIssuances = new AssetIssuance[assetIdsLength];

                    for (int j = 0; j < assetIdsLength; j++)
                    {
                        byte[] assetId = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                        readBytes += Globals.NODE_PUBLIC_KEY_SIZE;

                        byte strLen = spanBody.Slice(readBytes, 1).ToArray()[0];
                        readBytes++;

                        string issuedAssetInfo = Encoding.ASCII.GetString(spanBody.Slice(readBytes, strLen).ToArray());
                        readBytes += strLen;

                        assetIssuances[j] = new AssetIssuance
                        {
                            AssetId         = assetId,
                            IssuedAssetInfo = issuedAssetInfo
                        };
                    }

                    assetsIssuanceGroups[i] = new AssetsIssuanceGroup
                    {
                        GroupId        = groupId,
                        AssetIssuances = assetIssuances
                    };
                }

                for (int i = 0; i < blindedAssetsIssuanceGroupsLength; i++)
                {
                    uint groupId = BinaryPrimitives.ReadUInt32LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(uint);

                    ushort assetCommitmentsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(ushort);

                    byte[][] assetCommitments = new byte[assetCommitmentsLength][];

                    for (int j = 0; j < assetCommitmentsLength; j++)
                    {
                        assetCommitments[j] = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                        readBytes          += Globals.NODE_PUBLIC_KEY_SIZE;
                    }

                    AssetIssuance[] blindedAssetIssuances = new AssetIssuance[assetCommitmentsLength];
                    for (int j = 0; j < assetCommitmentsLength; j++)
                    {
                        byte[] assetId = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                        readBytes += Globals.NODE_PUBLIC_KEY_SIZE;

                        byte strLen = spanBody.Slice(readBytes, 1).ToArray()[0];
                        readBytes++;

                        string issuedAssetInfo = Encoding.ASCII.GetString(spanBody.Slice(readBytes, strLen).ToArray());
                        readBytes += strLen;

                        blindedAssetIssuances[i] = new AssetIssuance
                        {
                            AssetId         = assetId,
                            IssuedAssetInfo = issuedAssetInfo
                        };
                    }

                    IssuanceProof[] issuanceProofs = new IssuanceProof[assetCommitmentsLength];
                    for (int j = 0; j < assetCommitmentsLength; j++)
                    {
                        SurjectionProof surjectionProof = ReadSurjectionProof(spanBody.Slice(readBytes).Span, out int count);
                        readBytes += count;

                        byte[] mask = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                        readBytes += Globals.NODE_PUBLIC_KEY_SIZE;

                        issuanceProofs[j] = new IssuanceProof
                        {
                            SurjectionProof = surjectionProof,
                            Mask            = mask,
                        };
                    }

                    blindedAssetsIssuanceGroups[i] = new BlindedAssetsIssuanceGroup
                    {
                        GroupId          = groupId,
                        AssetCommitments = assetCommitments,
                        AssetIssuances   = blindedAssetIssuances,
                        IssuanceProofs   = issuanceProofs
                    };
                }

                byte strLen2 = spanBody.Slice(readBytes, 1).ToArray()[0];
                readBytes++;

                string issuanceInfo = Encoding.ASCII.GetString(spanBody.Slice(readBytes, strLen2).ToArray());
                readBytes += strLen2;

                ushort assetsGroupsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                readBytes += sizeof(ushort);

                ushort blindedAssetGroupsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                readBytes += sizeof(ushort);

                AssetsGroup[]        assetsGroups        = new AssetsGroup[assetsGroupsLength];
                BlindedAssetsGroup[] blindedAssetsGroups = new BlindedAssetsGroup[blindedAssetGroupsLength];

                for (int i = 0; i < assetsGroupsLength; i++)
                {
                    uint groupId = BinaryPrimitives.ReadUInt32LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(uint);

                    ushort assetIdsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(ushort);

                    byte[][] assetIds = new byte[assetIdsLength][];
                    ulong[]  amounts  = new ulong[assetIdsLength];

                    for (int j = 0; j < assetIdsLength; j++)
                    {
                        assetIds[j] = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                        readBytes  += Globals.NODE_PUBLIC_KEY_SIZE;

                        amounts[j] = BinaryPrimitives.ReadUInt64LittleEndian(spanBody.Slice(readBytes).Span);
                        readBytes += sizeof(ulong);
                    }

                    assetsGroups[i] = new AssetsGroup
                    {
                        GroupId      = groupId,
                        AssetIds     = assetIds,
                        AssetAmounts = amounts
                    };
                }

                for (int i = 0; i < blindedAssetGroupsLength; i++)
                {
                    uint groupId = BinaryPrimitives.ReadUInt32LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(uint);

                    ushort assetCommitmentsLength = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span);
                    readBytes += sizeof(ushort);

                    byte[][] assetCommitments = new byte[assetCommitmentsLength][];

                    for (int j = 0; j < assetCommitmentsLength; j++)
                    {
                        assetCommitments[j] = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray();
                        readBytes          += Globals.NODE_PUBLIC_KEY_SIZE;
                    }

                    blindedAssetsGroups[i] = new BlindedAssetsGroup
                    {
                        GroupId          = groupId,
                        AssetCommitments = assetCommitments
                    };
                }

                block = new IssueGroupedAssets
                {
                    AssetsIssuanceGroups        = assetsIssuanceGroups,
                    BlindedAssetsIssuanceGroups = blindedAssetsIssuanceGroups,
                    IssuanceInfo        = issuanceInfo,
                    AssetsGroups        = assetsGroups,
                    BlindedAssetsGroups = blindedAssetsGroups
                };

                transactionalBlockBase = block;
                return(spanBody.Slice(readBytes));
            }

            throw new BlockVersionNotSupportedException(version, BlockType);
        }