Beispiel #1
0
        public UserOperationSimulator(
            IUserOperationTxBuilder userOperationTxBuilder,
            IStateProvider stateProvider,
            IStateReader stateReader,
            AbiDefinition entryPointContractAbi,
            Address create2FactoryAddress,
            Address entryPointContractAddress,
            ISpecProvider specProvider,
            IBlockTree blockTree,
            IDbProvider dbProvider,
            IReadOnlyTrieStore trieStore,
            ITimestamper timestamper,
            ILogManager logManager)
        {
            _userOperationTxBuilder    = userOperationTxBuilder;
            _stateProvider             = stateProvider;
            _stateReader               = stateReader;
            _entryPointContractAbi     = entryPointContractAbi;
            _create2FactoryAddress     = create2FactoryAddress;
            _entryPointContractAddress = entryPointContractAddress;
            _specProvider              = specProvider;
            _blockTree   = blockTree;
            _dbProvider  = dbProvider.AsReadOnly(false);
            _trieStore   = trieStore;
            _timestamper = timestamper;
            _logManager  = logManager;

            _abiEncoder = new AbiEncoder();
        }
 public UserOperationTxSource(
     IUserOperationTxBuilder userOperationTxBuilder,
     IUserOperationPool userOperationPool,
     IUserOperationSimulator userOperationSimulator,
     ISpecProvider specProvider,
     ILogger logger)
 {
     _userOperationTxBuilder = userOperationTxBuilder;
     _userOperationPool      = userOperationPool;
     _userOperationSimulator = userOperationSimulator;
     _specProvider           = specProvider;
     _logger = logger;
 }
        public UserOperationSimulator(
            IUserOperationTxBuilder userOperationTxBuilder,
            IReadOnlyStateProvider stateProvider,
            ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory,
            AbiDefinition entryPointContractAbi,
            Address entryPointContractAddress,
            Address[] whitelistedPaymasters,
            ISpecProvider specProvider,
            ITimestamper timestamper,
            ILogManager logManager)
        {
            _userOperationTxBuilder         = userOperationTxBuilder;
            _stateProvider                  = stateProvider;
            _readOnlyTxProcessingEnvFactory = readOnlyTxProcessingEnvFactory;
            _entryPointContractAbi          = entryPointContractAbi;
            _entryPointContractAddress      = entryPointContractAddress;
            _whitelistedPaymasters          = whitelistedPaymasters;
            _specProvider = specProvider;
            _timestamper  = timestamper;
            _logger       = logManager.GetClassLogger <UserOperationSimulator>();

            _abiEncoder = new AbiEncoder();
        }
Beispiel #4
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);
            }
        }