示例#1
0
        public ResultWrapper <byte[]> eth_call(TransactionForRpc transactionCall, BlockParameter blockParameter = null)
        {
            BlockHeader block = _blockchainBridge.GetHeader(blockParameter ?? BlockParameter.Latest);

            var tx = transactionCall.ToTransaction();

            tx.GasPrice = 0;
            if (tx.GasLimit < 21000)
            {
                tx.GasLimit = 10000000;
            }

            if (tx.To == null)
            {
                return(ResultWrapper <byte[]> .Fail($"Recipient address not specified on the transaction.", ErrorType.InvalidParams));
            }

            BlockchainBridge.CallOutput result = _blockchainBridge.Call(block, tx);

            if (result.Error != null)
            {
                return(ResultWrapper <byte[]> .Fail($"VM Exception while processing transaction: {result.Error}", ErrorType.ExecutionError, result.OutputData));
            }

            return(ResultWrapper <byte[]> .Success(result.OutputData));
        }
示例#2
0
        public ResultWrapper <string> eth_call(TransactionForRpc transactionCall, BlockParameter blockParameter = null)
        {
            SearchResult <BlockHeader> searchResult = _blockFinder.SearchForHeader(blockParameter);

            if (searchResult.IsError)
            {
                return(ResultWrapper <string> .Fail(searchResult));
            }

            BlockHeader header = searchResult.Object;

            if (!HasStateForBlock(header))
            {
                return(ResultWrapper <string> .Fail($"No state available for block {header.Hash}", ErrorCodes.ResourceUnavailable));
            }

            FixCallTx(transactionCall, header);

            using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(_cancellationTokenTimeout);
            CancellationToken cancellationToken = cancellationTokenSource.Token;
            Transaction       tx = transactionCall.ToTransaction();

            BlockchainBridge.CallOutput result = _blockchainBridge.Call(header, tx, cancellationToken);

            return(result.Error != null ? ResultWrapper <string> .Fail("VM execution error.", ErrorCodes.ExecutionError, result.Error) : ResultWrapper <string> .Success(result.OutputData.ToHexString(true)));
        }
示例#3
0
        private ResultWrapper <UInt256?> EstimateGas(TransactionForRpc transactionCall, BlockHeader head)
        {
            // 2021-03-04 08:54:18.6489|DEBUG|101|Responded to ID 40, eth_estimateGas({
            //     "from": "0x2b5ad5c4795c026514f8317c7a215e218dccd6cf",
            //     "to": "0xa28afda14be5789564ae5fa03665c4180e3c680b",
            //     "data": "0x25936984"
            // })

            // 2021-03-04 08:54:18.6533|DEBUG|13|Responded to ID 41, eth_sendTransaction({
            //     "gas": "0x1f815f1",
            //     "from": "0x2b5ad5c4795c026514f8317c7a215e218dccd6cf",
            //     "to": "0xa28afda14be5789564ae5fa03665c4180e3c680b",
            //     "data": "0x25936984",
            //     "gasPrice": "0x4a817c800"
            // })

            FixCallTx(transactionCall);

            // using CancellationTokenSource cancellationTokenSource = new(_cancellationTokenTimeout);
            CancellationToken cancellationToken = CancellationToken.None;

            BlockchainBridge.CallOutput result =
                _blockchainBridge.EstimateGas(head, transactionCall.ToTransaction(), cancellationToken);

            if (result.Error == null)
            {
                return(ResultWrapper <UInt256?> .Success((UInt256)result.GasSpent));
            }

            return(ResultWrapper <UInt256?> .Fail(result.Error, result.InputError?ErrorCodes.InvalidInput : ErrorCodes.InternalError));
        }
示例#4
0
            protected override ResultWrapper <UInt256?> ExecuteTx(BlockHeader header, Transaction tx, CancellationToken token)
            {
                BlockchainBridge.CallOutput result = _blockchainBridge.EstimateGas(header, tx, token);

                if (result.Error is null)
                {
                    return(ResultWrapper <UInt256?> .Success((UInt256)result.GasSpent));
                }

                return(result.InputError
                    ? GetInputError(result)
                    : ResultWrapper <UInt256?> .Fail(result.Error, ErrorCodes.InternalError));
            }
