Ejemplo n.º 1
0
        public Keccak SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            if (tx.Signature == null)
            {
                if (_wallet.IsUnlocked(tx.SenderAddress))
                {
                    Sign(tx);
                }
                else
                {
                    throw new SecurityException("Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.");
                }
            }

            tx.Hash      = tx.CalculateHash();
            tx.Timestamp = _timestamper.EpochSeconds;

            AddTxResult result = _txPool.AddTransaction(tx, txHandlingOptions);

            if (result == AddTxResult.OwnNonceAlreadyUsed && (txHandlingOptions & TxHandlingOptions.ManagedNonce) == TxHandlingOptions.ManagedNonce)
            {
                // below the temporary NDM support - needs some review
                tx.Nonce = _txPool.ReserveOwnTransactionNonce(tx.SenderAddress);
                Sign(tx);
                tx.Hash = tx.CalculateHash();
                _txPool.AddTransaction(tx, txHandlingOptions);
            }

            return(tx.Hash);
        }
Ejemplo n.º 2
0
    public Task <ResultWrapper <Keccak> > eth_sendTransaction(TransactionForRpc rpcTx)
    {
        Transaction       tx      = rpcTx.ToTransactionWithDefaults(_blockchainBridge.GetChainId());
        TxHandlingOptions options = rpcTx.Nonce == null ? TxHandlingOptions.ManagedNonce : TxHandlingOptions.None;

        return(SendTx(tx, options));
    }
Ejemplo n.º 3
0
    private async Task <ResultWrapper <Keccak> > SendTx(Transaction tx,
                                                        TxHandlingOptions txHandlingOptions = TxHandlingOptions.None)
    {
        try
        {
            (Keccak txHash, AcceptTxResult? acceptTxResult) =
                await _txSender.SendTransaction(tx, txHandlingOptions | TxHandlingOptions.PersistentBroadcast);

            return(acceptTxResult.Equals(AcceptTxResult.Accepted)
                ? ResultWrapper <Keccak> .Success(txHash)
                : ResultWrapper <Keccak> .Fail(acceptTxResult?.ToString() ?? string.Empty, ErrorCodes.TransactionRejected));
        }
        catch (SecurityException e)
        {
            return(ResultWrapper <Keccak> .Fail(e.Message, ErrorCodes.AccountLocked));
        }
        catch (Exception e)
        {
            if (_logger.IsError)
            {
                _logger.Error("Failed to send transaction.", e);
            }
            return(ResultWrapper <Keccak> .Fail(e.Message, ErrorCodes.TransactionRejected));
        }
    }
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions handlingOptions)
        {
            IReleaseSpec spec           = _specProvider.GetCurrentHeadSpec();
            Account      account        = _accounts.GetAccount(tx.SenderAddress !);
            UInt256      balance        = account.Balance;
            UInt256      cumulativeCost = UInt256.Zero;
            bool         overflow       = false;

            Transaction[] transactions = _txs.GetBucketSnapshot(tx.SenderAddress);

            for (int i = 0; i < transactions.Length; i++)
            {
                if (transactions[i].Nonce < account.Nonce)
                {
                    continue;
                }

                if (transactions[i].Nonce < tx.Nonce)
                {
                    overflow |= UInt256.MultiplyOverflow(
                        transactions[i].CalculateEffectiveGasPrice(spec.IsEip1559Enabled, _headInfo.CurrentBaseFee),
                        (UInt256)transactions[i].GasLimit,
                        out UInt256 txCost);

                    overflow |= UInt256.AddOverflow(cumulativeCost, txCost, out cumulativeCost);
                    overflow |= UInt256.AddOverflow(cumulativeCost, tx.Value, out cumulativeCost);
                }
                else
                {
                    break;
                }
            }

            UInt256 affordableGasPrice = tx.CalculateAffordableGasPrice(spec.IsEip1559Enabled, _headInfo.CurrentBaseFee, balance > cumulativeCost ? balance - cumulativeCost : 0);

            overflow |= spec.IsEip1559Enabled && UInt256.AddOverflow(tx.MaxPriorityFeePerGas, tx.MaxFeePerGas, out _);
            overflow |= UInt256.MultiplyOverflow(affordableGasPrice, (UInt256)tx.GasLimit, out UInt256 cost);
            overflow |= UInt256.AddOverflow(cost, tx.Value, out cost);
            overflow |= UInt256.AddOverflow(cost, cumulativeCost, out cumulativeCost);
            if (overflow)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Skipped adding transaction {tx.ToString("  ")}, cost overflow.");
                }
                return(AcceptTxResult.Int256Overflow);
            }

            if (balance < cumulativeCost)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Skipped adding transaction {tx.ToString("  ")}, insufficient funds.");
                }
                return(AcceptTxResult.InsufficientFunds.WithMessage($"Account balance: {balance}, cumulative cost: {cumulativeCost}"));
            }

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 5
0
        public Keccak SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            // TODO: Move to Uint256 when we support division
            ulong minGasPrice = (ulong)CurrentMinGasPrice();

            tx.GasPrice = minGasPrice * _percentDelta / 100;
            return(_txSender.SendTransaction(tx, txHandlingOptions));
        }
