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); }
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)); }
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); }
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)); }
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)); }
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)); }
public AcceptTxResult Accept(Transaction tx, TxHandlingOptions handlingOptions) { if (tx.Hash is null) { return(AcceptTxResult.Invalid.WithMessage("transaction Hash is null")); } return(AcceptTxResult.Accepted); }
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()); }
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())); }
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); }
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); } }
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)); }
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); }
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); }
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); }
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); }
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); }
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)); }
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); }
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); }
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); }
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))); }
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)); }
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); }
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)); }
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); }
public AddTxResult AddTransaction(Transaction tx, long blockNumber, TxHandlingOptions txHandlingOptions) => AddTxResult.Added;