示例#5
0
            protected override ResultWrapper <string> ExecuteTx(BlockHeader header, Transaction tx, CancellationToken token)
            {
                BlockchainBridge.CallOutput result = _blockchainBridge.Call(header, tx, token);

                if (result.Error is null)
                {
                    return(ResultWrapper <string> .Success(result.OutputData.ToHexString(true)));
                }

                return(result.InputError
                    ? GetInputError(result)
                    : ResultWrapper <string> .Fail("VM execution error.", ErrorCodes.ExecutionError, result.Error));
            }
示例#6
0
            protected override ResultWrapper <AccessListForRpc> ExecuteTx(BlockHeader header, Transaction tx, CancellationToken token)
            {
                BlockchainBridge.CallOutput result = _blockchainBridge.CreateAccessList(header, tx, token, _optimize);

                if (result.Error is null)
                {
                    return(ResultWrapper <AccessListForRpc> .Success(new(GetResultAccessList(tx, result), GetResultGas(tx, result))));
                }

                return(result.InputError
                    ? GetInputError(result)
                    : ResultWrapper <AccessListForRpc> .Fail(result.Error, ErrorCodes.InternalError, new(GetResultAccessList(tx, result), GetResultGas(tx, result))));
            }
示例#7
0
        public ResultWrapper <UInt256?> eth_estimateGas(TransactionForRpc transactionCall)
        {
            BlockHeader head = _blockchainBridge.FindLatestHeader();

            FixCallTx(transactionCall, head);

            BlockchainBridge.CallOutput result = _blockchainBridge.EstimateGas(head, transactionCall.ToTransaction());
            if (result.Error == null)
            {
                return(ResultWrapper <UInt256?> .Success((UInt256)result.GasSpent));
            }

            return(ResultWrapper <UInt256?> .Fail(result.Error));
        }
示例#8
0
            private static UInt256 GetResultGas(Transaction transaction, BlockchainBridge.CallOutput result)
            {
                long gas = result.GasSpent;

                if (result.AccessList is not null)
                {
                    // if we generated access list, we need to fix actual gas cost, as all storage was considered warm
                    gas -= IntrinsicGasCalculator.Calculate(transaction, Berlin.Instance);
                    transaction.AccessList = result.AccessList;
                    gas += IntrinsicGasCalculator.Calculate(transaction, Berlin.Instance);
                }

                return((UInt256)gas);
            }
        public async Task call_should_invoke_blockchain_bridge_call_and_return_data()
        {
            Block       head        = Build.A.Block.TestObject;
            Transaction transaction = Build.A.Transaction.TestObject;

            byte[] data = new byte[] { 0, 1, 2 };
            _blockchainBridge.HeadBlock.Returns(head);
            BlockchainBridge.CallOutput output = new BlockchainBridge.CallOutput(data, 0, null);
            _blockchainBridge.Call(head?.Header, transaction, default).Returns(output);
            byte[] result = await _ndmBridge.CallAsync(transaction);

            _blockchainBridge.Received().Call(head?.Header, transaction, default);
            result.Should().BeSameAs(data);
        }
示例#10
0
        public uint VerifyDeposit(Address onBehalfOf, Keccak depositId, BlockHeader head)
        {
            var         txData      = _abiEncoder.Encode(AbiEncodingStyle.IncludeSignature, ContractData.VerifyDepositAbiSig, depositId.Bytes);
            Transaction transaction = new Transaction();

            transaction.Value         = 0;
            transaction.Data          = txData;
            transaction.To            = _contractAddress;
            transaction.SenderAddress = onBehalfOf;
            transaction.GasLimit      = 100000;
            transaction.GasPrice      = 0.GWei();
            transaction.Nonce         = (UInt256)_blockchainBridge.GetNonce(onBehalfOf);
            BlockchainBridge.CallOutput callOutput = _blockchainBridge.Call(head, transaction);
            return((callOutput.OutputData ?? new byte[] { 0 }).ToUInt32());
        }
        public async Task call_should_invoke_blockchain_bridge_call_and_return_data()
        {
            var head        = Build.A.BlockHeader.TestObject;
            var transaction = Build.A.Transaction.TestObject;
            var data        = new byte[] { 0, 1, 2 };

            _blockchainBridge.Head.Returns(head);
            var output = new BlockchainBridge.CallOutput(data, 0, null);

            _blockchainBridge.Call(head, transaction).Returns(output);
            var result = await _ndmBridge.CallAsync(transaction);

            _blockchainBridge.Received().Call(head, transaction);
            result.Should().BeSameAs(data);
        }
        public async Task call_with_transaction_number_should_invoke_blockchain_bridge_call_and_return_data()
        {
            Block       block       = Build.A.Block.TestObject;
            Transaction transaction = Build.A.Transaction.TestObject;

            byte[] data = new byte[] { 0, 1, 2 };
            _blockFinder.FindBlock(block.Number).Returns(block);
            BlockchainBridge.CallOutput output = new BlockchainBridge.CallOutput(data, 0, null);
            _blockchainBridge.Call(block.Header, transaction, default).Returns(output);
            byte[] result = await _ndmBridge.CallAsync(transaction, block.Number);

            _blockFinder.Received().FindBlock(block.Number);
            _blockchainBridge.Received().Call(block.Header, transaction, default);
            result.Should().BeSameAs(data);
        }