Ejemplo n.º 6
0
        public ValueTask <Keccak> SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            UInt256 minGasPrice = CurrentMinGasPrice();
            UInt256 txGasPrice  = minGasPrice * _percentDelta / 100;

            tx.GasPrice = UInt256.Max(txGasPrice, _miningConfig.MinGasPrice);
            return(_txSender.SendTransaction(tx, txHandlingOptions));
        }
Ejemplo n.º 7
0
        public ValueTask <(Keccak, AcceptTxResult?)> SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            UInt256 gasPriceEstimated = _gasPriceOracle.GetGasPriceEstimate() * _percentDelta / 100;

            tx.DecodedMaxFeePerGas = gasPriceEstimated;
            tx.GasPrice            = gasPriceEstimated;
            return(_txSender.SendTransaction(tx, txHandlingOptions));
        }
Ejemplo n.º 8
0
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions handlingOptions)
        {
            if (tx.Hash is null)
            {
                return(AcceptTxResult.Invalid.WithMessage("transaction Hash is null"));
            }

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 9
0
 public Keccak SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
 {
     tx.Hash = tx.CalculateHash();
     _headBlock.Transactions[_txIndex++] = tx;
     _receiptsTracer.StartNewTxTrace(tx.Hash);
     _processor.Execute(tx, Head, _receiptsTracer);
     _receiptsTracer.EndTxTrace();
     return(tx.CalculateHash());
 }
Ejemplo n.º 10
0
 public ValueTask <Keccak> SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
 {
     tx.Nonce = GetNonce(tx.SenderAddress);
     tx.Hash  = tx.CalculateHash();
     _headBlock.Transactions[_txIndex++] = tx;
     _receiptsTracer.StartNewTxTrace(tx.Hash);
     _processor.Execute(tx, Head?.Header, _receiptsTracer);
     _receiptsTracer.EndTxTrace();
     return(new ValueTask <Keccak>(tx.CalculateHash()));
 }
Ejemplo n.º 11
0
        private static void SendTransaction(ReportType reportType, ITxSender txSender, Transaction transaction)
        {
            TxHandlingOptions handlingOptions = reportType switch
            {
                ReportType.Benign => TxHandlingOptions.ManagedNonce,
                ReportType.Malicious => TxHandlingOptions.ManagedNonce | TxHandlingOptions.PersistentBroadcast,
                _ => TxHandlingOptions.ManagedNonce
            };

            txSender.SendTransaction(transaction, handlingOptions);
        }
Ejemplo n.º 12
0
 public Keccak SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
 {
     try
     {
         return(_txSender.SendTransaction(tx, txHandlingOptions));
     }
     catch (SecurityException e)
     {
         throw new SecurityException("Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.", e);
     }
 }
Ejemplo n.º 13
0
        public ValueTask <Keccak> SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            (UInt256 minFeeCap, UInt256 minGasPremium) = CurrentMinGas();
            UInt256 txFeeCap     = minFeeCap * _percentDelta / 100;
            UInt256 txGasPremium = minGasPremium * _percentDelta / 100;

            tx.DecodedFeeCap = UInt256.Max(txFeeCap, _miningConfig.MinGasPrice);
            tx.GasPrice      = txGasPremium;
            tx.Type          = TxType.EIP1559;
            return(_txSender.SendTransaction(tx, txHandlingOptions));
        }
