예제 #1
0
        public async Task Execute(CancellationToken _)
        {
            _initConfig = _api.Config <IInitConfig>();
            Keccak?expectedGenesisHash = string.IsNullOrWhiteSpace(_initConfig.GenesisHash) ? null : new Keccak(_initConfig.GenesisHash);

            if (_api.BlockTree == null)
            {
                throw new StepDependencyException();
            }

            // if we already have a database with blocks then we do not need to load genesis from spec
            if (_api.BlockTree.Genesis == null)
            {
                Load();
            }

            ValidateGenesisHash(expectedGenesisHash);

            if (!_initConfig.ProcessingEnabled)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Shutting down the blockchain processor due to {nameof(InitConfig)}.{nameof(InitConfig.ProcessingEnabled)} set to false");
                }
                await(_api.BlockchainProcessor?.StopAsync() ?? Task.CompletedTask);
            }
        }
예제 #2
0
 public static ResultWrapper <ForkchoiceUpdatedV1Result> Invalid(Keccak?latestValidHash, string?validationError = null) =>
 ResultWrapper <ForkchoiceUpdatedV1Result> .Success(new ForkchoiceUpdatedV1Result
 {
     PayloadStatus = new PayloadStatusV1 {
         Status = Data.V1.PayloadStatus.Invalid, LatestValidHash = latestValidHash, ValidationError = validationError
     }
 });
예제 #3
0
        public async Task <PaymentsValueSummary> GetPaymentsSummary(Keccak?depositId = null,
                                                                    Keccak?assetId   = null, Address?consumer = null)
        {
            var values = await Query(depositId, assetId, consumer)
                         .Select(c => new { c.ClaimedValue, c.Income, c.Status })
                         .ToListAsync();

            if (values.Count == 0)
            {
                return(PaymentsValueSummary.Empty);
            }

            var claimed = UInt256.Zero;
            var pending = UInt256.Zero;
            var income  = UInt256.Zero;

            foreach (var value in values)
            {
                if (value.Status == PaymentClaimStatus.Claimed)
                {
                    claimed += value.ClaimedValue;
                    income  += value.Income;
                }
                else
                {
                    pending += value.ClaimedValue;
                }
            }

            return(new PaymentsValueSummary(claimed, pending, income));
        }
 public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error,
                          Keccak?stateRoot = null)
 {
     Success = false;
     Error   = error;
     Output  = output;
 }
예제 #5
0
        private IMongoQueryable <PaymentClaim> Query(Keccak?depositId = null, Keccak?assetId     = null,
                                                     Address?consumer = null, bool onlyUnclaimed = false, bool onlyPending = false)
        {
            var paymentClaims = PaymentClaims.AsQueryable();

            if (!(depositId is null))
            {
                paymentClaims = paymentClaims.Where(c => c.DepositId == depositId);
            }

            if (!(assetId is null))
            {
                paymentClaims = paymentClaims.Where(c => c.AssetId == assetId);
            }

            if (!(consumer is null))
            {
                paymentClaims = paymentClaims.Where(c => c.Consumer == consumer);
            }

            if (onlyUnclaimed)
            {
                paymentClaims = paymentClaims.Where(c => c.Status != PaymentClaimStatus.Claimed &&
                                                    c.Status != PaymentClaimStatus.ClaimedWithLoss);
            }

            if (onlyPending)
            {
                paymentClaims = paymentClaims.Where(c => c.Transaction != null &&
                                                    c.Transaction.State == TransactionState.Pending &&
                                                    c.Status == PaymentClaimStatus.Sent);
            }

            return(paymentClaims.OrderByDescending(c => c.Timestamp));
        }
예제 #6
0
        public TransactionForRpc(Keccak?blockHash, long?blockNumber, int?txIndex, Transaction transaction)
        {
            Hash             = transaction.Hash;
            Nonce            = transaction.Nonce;
            BlockHash        = blockHash;
            BlockNumber      = blockNumber;
            TransactionIndex = txIndex;
            From             = transaction.SenderAddress;
            To         = transaction.To;
            Value      = transaction.Value;
            GasPrice   = transaction.GasPrice;
            Gas        = transaction.GasLimit;
            Input      = Data = transaction.Data;
            Type       = transaction.Type;
            AccessList = transaction.AccessList is null ? null : AccessListItemForRpc.FromAccessList(transaction.AccessList);

            Signature?signature = transaction.Signature;

            if (signature != null)
            {
                R = new UInt256(signature.R, true);
                S = new UInt256(signature.S, true);
                V = (UInt256?)signature.V;
            }
        }