示例#13
0
        public UInt256 ReadDepositBalance(Address onBehalfOf, Keccak depositId)
        {
            var         txData      = _abiEncoder.Encode(AbiEncodingStyle.IncludeSignature, ContractData.DepositBalanceAbiSig, depositId.Bytes);
            Transaction transaction = new Transaction();

            transaction.Value         = 0;
            transaction.Data          = txData;
            transaction.To            = _contractAddress;
            transaction.SenderAddress = onBehalfOf;
            transaction.GasLimit      = 100000;
            transaction.GasPrice      = 0.GWei();
            transaction.Nonce         = (UInt256)_blockchainBridge.GetNonce(onBehalfOf);
            _wallet.Sign(transaction, _blockchainBridge.GetNetworkId());
            BlockchainBridge.CallOutput callOutput = _blockchainBridge.Call(_blockchainBridge.Head, transaction);
            return((callOutput.OutputData ?? new byte[] { 0 }).ToUInt256());
        }
示例#14
0
        private ResultWrapper <UInt256?> EstimateGas(TransactionForRpc transactionCall, BlockHeader head)
        {
            FixCallTx(transactionCall, head);

            var tokenTimeout = TimeSpan.FromMilliseconds(_rpcConfig.TracerTimeout);
            CancellationToken cancellationToken = new CancellationTokenSource(tokenTimeout).Token;

            BlockchainBridge.CallOutput result = _blockchainBridge.EstimateGas(head, transactionCall.ToTransaction(), cancellationToken);

            if (result.Error == null)
            {
                return(ResultWrapper <UInt256?> .Success((UInt256)result.GasSpent));
            }

            return(ResultWrapper <UInt256?> .Fail(result.Error));
        }
示例#15
0
        private ResultWrapper <UInt256?> EstimateGas(TransactionForRpc transactionCall, BlockHeader head)
        {
            FixCallTx(transactionCall, head);

            using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(_cancellationTokenTimeout);
            CancellationToken cancellationToken = cancellationTokenSource.Token;

            BlockchainBridge.CallOutput result = _blockchainBridge.EstimateGas(head, transactionCall.ToTransaction(), cancellationToken);

            if (result.Error == null)
            {
                return(ResultWrapper <UInt256?> .Success((UInt256)result.GasSpent));
            }

            return(ResultWrapper <UInt256?> .Fail(result.Error));
        }
示例#16
0
        public ResultWrapper <UInt256?> eth_estimateGas(TransactionForRpc transactionCall)
        {
            BlockHeader head = _blockchainBridge.FindLatestHeader();

            if (!HasStateForBlock(head))
            {
                return(ResultWrapper <UInt256?> .Fail($"No state available for block {head.Hash}", ErrorCodes.ResourceUnavailable));
            }

            FixCallTx(transactionCall, head);

            BlockchainBridge.CallOutput result = _blockchainBridge.EstimateGas(head, transactionCall.ToTransaction());
            if (result.Error == null)
            {
                return(ResultWrapper <UInt256?> .Success((UInt256)result.GasSpent));
            }

            return(ResultWrapper <UInt256?> .Fail(result.Error));
        }
示例#17
0
        public ResultWrapper <string> eth_call(TransactionForRpc transactionCall, BlockParameter blockParameter = null)
        {
            SearchResult <BlockHeader> searchResult = _blockchainBridge.SearchForHeader(blockParameter);

            if (searchResult.IsError)
            {
                return(ResultWrapper <string> .Fail(searchResult));
            }

            BlockHeader header = searchResult.Object;

            FixCallTx(transactionCall, header);

            Transaction tx = transactionCall.ToTransaction();

            BlockchainBridge.CallOutput result = _blockchainBridge.Call(header, tx);

            return(result.Error != null ? ResultWrapper <string> .Fail("VM execution error.", ErrorCodes.ExecutionError, result.Error) : ResultWrapper <string> .Success(result.OutputData.ToHexString(true)));
        }