Ejemplo n.º 14
0
        public virtual void Seal(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            bool allowChangeExistingSignature = (txHandlingOptions & TxHandlingOptions.AllowReplacingSignature) == TxHandlingOptions.AllowReplacingSignature;

            if (tx.Signature == null || allowChangeExistingSignature)
            {
                _txSigner.Sign(tx);
            }

            tx.Hash      = tx.CalculateHash();
            tx.Timestamp = _timestamper.EpochSeconds;
        }
        public override ValueTask Seal(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            bool manageNonce = (txHandlingOptions & TxHandlingOptions.ManagedNonce) == TxHandlingOptions.ManagedNonce;

            if (manageNonce)
            {
                tx.Nonce           = _txPool.ReserveOwnTransactionNonce(tx.SenderAddress);
                txHandlingOptions |= TxHandlingOptions.AllowReplacingSignature;
            }

            return(base.Seal(tx, txHandlingOptions));
        }
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions handlingOptions)
        {
            if (_hashCache.Get(tx.Hash !))
            {
                Metrics.PendingTransactionsKnown++;
                return(AcceptTxResult.AlreadyKnown);
            }

            _hashCache.SetForCurrentBlock(tx.Hash !);

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 17
0
        public virtual ValueTask Seal(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            bool allowChangeExistingSignature = (txHandlingOptions & TxHandlingOptions.AllowReplacingSignature) == TxHandlingOptions.AllowReplacingSignature;

            if (tx.Signature == null || allowChangeExistingSignature)
            {
                _txSigner.Sign(tx);
            }

            tx.Hash      = tx.CalculateHash();
            tx.Timestamp = _timestamper.UnixTime.Seconds;

            return(ValueTask.CompletedTask);
        }
Ejemplo n.º 18
0
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions handlingOptions)
        {
            long gasLimit = Math.Min(_chainHeadInfoProvider.BlockGasLimit ?? long.MaxValue, _configuredGasLimit);

            if (tx.GasLimit > gasLimit)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Skipped adding transaction {tx.ToString("  ")}, gas limit exceeded.");
                }
                return(AcceptTxResult.GasLimitExceeded.WithMessage($"Gas limit: {gasLimit}, gas limit of rejected tx: {tx.GasLimit}"));
            }

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 19
0
        public Keccak SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            foreach (var sealer in _sealers)
            {
                sealer.Seal(tx);

                AddTxResult result = _txPool.AddTransaction(tx, txHandlingOptions);

                if (result != AddTxResult.OwnNonceAlreadyUsed || (txHandlingOptions & TxHandlingOptions.ManagedNonce) != TxHandlingOptions.ManagedNonce)
                {
                    break;
                }
            }

            return(tx.Hash);
        }
Ejemplo n.º 20
0
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            IReleaseSpec spec = _specProvider.GetCurrentHeadSpec();

            if (!_txValidator.IsWellFormed(tx, spec))
            {
                // It may happen that other nodes send us transactions that were signed for another chain or don't have enough gas.
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Skipped adding transaction {tx.ToString("  ")}, invalid transaction.");
                }
                return(AcceptTxResult.Invalid);
            }

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 21
0
        public ValueTask <Keccak> SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            // TODO: this is very not intuitive - can we fix it...?
            // maybe move nonce reservation to sender itself before sealing
            // sealers should behave like composite and not like chain of commands
            foreach (var sealer in _sealers)
            {
                sealer.Seal(tx, txHandlingOptions);

                AddTxResult result = _txPool.AddTransaction(tx, txHandlingOptions);

                if (result != AddTxResult.OwnNonceAlreadyUsed || (txHandlingOptions & TxHandlingOptions.ManagedNonce) != TxHandlingOptions.ManagedNonce)
                {
                    break;
                }
            }

            return(new ValueTask <Keccak>(tx.Hash));
        }
Ejemplo n.º 22
0
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions handlingOptions)
        {
            // As we have limited number of transaction that we store in mem pool its fairly easy to fill it up with
            // high-priority garbage transactions. We need to filter them as much as possible to use the tx pool space
            // efficiently. One call to get account from state is not that costly and it only happens after previous checks.
            // This was modeled by OpenEthereum behavior.
            Account account      = _accounts.GetAccount(tx.SenderAddress !);
            UInt256 currentNonce = account.Nonce;

            if (tx.Nonce < currentNonce)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Skipped adding transaction {tx.ToString("  ")}, nonce already used.");
                }
                return(AcceptTxResult.OldNonce.WithMessage($"Current nonce: {currentNonce}, nonce of rejected tx: {tx.Nonce}"));
            }

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 23
0
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions handlingOptions)
        {
            int     numberOfSenderTxsInPending = _txs.GetBucketCount(tx.SenderAddress);
            bool    isTxPoolFull         = _txs.IsFull();
            UInt256 currentNonce         = _accounts.GetAccount(tx.SenderAddress !).Nonce;
            long    nextNonceInOrder     = (long)currentNonce + numberOfSenderTxsInPending;
            bool    isTxNonceNextInOrder = tx.Nonce <= nextNonceInOrder;

            if (isTxPoolFull && !isTxNonceNextInOrder)
            {
                Metrics.PendingTransactionsNonceGap++;
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Skipped adding transaction {tx.ToString("  ")}, nonce in future.");
                }
                return(AcceptTxResult.NonceGap.WithMessage($"Future nonce. Expected nonce: {nextNonceInOrder}"));
            }

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 24
0
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions handlingOptions)
        {
            /* We have encountered multiple transactions that do not resolve sender address properly.
             * We need to investigate what these txs are and why the sender address is resolved to null.
             * Then we need to decide whether we really want to broadcast them.
             */
            if (tx.SenderAddress is null)
            {
                tx.SenderAddress = _ecdsa.RecoverAddress(tx);
                if (tx.SenderAddress is null)
                {
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Skipped adding transaction {tx.ToString("  ")}, no sender.");
                    }
                    return(AcceptTxResult.FailedToResolveSender);
                }
            }

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 25
0
        public ValueTask <(Keccak, AcceptTxResult?)> SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            AcceptTxResult?result = null;

            // TODO: this is very not intuitive - can we fix it...?
            // maybe move nonce reservation to sender itself before sealing
            // sealers should behave like composite and not like chain of commands
            foreach (ITxSealer sealer in _sealers)
            {
                sealer.Seal(tx, txHandlingOptions);

                result = _txPool.SubmitTx(tx, txHandlingOptions);

                if (result != AcceptTxResult.OwnNonceAlreadyUsed && result != AcceptTxResult.AlreadyKnown ||
                    (txHandlingOptions & TxHandlingOptions.ManagedNonce) != TxHandlingOptions.ManagedNonce)
                {
                    break;
                }
            }

            return(new ValueTask <(Keccak, AcceptTxResult?)>((tx.Hash, result)));
        }