예제 #7
0
    private List <Keccak> MakeChain(int n, bool connectInReverse = false)
    {
        Keccak?       prev     = null;
        List <Keccak> hashList = new();

        for (int i = 0; i < n; i++)
        {
            Keccak newHash = Keccak.Compute(Random.Shared.NextInt64().ToString());
            hashList.Add(newHash);
        }

        if (connectInReverse)
        {
            for (int i = hashList.Count - 2; i >= 0; i--)
            {
                _tracker.SetChildParent(hashList[i + 1], hashList[i]);
            }
        }
        else
        {
            for (int i = 0; i < hashList.Count - 1; i++)
            {
                _tracker.SetChildParent(hashList[i + 1], hashList[i]);
            }
        }

        return(hashList);
    }
예제 #8
0
        public Task <PaymentsValueSummary> GetPaymentsSummary(Keccak?depositId = null, Keccak?assetId = null,
                                                              Address?consumer = null)
        {
            var paymentClaims = GetAll();

            if (paymentClaims.Length == 0)
            {
                return(Task.FromResult(PaymentsValueSummary.Empty));
            }

            var values = Query(paymentClaims.AsEnumerable(), depositId, assetId, consumer)
                         .Select(c => new { c.ClaimedValue, c.Income, c.Status });

            var claimed = UInt256.Zero;
            var pending = UInt256.Zero;
            var income  = UInt256.Zero;

            foreach (var value in values)
            {
                if (value.Status == PaymentClaimStatus.Claimed)
                {
                    claimed += value.ClaimedValue;
                    income  += value.Income;
                }
                else
                {
                    pending += value.ClaimedValue;
                }
            }

            return(Task.FromResult(new PaymentsValueSummary(claimed, pending, income)));
        }
예제 #9
0
        public bool TryUpdateTerminalBlock(BlockHeader header)
        {
            if (_terminalBlockExplicitSpecified || TransitionFinished || !header.IsTerminalBlock(_specProvider))
            {
                return(false);
            }

            _terminalBlockNumber = header.Number;
            _terminalBlockHash   = header.Hash;
            _metadataDb.Set(MetadataDbKeys.TerminalPoWNumber, Rlp.Encode(_terminalBlockNumber.Value).Bytes);
            _metadataDb.Set(MetadataDbKeys.TerminalPoWHash, Rlp.Encode(_terminalBlockHash).Bytes);
            _firstPoSBlockNumber = header.Number + 1;
            _specProvider.UpdateMergeTransitionInfo(_firstPoSBlockNumber.Value);

            if (_hasEverReachedTerminalDifficulty == false)
            {
                TerminalBlockReached?.Invoke(this, EventArgs.Empty);
                _hasEverReachedTerminalDifficulty = true;
                if (_logger.IsInfo)
                {
                    _logger.Info($"Reached terminal block {header}");
                }
            }
            else
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Updated terminal block {header}");
                }
            }

            return(true);
        }
        private ConsumerSession[] Filter(
            Keccak?depositId         = null,
            Keccak?dataAssetId       = null,
            PublicKey?consumerNodeId = null,
            Address?consumerAddress  = null,
            PublicKey?providerNodeId = null,
            Address?providerAddress  = null)
        {
            byte[][] sessionsBytes = _database.GetAllValues().ToArray();
            if (sessionsBytes.Length == 0)
            {
                return(Array.Empty <ConsumerSession>());
            }

            ConsumerSession[] sessions = new ConsumerSession[sessionsBytes.Length];
            for (int i = 0; i < sessionsBytes.Length; i++)
            {
                sessions[i] = Decode(sessionsBytes[i]);
            }

            if (depositId is null && dataAssetId is null && consumerNodeId is null && consumerAddress is null &&
                providerNodeId is null && providerAddress is null)
            {
                return(sessions);
            }

            IEnumerable <ConsumerSession> filteredSessions = sessions.AsEnumerable();

            if (!(depositId is null))
            {
                filteredSessions = filteredSessions.Where(s => s.DepositId == depositId);
            }

            if (!(dataAssetId is null))
            {
                filteredSessions = filteredSessions.Where(s => s.DataAssetId == dataAssetId);
            }

            if (!(consumerNodeId is null))
            {
                filteredSessions = filteredSessions.Where(s => s.ConsumerNodeId == consumerNodeId);
            }

            if (!(consumerAddress is null))
            {
                filteredSessions = filteredSessions.Where(s => s.ConsumerAddress == consumerAddress);
            }

            if (!(providerNodeId is null))
            {
                filteredSessions = filteredSessions.Where(s => s.ProviderNodeId == providerNodeId);
            }

            if (!(providerAddress is null))
            {
                filteredSessions = filteredSessions.Where(s => s.ProviderAddress == providerAddress);
            }

            return(filteredSessions.OrderByDescending(s => s.StartTimestamp).ToArray());
        }