示例#18
0
        public ResultWrapper <byte[]> eth_call(TransactionForRpc transactionCall, BlockParameter blockParameter = null)
        {
            try
            {
                _readerWriterLockSlim.EnterWriteLock();
                BlockHeader block = blockParameter == null ? _blockchainBridge.Head : GetBlock(blockParameter).Data.Header;
                BlockchainBridge.CallOutput result = _blockchainBridge.Call(block, transactionCall.ToTransaction());

                if (result.Error != null)
                {
                    return(ResultWrapper <byte[]> .Fail($"VM Exception while processing transaction: {result.Error}", ErrorType.ExecutionError, result.OutputData));
                }

                return(ResultWrapper <byte[]> .Success(result.OutputData));
            }
            finally
            {
                _readerWriterLockSlim.ExitWriteLock();
            }
        }
示例#19
0
        public ResultWrapper <string> eth_call(TransactionForRpc transactionCall, BlockParameter blockParameter = null)
        {
            BlockHeader block = _blockchainBridge.GetHeader(blockParameter ?? BlockParameter.Latest);

            var tx = transactionCall.ToTransaction();

            tx.GasPrice = 0;
            if (tx.GasLimit < 21000)
            {
                tx.GasLimit = 10000000;
            }

            BlockchainBridge.CallOutput result = _blockchainBridge.Call(block, tx);

            if (result.Error != null)
            {
                return(ResultWrapper <string> .Fail("VM execution error.", ErrorType.ExecutionError, result.Error));
            }

            return(ResultWrapper <string> .Success(result.OutputData.ToHexString(true)));
        }