Ejemplo n.º 26
0
        public async ValueTask <Keccak> SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            await EnsureAccount();

            ProvideTx provideTx = new ProvideTx();

            provideTx.Data        = "0x" + (tx.Data ?? tx.Init).ToHexString();
            provideTx.Description = "From Nethermind with love";
            provideTx.Hash        = tx.Hash?.ToString();
            provideTx.AccountId   = _accountId;
            provideTx.NetworkId   = _networkId;
            provideTx.To          = tx.To?.ToString();
            provideTx.Value       = (BigInteger)tx.Value;
            provideTx.Params      = new Dictionary <string, object>
            {
                { "subsidize", true },
            };
            // this should happen after we set the GasPrice
            _txSigner.Seal(tx, TxHandlingOptions.None);
            ProvideTx createdTx = await _provide.CreateTransaction(provideTx);

            return(createdTx?.Hash == null ? Keccak.Zero : new Keccak(createdTx.Hash));
        }
Ejemplo n.º 27
0
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions handlingOptions)
        {
            IReleaseSpec spec               = _specProvider.GetCurrentHeadSpec();
            Account      account            = _accounts.GetAccount(tx.SenderAddress !);
            UInt256      balance            = account.Balance;
            UInt256      affordableGasPrice = tx.CalculateAffordableGasPrice(spec.IsEip1559Enabled, _headInfo.CurrentBaseFee, balance);
            bool         isNotLocal         = (handlingOptions & TxHandlingOptions.PersistentBroadcast) != TxHandlingOptions.PersistentBroadcast;

            if (_txs.IsFull() &&
                _txs.TryGetLast(out Transaction? lastTx) &&
                affordableGasPrice <= lastTx?.GasBottleneck &&
                isNotLocal)
            {
                Metrics.PendingTransactionsTooLowFee++;
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Skipped adding transaction {tx.ToString("  ")}, too low payable gas price.");
                }
                return(AcceptTxResult.FeeTooLow.WithMessage($"FeePerGas needs to be higher than {lastTx.GasBottleneck.Value} to be added to the TxPool. Affordable FeePerGas of rejected tx: {affordableGasPrice}."));
            }

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 28
0
        public async ValueTask <Keccak> SendTransaction(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            ProvideTx provideTx = new ProvideTx();

            provideTx.Data        = (tx.Data ?? tx.Init).ToHexString();
            provideTx.Description = "From Nethermind with love";
            provideTx.Hash        = tx.Hash.ToString();
            provideTx.Signer      = tx.SenderAddress.ToString();
            provideTx.NetworkId   = _networkId;
            provideTx.To          = tx.To.ToString();
            provideTx.Value       = (BigInteger)tx.Value;
            provideTx.Params      = new Dictionary <string, object>
            {
                { "subsidize", true }
            };

            // this should happen after we set the GasPrice
            _txSigner.Seal(tx);

            ProvideTx createdTx = await _provide.CreateTransaction(provideTx);

            return(new Keccak(createdTx.Hash));
        }
Ejemplo n.º 29
0
        public AcceptTxResult Accept(Transaction tx, TxHandlingOptions txHandlingOptions)
        {
            if (tx is not GeneratedTransaction)
            {
                BlockHeader parentHeader = _blockTree.Head?.Header;
                if (parentHeader == null)
                {
                    return(AcceptTxResult.Accepted);
                }

                AcceptTxResult isAllowed = _txFilter.IsAllowed(tx, parentHeader);
                if (!isAllowed)
                {
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Skipped adding transaction {tx.ToString("  ")}, filtered ({isAllowed}).");
                    }
                }

                return(isAllowed);
            }

            return(AcceptTxResult.Accepted);
        }
Ejemplo n.º 30
0
 public AddTxResult AddTransaction(Transaction tx, long blockNumber, TxHandlingOptions txHandlingOptions) => AddTxResult.Added;