예제 #11
0
 public static ResultWrapper <PayloadStatusV1> Valid(Keccak?latestValidHash)
 {
     return(ResultWrapper <PayloadStatusV1> .Success(new PayloadStatusV1()
     {
         Status = PayloadStatus.Valid, LatestValidHash = latestValidHash
     }));
 }
예제 #12
0
 public static ResultWrapper <PayloadStatusV1> Invalid(Keccak?latestValidHash, string?validationError = null)
 {
     return(ResultWrapper <PayloadStatusV1> .Success(new PayloadStatusV1()
     {
         Status = PayloadStatus.Invalid, LatestValidHash = latestValidHash, ValidationError = validationError
     }));
 }
예제 #13
0
        public async Task payment_claim_should_not_be_sent_while_units_are_less_than_units_range_to()
        {
            var unitsRange   = new UnitsRange(0, 5);
            var paymentClaim = new PaymentClaim(id: Keccak.Zero,
                                                depositId: Keccak.Zero,
                                                assetId: Keccak.Zero,
                                                assetName: "test",
                                                units: 3,
                                                claimedUnits: 3,
                                                unitsRange: unitsRange,
                                                value: 10,
                                                claimedValue: 30,
                                                expiryTime: 10,
                                                pepper: Array.Empty <byte>(),
                                                provider: TestItem.AddressA,
                                                consumer: TestItem.AddressB,
                                                signature: new Signature(1, 2, 37),
                                                timestamp: 12,
                                                transactions: Array.Empty <TransactionInfo>(),
                                                status: PaymentClaimStatus.Unknown
                                                );

            Keccak?transactionHash = await _processor.SendTransactionAsync(paymentClaim, 10);

            Assert.IsNull(transactionHash);
            Assert.IsTrue(paymentClaim.Status != PaymentClaimStatus.Sent);
        }
예제 #14
0
        public async Task <RefundClaimStatus> TryClaimRefundAsync(DepositDetails deposit, Address refundTo)
        {
            ulong now = _timestamper.EpochSeconds;

            if (!deposit.CanClaimRefund(now))
            {
                return(RefundClaimStatus.Empty);
            }

            Block?latestBlock = await _blockchainBridge.GetLatestBlockAsync();

            if (latestBlock == null)
            {
                return(RefundClaimStatus.Empty);
            }

            now = (ulong)latestBlock.Timestamp;
            if (!deposit.CanClaimRefund(now))
            {
                return(RefundClaimStatus.Empty);
            }

            Keccak depositId       = deposit.Deposit.Id;
            Keccak?transactionHash = deposit.ClaimedRefundTransaction?.Hash;

            if (transactionHash is null)
            {
                Address     provider    = deposit.DataAsset.Provider.Address;
                RefundClaim refundClaim = new RefundClaim(depositId, deposit.DataAsset.Id, deposit.Deposit.Units,
                                                          deposit.Deposit.Value, deposit.Deposit.ExpiryTime, deposit.Pepper, provider, refundTo);
                UInt256 gasPrice = await _gasPriceService.GetCurrentAsync();

                transactionHash = await _refundService.ClaimRefundAsync(refundTo, refundClaim, gasPrice);

                if (transactionHash is null)
                {
                    if (_logger.IsError)
                    {
                        _logger.Error("There was an error when trying to claim refund (no transaction hash returned).");
                    }
                    return(RefundClaimStatus.Empty);
                }

                deposit.AddClaimedRefundTransaction(TransactionInfo.Default(transactionHash, 0, gasPrice,
                                                                            _refundService.GasLimit, _timestamper.EpochSeconds));
                await _depositRepository.UpdateAsync(deposit);

                if (_logger.IsInfo)
                {
                    _logger.Info($"Claimed a refund for deposit: '{depositId}', gas price: {gasPrice} wei, transaction hash: '{transactionHash}' (awaits a confirmation).");
                }
            }

            bool confirmed = await TryConfirmClaimAsync(deposit, string.Empty);

            return(confirmed
                ? RefundClaimStatus.Confirmed(transactionHash)
                : RefundClaimStatus.Unconfirmed(transactionHash));
        }
 public FaucetRequestDetailsForRpc(string?host, Address?address, UInt256?value, DateTime?date, Keccak?transactionHash)
 {
     Host            = host;
     Address         = address;
     Value           = value;
     Date            = date;
     TransactionHash = transactionHash;
 }
