public async Task Should_count_total_coinbase_payments() { var chain = await MevRpcModuleTests.CreateChain(1); chain.GasLimitCalculator.GasLimit = 10_000_000; Address contractAddress = await MevRpcModuleTests.Contracts.Deploy(chain, MevRpcModuleTests.Contracts.CoinbaseCode); BundleTransaction seedContractTx = Build.A.TypedTransaction <BundleTransaction>() .WithTo(contractAddress) .WithData(Bytes.FromHexString(MevRpcModuleTests.Contracts.CoinbaseDeposit)) .WithValue(100000000000) .WithNonce(1) .WithGasLimit(1_000_000) .SignedAndResolved(TestItem.PrivateKeyC).TestObject; await chain.AddBlock(true, seedContractTx); //Console.WriteLine((await chain.EthRpcModule.eth_getBalance(contractAddress)).Data!); UInt256 beforeCoinbasePayments = (UInt256)Metrics.TotalCoinbasePayments; BundleTransaction coinbaseTx = Build.A.TypedTransaction <BundleTransaction>() .WithGasLimit(MevRpcModuleTests.Contracts.LargeGasLimit) .WithData(Bytes.FromHexString(MevRpcModuleTests.Contracts.CoinbaseInvokePay)) .WithTo(contractAddress) .WithGasPrice(1ul) .WithNonce(0) .WithValue(0) .SignedAndResolved(TestItem.PrivateKeyA).TestObject; MevRpcModuleTests.SuccessfullySendBundle(chain, 3, coinbaseTx); await chain.AddBlock(true); MevRpcModuleTests.GetHashes(chain.BlockTree.Head !.Transactions).Should().Equal(MevRpcModuleTests.GetHashes(new [] { coinbaseTx })); UInt256 deltaCoinbasePayments = (UInt256)Metrics.TotalCoinbasePayments - beforeCoinbasePayments; deltaCoinbasePayments.Should().Be(100000000000); }
private TxAction ProcessBundleTransaction( Block block, BundleTransaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions, LinkedHashSet <Transaction> transactionsInBlock) { TxAction action = ProcessTransaction(block, currentTx, index, receiptsTracer, processingOptions, transactionsInBlock, false); if (action == TxAction.Add) { string?error = receiptsTracer.LastReceipt.Error; bool transactionSucceeded = string.IsNullOrEmpty(error) || (error == "revert" && currentTx.CanRevert); return(transactionSucceeded ? TxAction.Add : TxAction.Skip); } else { return(action); } }
private static BundleTransaction[] Decode(byte[][] transactions, ISet <Keccak>?revertingTxHashes = null) { revertingTxHashes ??= new HashSet <Keccak>(); BundleTransaction[] txs = new BundleTransaction[transactions.Length]; for (int i = 0; i < transactions.Length; i++) { BundleTransaction bundleTransaction = Rlp.Decode <BundleTransaction>(transactions[i], RlpBehaviors.SkipTypedWrapping); Keccak transactionHash = bundleTransaction.Hash !; bundleTransaction.CanRevert = revertingTxHashes.Contains(transactionHash); revertingTxHashes.Remove(transactionHash); txs[i] = bundleTransaction; } if (revertingTxHashes.Count > 0) { throw new ArgumentException( $"Bundle didn't contain some of revertingTxHashes: [{string.Join(", ", revertingTxHashes.OfType<object>())}]", nameof(revertingTxHashes)); } return(txs); }
protected override SimulatedMevBundle BuildResult(MevBundle bundle, BundleBlockTracer tracer) { UInt256 eligibleGasFeePayment = UInt256.Zero; UInt256 totalGasFeePayment = UInt256.Zero; bool success = true; for (int i = 0; i < bundle.Transactions.Count; i++) { BundleTransaction tx = bundle.Transactions[i]; tx.SimulatedBundleGasUsed = (UInt256)tracer.GasUsed; success &= tracer.TransactionResults[i]; totalGasFeePayment += tracer.TxFees[i]; if (!_txPool.IsKnown(tx.Hash)) { eligibleGasFeePayment += tracer.TxFees[i]; } } for (int i = 0; i < bundle.Transactions.Count; i++) { bundle.Transactions[i].SimulatedBundleFee = totalGasFeePayment + tracer.CoinbasePayments; } if ((UInt256)decimal.MaxValue >= (UInt256)Metrics.TotalCoinbasePayments + tracer.CoinbasePayments) { Metrics.TotalCoinbasePayments += (decimal)tracer.CoinbasePayments; } else { Metrics.TotalCoinbasePayments = ulong.MaxValue; } return(new(bundle, tracer.GasUsed, success, tracer.BundleFee, tracer.CoinbasePayments, eligibleGasFeePayment)); }
private TxAction ProcessBundle(Block block, List <BundleTransaction> bundleTransactions, LinkedHashSet <Transaction> transactionsInBlock, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions) { Snapshot snapshot = _worldState.TakeSnapshot(); int receiptSnapshot = receiptsTracer.TakeSnapshot(); UInt256 initialBalance = _stateProvider.GetBalance(block.Header.GasBeneficiary !); bool CheckFeeNotManipulated() { UInt256 finalBalance = _stateProvider.GetBalance(block.Header.GasBeneficiary !); UInt256 feeReceived = finalBalance - initialBalance; UInt256 originalSimulatedGasPrice = bundleTransactions[0].SimulatedBundleFee / bundleTransactions[0].SimulatedBundleGasUsed; UInt256 actualGasPrice = feeReceived / (UInt256)receiptsTracer.LastReceipt.GasUsed !; return(actualGasPrice >= originalSimulatedGasPrice); } bool bundleSucceeded = bundleTransactions.Count > 0; TxAction txAction = TxAction.Skip; for (int index = 0; index < bundleTransactions.Count && bundleSucceeded; index++) { txAction = ProcessBundleTransaction(block, bundleTransactions[index], index, receiptsTracer, processingOptions, transactionsInBlock); bundleSucceeded &= txAction == TxAction.Add; // if we need to stop on not first tx in the bundle, we actually want to skip the bundle txAction = txAction == TxAction.Stop && index != 0 ? TxAction.Skip : txAction; } if (bundleSucceeded) { bundleSucceeded &= CheckFeeNotManipulated(); } if (bundleSucceeded) { for (int index = 0; index < bundleTransactions.Count; index++) { BundleTransaction bundleTransaction = bundleTransactions[index]; transactionsInBlock.Add(bundleTransaction); int txIndex = receiptSnapshot + index; _transactionProcessed?.Invoke(this, new TxProcessedEventArgs(txIndex, bundleTransaction, receiptsTracer.TxReceipts[txIndex])); } } else { _worldState.Restore(snapshot); receiptsTracer.Restore(receiptSnapshot); for (int index = 0; index < bundleTransactions.Count; index++) { transactionsInBlock.Remove(bundleTransactions[index]); } } bundleTransactions.Clear(); return(txAction); }