示例#20
0
        public IEnumerable <Transaction> GetTransactions(BlockHeader parent, long gasLimit)
        {
            IDictionary <Address, HashSet <UInt256> > usedAccessList = new Dictionary <Address, HashSet <UInt256> >();
            // IList<UserOperation> userOperationsToInclude = new List<UserOperation>();
            IDictionary <Address, IList <UserOperation> > userOperationsToIncludeByEntryPoint =
                new Dictionary <Address, IList <UserOperation> >();
            ulong gasUsed = 0;

            IList <Tuple <Address, UserOperation> > combinedUserOperations = new List <Tuple <Address, UserOperation> >();

            foreach (Address entryPoint in _userOperationPools.Keys)
            {
                IEnumerable <UserOperation> entryPointUserOperations =
                    _userOperationPools[entryPoint]
                    .GetUserOperations()
                    .Where(op => op.MaxFeePerGas >= parent.BaseFeePerGas);

                foreach (UserOperation userOperation in entryPointUserOperations)
                {
                    combinedUserOperations.Add(Tuple.Create(entryPoint, userOperation));
                }
            }
            IList <Tuple <Address, UserOperation> > sortedUserOperations =
                combinedUserOperations.OrderByDescending(
                    op =>
                    CalculateUserOperationPremiumGasPrice(op.Item2, parent.BaseFeePerGas))
                .ToList();

            foreach (Tuple <Address, UserOperation> addressedUserOperation in sortedUserOperations)
            {
                (Address entryPoint, UserOperation userOperation) = addressedUserOperation;

                ulong userOperationTotalGasLimit = (ulong)userOperation.CallGas +
                                                   (ulong)userOperation.PreVerificationGas +
                                                   (ulong)userOperation.VerificationGas;

                if (gasUsed + userOperationTotalGasLimit > (ulong)gasLimit)
                {
                    continue;
                }

                // no intersect of accessed addresses between ops
                if (userOperation.AccessList.AccessListOverlaps(usedAccessList))
                {
                    continue;
                }

                // simulate again to make sure the op is still valid
                ResultWrapper <Keccak> result = _userOperationSimulators[entryPoint].Simulate(userOperation, parent);
                if (result.Result != Result.Success)
                {
                    //if (_logger.IsDebug) commented out for testing
                    {
                        _logger.Debug($"UserOperation {userOperation.RequestId!} resimulation unsuccessful: {result.Result.Error}");
                        // TODO: Remove logging, just for testing
                        _logger.Info($"UserOperation {userOperation.RequestId!} resimulation unsuccessful: {result.Result.Error}");

                        bool removeResult = _userOperationPools[entryPoint].RemoveUserOperation(userOperation.RequestId !);
                        if (_logger.IsDebug)
                        {
                            _logger.Debug(
                                removeResult ?
                                "Removed UserOperation {userOperation.Hash} from Pool"
                                : "Failed to remove UserOperation {userOperation} from Pool");
                        }
                    }

                    continue;
                }

                gasUsed += userOperationTotalGasLimit;

                // add user operation with correct entryPoint
                if (userOperationsToIncludeByEntryPoint.TryGetValue(entryPoint, out IList <UserOperation>?userOperations))
                {
                    userOperations.Add(userOperation);
                }
                else
                {
                    userOperationsToIncludeByEntryPoint[entryPoint] = new List <UserOperation> {
                        userOperation
                    };
                }

                // add userOp accessList to combined list
                foreach (KeyValuePair <Address, HashSet <UInt256> > kv in userOperation.AccessList.Data)
                {
                    if (usedAccessList.ContainsKey(kv.Key))
                    {
                        usedAccessList[kv.Key].UnionWith(kv.Value);
                    }
                    else
                    {
                        usedAccessList[kv.Key] = kv.Value;
                    }
                }
            }

            if (userOperationsToIncludeByEntryPoint.Count == 0)
            {
                yield break;
            }

            UInt256 initialNonce = _stateProvider.GetNonce(_signer.Address);
            UInt256 txsBuilt     = 0;

            // build transaction for each entryPoint with ops to be included
            foreach (KeyValuePair <Address, UserOperationTxBuilder> kv in _userOperationTxBuilders)
            {
                Address entryPoint = kv.Key;
                IUserOperationTxBuilder txBuilder = kv.Value;

                bool foundUserOperations =
                    userOperationsToIncludeByEntryPoint.TryGetValue(entryPoint, out IList <UserOperation>?userOperationsToInclude);
                if (!foundUserOperations)
                {
                    continue;
                }

                long totalGasUsed = userOperationsToInclude !.Aggregate((long)0,
                                                                        (sum, op) =>
                                                                        sum +
                                                                        (long)op.CallGas +
                                                                        (long)op.PreVerificationGas +
                                                                        (long)op.VerificationGas);

                // build test transaction to make sure it succeeds as a batch of ops
                Transaction userOperationTransaction =
                    txBuilder.BuildTransactionFromUserOperations(
                        userOperationsToInclude !,
                        parent,
                        totalGasUsed,
                        initialNonce,
                        _specProvider.GetSpec(parent.Number + 1));
                if (_logger.IsDebug)
                {
                    _logger.Debug($"Constructed tx from {userOperationsToInclude!.Count} userOperations: {userOperationTransaction.Hash}");
                }
                // TODO: Remove logging, just for testing
                _logger.Info($"Constructed tx from {userOperationsToInclude!.Count} userOperations: {userOperationTransaction.Hash}");

                BlockchainBridge.CallOutput callOutput = _userOperationSimulators[entryPoint].EstimateGas(parent, userOperationTransaction, CancellationToken.None);
                FailedOp?failedOp = txBuilder.DecodeEntryPointOutputError(callOutput.OutputData);
                if (failedOp is not null)
                {
                    UserOperation opToRemove = userOperationsToInclude[(int)failedOp.Value._opIndex];
                    _userOperationPools[entryPoint].RemoveUserOperation(opToRemove.RequestId !);
                    continue;
                }
                if (callOutput.Error != null)
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn($"AA Simulation error for entryPoint {entryPoint}: {callOutput.Error}");
                    }
                    continue;
                }

                // construct tx with previously estimated gas limit
                Transaction updatedUserOperationTransaction =
                    _userOperationTxBuilders[entryPoint].BuildTransactionFromUserOperations(
                        userOperationsToInclude,
                        parent,
                        callOutput.GasSpent + 200000,
                        initialNonce + txsBuilt,
                        _specProvider.GetSpec(parent.Number + 1));

                txsBuilt++;
                yield return(updatedUserOperationTransaction);
            }
        }
        public IEnumerable <Transaction> GetTransactions(BlockHeader parent, long gasLimit)
        {
            IDictionary <Address, HashSet <UInt256> > usedAccessList = new Dictionary <Address, HashSet <UInt256> >();
            IList <UserOperation> userOperationsToInclude            = new List <UserOperation>();
            ulong gasUsed = 0;

            IEnumerable <UserOperation> userOperations =
                _userOperationPool
                .GetUserOperations()
                .Where(op => op.MaxFeePerGas >= parent.BaseFeePerGas)
                .OrderByDescending(op => CalculateUserOperationPremiumGasPrice(op, parent.BaseFeePerGas));

            foreach (UserOperation userOperation in userOperations)
            {
                if (gasUsed >= (ulong)gasLimit)
                {
                    continue;
                }

                // no intersect of accessed addresses between ops
                if (userOperation.AccessList.AccessListOverlaps(usedAccessList))
                {
                    continue;
                }

                // simulate again to make sure the op is still valid
                ResultWrapper <Keccak> result = _userOperationSimulator.Simulate(userOperation, parent);
                if (result.Result != Result.Success)
                {
                    //if (_logger.IsDebug) commented out for testing
                    {
                        _logger.Debug($"UserOperation {userOperation.Hash} resimulation unsuccessful: {result.Result.Error}");
                        // TODO: Remove logging, just for testing
                        _logger.Info($"UserOperation {userOperation.Hash} resimulation unsuccessful: {result.Result.Error}");

                        bool removeResult = _userOperationPool.RemoveUserOperation(userOperation.Hash);
                        if (_logger.IsDebug)
                        {
                            _logger.Debug(
                                removeResult ?
                                "Removed UserOperation {userOperation.Hash} from Pool"
                                : "Failed to remove UserOperation {userOperation} from Pool");
                        }
                    }

                    continue;
                }

                userOperationsToInclude.Add(userOperation);
                gasUsed += (ulong)userOperation.CallGas +
                           (ulong)userOperation.PreVerificationGas +
                           (ulong)userOperation.VerificationGas;

                // add userOp accessList to combined list
                foreach (KeyValuePair <Address, HashSet <UInt256> > kv in userOperation.AccessList.Data)
                {
                    if (usedAccessList.ContainsKey(kv.Key))
                    {
                        usedAccessList[kv.Key].UnionWith(kv.Value);
                    }
                    else
                    {
                        usedAccessList[kv.Key] = kv.Value;
                    }
                }
            }

            if (userOperationsToInclude.Count == 0)
            {
                return(new List <Transaction>());
            }

            Transaction userOperationTransaction =
                _userOperationTxBuilder.BuildTransactionFromUserOperations(
                    userOperationsToInclude,
                    parent,
                    100_000_000, // high gas to test
                    _specProvider.GetSpec(parent.Number + 1));

            if (_logger.IsDebug)
            {
                _logger.Debug($"Constructed tx from {userOperationsToInclude.Count} userOperations: {userOperationTransaction.Hash}");
            }
            // TODO: Remove logging, just for testing
            _logger.Info($"Constructed tx from {userOperationsToInclude.Count} userOperations: {userOperationTransaction.Hash}");

            BlockchainBridge.CallOutput callOutput = _userOperationSimulator.EstimateGas(parent, userOperationTransaction, CancellationToken.None);
            FailedOp?failedOp = _userOperationTxBuilder.DecodeEntryPointOutputError(callOutput.OutputData);

            if (failedOp is not null)
            {
                // TODO punish paymaster
            }

            Transaction updatedUserOperationTransaction =
                _userOperationTxBuilder.BuildTransactionFromUserOperations(
                    userOperationsToInclude,
                    parent,
                    callOutput.GasSpent,
                    _specProvider.GetSpec(parent.Number + 1));

            return(new List <Transaction> {
                updatedUserOperationTransaction
            });
        }
示例#22
0
 protected ResultWrapper <TResult> GetInputError(BlockchainBridge.CallOutput result) =>
 ResultWrapper <TResult> .Fail(result.Error ?? string.Empty, ErrorCodes.InvalidInput);
示例#23
0
            private static AccessListItemForRpc[] GetResultAccessList(Transaction tx, BlockchainBridge.CallOutput result)
            {
                AccessList?accessList = result.AccessList ?? tx.AccessList;

                return(accessList is null?Array.Empty <AccessListItemForRpc>() : AccessListItemForRpc.FromAccessList(accessList));
            }