예제 #16
0
 public NdmTransaction(Transaction transaction, bool isPending, long?blockNumber, Keccak?blockHash, long?gasUsed)
 {
     Transaction = transaction;
     IsPending   = isPending;
     BlockNumber = blockNumber;
     BlockHash   = blockHash;
     GasUsed     = gasUsed;
 }
예제 #17
0
        public async Task <UpdatedTransactionInfo> CancelPaymentClaimAsync(Keccak paymentClaimId)
        {
            (UpdatedTransactionStatus status, PaymentClaim? paymentClaim) = await TryGetPaymentClaimAsync(paymentClaimId, "cancel");

            if (status != UpdatedTransactionStatus.Ok)
            {
                return(new UpdatedTransactionInfo(status));
            }

            TransactionInfo?currentTransaction = paymentClaim !.Transaction;

            if (currentTransaction == null)
            {
                if (_logger.IsError)
                {
                    _logger.Error($"Cannot cancel missing transaction for payment claim with id: '{paymentClaim!.Id}'.");
                }
                return(new UpdatedTransactionInfo(UpdatedTransactionStatus.MissingTransaction));
            }

            Keccak?hash = currentTransaction.Hash;

            if (hash == null)
            {
                if (_logger.IsError)
                {
                    _logger.Error($"Cannot cancel missing transaction for payment claim with id: '{paymentClaim!.Id}'.");
                }
                return(new UpdatedTransactionInfo(UpdatedTransactionStatus.MissingTransaction));
            }

            if (currentTransaction.State != TransactionState.Pending)
            {
                if (_logger.IsError)
                {
                    _logger.Error($"Cannot cancel transaction with hash: '{hash}' for payment claim with id: '{paymentClaim!.Id}' (state: '{currentTransaction.State}').");
                }
                return(new UpdatedTransactionInfo(UpdatedTransactionStatus.AlreadyIncluded));
            }

            if (_logger.IsWarn)
            {
                _logger.Warn($"Canceling transaction for payment claim with id: '{paymentClaimId}'.");
            }
            CanceledTransactionInfo transaction = await _transactionService.CancelAsync(hash);

            if (_logger.IsWarn)
            {
                _logger.Warn($"Canceled transaction for payment claim with id: '{paymentClaimId}', transaction hash: '{transaction.Hash}'.");
            }
            TransactionInfo cancellingTransaction = TransactionInfo.Cancellation(transaction.Hash, transaction.GasPrice,
                                                                                 transaction.GasLimit, _timestamper.UnixTime.Seconds);

            paymentClaim !.AddTransaction(cancellingTransaction);
            await _paymentClaimRepository.UpdateAsync(paymentClaim !);

            return(new UpdatedTransactionInfo(UpdatedTransactionStatus.Ok, transaction.Hash));
        }
예제 #18
0
 public FaucetRequestDetails(string host, Address address, UInt256 value, DateTime date, Keccak transactionHash)
 {
     Host            = host;
     Address         = address;
     Value           = value;
     Date            = date;
     TransactionHash = transactionHash;
     Value           = value;
 }
예제 #19
0
        public bool Equals(Keccak?other)
        {
            if (ReferenceEquals(other, null))
            {
                return(false);
            }

            return(Core.Extensions.Bytes.AreEqual(other.Bytes, Bytes));
        }
    public async Task forkChoiceUpdatedV1_unknown_block_initiates_syncing()
    {
        using MergeTestBlockchain chain = await CreateBlockChain();

        IEngineRpcModule rpc          = CreateEngineModule(chain);
        Keccak?          startingHead = chain.BlockTree.HeadHash;
        BlockHeader      parent       = Build.A.BlockHeader
                                        .WithNumber(1)
                                        .WithHash(TestItem.KeccakA)
                                        .WithNonce(0)
                                        .WithDifficulty(0)
                                        .TestObject;
        Block block = Build.A.Block
                      .WithNumber(2)
                      .WithParent(parent)
                      .WithNonce(0)
                      .WithDifficulty(0)
                      .WithAuthor(Address.Zero)
                      .WithPostMergeFlag(true)
                      .TestObject;
        await rpc.engine_newPayloadV1(new ExecutionPayloadV1(block));

        // sync has not started yet
        chain.BeaconSync.IsBeaconSyncHeadersFinished().Should().BeTrue();
        chain.BeaconSync.IsBeaconSyncFinished(block.Header).Should().BeTrue();
        chain.BeaconSync.ShouldBeInBeaconHeaders().Should().BeFalse();
        chain.BeaconPivot.BeaconPivotExists().Should().BeFalse();
        BlockTreePointers pointers = new()
        {
            BestKnownNumber            = 0,
            BestSuggestedHeader        = chain.BlockTree.Genesis !,
            BestSuggestedBody          = chain.BlockTree.FindBlock(0) !,
            BestKnownBeaconBlock       = 0,
            LowestInsertedHeader       = null,
            LowestInsertedBeaconHeader = null
        };

        AssertBlockTreePointers(chain.BlockTree, pointers);

        ForkchoiceStateV1 forkchoiceStateV1 = new(block.Hash !, startingHead, startingHead);
        ResultWrapper <ForkchoiceUpdatedV1Result> forkchoiceUpdatedResult =
            await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1);

        forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should()
        .Be(nameof(PayloadStatusV1.Syncing).ToUpper());

        chain.BeaconSync.ShouldBeInBeaconHeaders().Should().BeTrue();
        chain.BeaconSync.IsBeaconSyncHeadersFinished().Should().BeFalse();
        chain.BeaconSync.IsBeaconSyncFinished(chain.BlockTree.FindBlock(block.Hash)?.Header).Should().BeFalse();
        AssertBeaconPivotValues(chain.BeaconPivot, block.Header);
        pointers.LowestInsertedBeaconHeader = block.Header;
        pointers.BestKnownBeaconBlock       = block.Number;
        pointers.LowestInsertedHeader       = block.Header;
        AssertBlockTreePointers(chain.BlockTree, pointers);
        AssertExecutionStatusNotChangedV1(rpc, block.Hash !, startingHead, startingHead);
    }
예제 #21
0
        public DataStreamDisabledMessage Deserialize(byte[] bytes)
        {
            RlpStream context = bytes.AsRlpStream();

            context.ReadSequenceLength();
            Keccak?depositId = context.DecodeKeccak();
            string client    = context.DecodeString();

            return(new DataStreamDisabledMessage(depositId, client));
        }
예제 #22
0
        public Account?Get(Address address, Keccak?rootHash = null)
        {
            byte[]? bytes = Get(ValueKeccak.Compute(address.Bytes).BytesAsSpan, rootHash);
            if (bytes is null)
            {
                return(null);
            }

            return(_decoder.Decode(bytes.AsRlpStream()));
        }
        public DataAssetStateChangedMessage Deserialize(byte[] bytes)
        {
            RlpStream context = bytes.AsRlpStream();

            context.ReadSequenceLength();
            Keccak?        dataAssetId = context.DecodeKeccak();
            DataAssetState state       = (DataAssetState)context.DecodeInt();

            return(new DataAssetStateChangedMessage(dataAssetId, state));
        }
        public DataAvailabilityMessage Deserialize(byte[] bytes)
        {
            RlpStream context = bytes.AsRlpStream();

            context.ReadSequenceLength();
            Keccak?          depositId = context.DecodeKeccak();
            DataAvailability reason    = (DataAvailability)context.DecodeInt();

            return(new DataAvailabilityMessage(depositId, reason));
        }
예제 #25
0
    private void AssertInvalid(Keccak hash, Keccak?expectedLsatValidHash = null)
    {
        Keccak?lastValidHash;

        _tracker.IsOnKnownInvalidChain(hash, out lastValidHash).Should().BeTrue();
        if (expectedLsatValidHash != null)
        {
            lastValidHash.Should().BeEquivalentTo(expectedLsatValidHash);
        }
    }
        public DepositApprovalRejectedMessage Deserialize(byte[] bytes)
        {
            RlpStream?context = bytes.AsRlpStream();

            context.ReadSequenceLength();
            Keccak? dataAssetId = context.DecodeKeccak();
            Address?consumer    = context.DecodeAddress();

            return(new DepositApprovalRejectedMessage(dataAssetId, consumer));
        }
예제 #27
0
        public async Task <UpdatedTransactionInfo> UpdatePaymentClaimGasPriceAsync(Keccak paymentClaimId, UInt256 gasPrice)
        {
            if (gasPrice == 0)
            {
                if (_logger.IsError)
                {
                    _logger.Error("Gas price cannot be 0.");
                }
                return(new UpdatedTransactionInfo(UpdatedTransactionStatus.InvalidGasPrice));
            }

            (UpdatedTransactionStatus status, PaymentClaim? paymentClaim) = await TryGetPaymentClaimAsync(paymentClaimId, "update gas price");

            if (status != UpdatedTransactionStatus.Ok)
            {
                return(new UpdatedTransactionInfo(status));
            }

            TransactionInfo?currentTransaction = paymentClaim !.Transaction;

            if (currentTransaction == null)
            {
                return(new UpdatedTransactionInfo(UpdatedTransactionStatus.MissingTransaction));
            }

            Keccak?currentHash = currentTransaction.Hash;

            if (currentHash == null)
            {
                return(new UpdatedTransactionInfo(UpdatedTransactionStatus.MissingTransaction));
            }

            ulong gasLimit = currentTransaction.GasLimit;

            if (_logger.IsInfo)
            {
                _logger.Info($"Updating gas price for payment claim with id: '{paymentClaim!.Id}', current transaction hash: '{currentHash}'.");
            }
            Keccak transactionHash = await _transactionService.UpdateGasPriceAsync(currentHash, gasPrice);

            if (_logger.IsInfo)
            {
                _logger.Info($"Received transaction hash: '{transactionHash}' for payment claim with id: '{paymentClaim.Id}' after updating gas price.");
            }
            paymentClaim !.AddTransaction(TransactionInfo.SpeedUp(transactionHash, 0, gasPrice, gasLimit,
                                                                  _timestamper.UnixTime.Seconds));
            await _paymentClaimRepository.UpdateAsync(paymentClaim !);

            if (_logger.IsInfo)
            {
                _logger.Info($"Updated gas price for payment claim with id: '{paymentClaim!.Id}', transaction hash: '{transactionHash}'.");
            }

            return(new UpdatedTransactionInfo(UpdatedTransactionStatus.Ok, transactionHash));
        }
예제 #28
0
 internal TransactionInfo(Keccak?hash, UInt256 value, UInt256 gasPrice, ulong gasLimit, ulong timestamp,
                          TransactionType type = TransactionType.Default, TransactionState state = TransactionState.Pending)
 {
     Hash      = hash;
     Value     = value;
     GasPrice  = gasPrice;
     GasLimit  = gasLimit;
     Timestamp = timestamp;
     Type      = type;
     State     = state;
 }
예제 #29
0
 public TransactionInfoForRpc(Keccak? hash, UInt256 value, UInt256 gasPrice, ulong gasLimit, ulong timestamp,
     string type, string state)
 {
     Hash = hash;
     Value = value;
     GasPrice = gasPrice;
     GasLimit = gasLimit;
     Timestamp = timestamp;
     Type = type;
     State = state;
 }
예제 #30
0
        public RequestDepositApprovalMessage Deserialize(byte[] bytes)
        {
            RlpStream context = bytes.AsRlpStream();

            context.ReadSequenceLength();
            Keccak? dataAssetId = context.DecodeKeccak();
            Address?consumer    = context.DecodeAddress();
            string  kyc         = context.DecodeString();

            return(new RequestDepositApprovalMessage(dataAssetId, consumer, kyc));
        }