private (bool success, UserOperationAccessList accessList, string?error) SimulateValidation( Transaction transaction, UserOperation userOperation, BlockHeader parent, ITransactionProcessor transactionProcessor) { UserOperationBlockTracer blockTracer = CreateBlockTracer(parent, userOperation); ITxTracer txTracer = blockTracer.StartNewTxTrace(transaction); transactionProcessor.CallAndRestore(transaction, parent, txTracer); blockTracer.EndTxTrace(); string?error = null; if (!blockTracer.Success) { if (blockTracer.FailedOp is not null) { error = blockTracer.FailedOp.ToString() !; } else { error = blockTracer.Error; } return(false, UserOperationAccessList.Empty, error); } UserOperationAccessList userOperationAccessList = new(blockTracer.AccessedStorage); return(true, userOperationAccessList, error); }
// TODO: block processor pipeline private void ApplyMinerRewards(Block block, IBlockTracer tracer, IReleaseSpec spec) { if (_logger.IsTrace) { _logger.Trace("Applying miner rewards:"); } BlockReward[] rewards = _rewardCalculator.CalculateRewards(block); for (int i = 0; i < rewards.Length; i++) { BlockReward reward = rewards[i]; ITxTracer txTracer = NullTxTracer.Instance; if (tracer.IsTracingRewards) { // we need this tracer to be able to track any potential miner account creation txTracer = tracer.StartNewTxTrace(null); } ApplyMinerReward(block, reward, spec); if (tracer.IsTracingRewards) { tracer.EndTxTrace(); tracer.ReportReward(reward.Address, reward.RewardType.ToLowerString(), reward.Value); if (txTracer.IsTracingState) { _stateProvider.Commit(spec, txTracer); } } } }
private void ApplyMinerRewards(Block block, IBlockTracer tracer) { if (_logger.IsTrace) { _logger.Trace("Applying miner rewards:"); } var rewards = _rewardCalculator.CalculateRewards(block); for (int i = 0; i < rewards.Length; i++) { BlockReward reward = rewards[i]; ITxTracer txTracer = null; if (tracer.IsTracingRewards) { txTracer = tracer.StartNewTxTrace(null); } ApplyMinerReward(block, reward, tracer.IsTracingRewards ? tracer : NullBlockTracer.Instance); if (tracer.IsTracingRewards) { tracer.EndTxTrace(); tracer.ReportReward(reward.Address, reward.RewardType.ToLowerString(), (UInt256)reward.Value); if (txTracer?.IsTracingState ?? false) { _stateProvider.Commit(_specProvider.GetSpec(block.Number), txTracer); } } } }
private void ApplyMinerRewards(Block block, IBlockTracer tracer) { if (_logger.IsTrace) { _logger.Trace("Applying miner rewards:"); } var rewards = _rewardCalculator.CalculateRewards(block); for (int i = 0; i < rewards.Length; i++) { BlockReward reward = rewards[i]; ITxTracer txTracer = null; if (tracer.IsTracingRewards) { // we need this tracer to be able to track any potential miner account creation txTracer = tracer.StartNewTxTrace(null); } ApplyMinerReward(block, reward); if (tracer.IsTracingRewards) { tracer.EndTxTrace(); tracer.ReportReward(reward.Address, reward.RewardType.ToLowerString(), reward.Value); if (txTracer?.IsTracingState ?? false) { _stateProvider.Commit(_specProvider.GetSpec(block.Number), txTracer); } } } }
public void BuildUp(Transaction transaction, BlockHeader block, ITxTracer txTracer) { // we need to treat the result of previous transaction as the original value of next transaction // when we do not commit _worldState.TakeSnapshot(true); Execute(transaction, block, txTracer, ExecutionOptions.None); }
private static void QuickFail(PublicEntry entry, ExecutionEnvironment env, ITxTracer txTracer) { // here we need to propagate back to Delta env.CurrentBlock.GasUsed += (long)entry.GasLimit; if (txTracer.IsTracingReceipt) { txTracer.MarkAsFailed(env.ExecutingAccount, (long)entry.GasLimit, Bytes.Empty, "invalid"); } }
private void QuickFail(Transaction tx, StateUpdate block, ITxTracer txTracer, bool readOnly) { block.GasUsed += (long)tx.GasLimit; Address recipient = tx.To ?? Address.OfContract(tx.SenderAddress, _stateProvider.GetNonce(tx.SenderAddress)); if (txTracer.IsTracingReceipt) { txTracer.MarkAsFailed(recipient, (long)tx.GasLimit, Bytes.Empty, "invalid"); } }
public void SetOperationStack(List <string> stackTrace) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingStack) { innerTracer.SetOperationStack(stackTrace); } } }
public void ReportOperationRemainingGas(long gas) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingInstructions) { innerTracer.ReportOperationRemainingGas(gas); } } }
public void ReportOperationError(EvmExceptionType error) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingInstructions) { innerTracer.ReportOperationError(error); } } }
public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Keccak?stateRoot = null) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingReceipt) { innerTracer.MarkAsFailed(recipient, gasSpent, output, error, stateRoot); } } }
public void ReportStorageRead(StorageCell storageCell) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingStorage) { innerTracer.ReportStorageRead(storageCell); } } }
public void ReportStorageChange(StorageCell storageCell, byte[] before, byte[] after) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingStorage) { innerTracer.ReportStorageChange(storageCell, before, after); } } }
public void ReportAccountRead(Address address) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingState) { innerTracer.ReportAccountRead(address); } } }
public void ReportCodeChange(Address address, byte[] before, byte[] after) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingState) { innerTracer.ReportCodeChange(address, before, after); } } }
public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Keccak?stateRoot = null) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingReceipt) { innerTracer.MarkAsSuccess(recipient, gasSpent, output, logs, stateRoot); } } }
public void StartOperation(int depth, long gas, Instruction opcode, int pc) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingInstructions) { innerTracer.StartOperation(depth, gas, opcode, pc); } } }
public void ReportBalanceChange(Address address, UInt256?before, UInt256?after) { for (int index = 0; index < _txTracers.Count; index++) { ITxTracer innerTracer = _txTracers[index]; if (innerTracer.IsTracingState) { innerTracer.ReportBalanceChange(address, before, after); } } }
private bool ValidateSender(PublicEntry entry, ExecutionEnvironment env, ITxTracer txTracer) { if (env.Sender != null) { return(true); } TraceLogInvalidTx(entry, "SENDER_NOT_SPECIFIED"); QuickFail(entry, env, txTracer); return(false); }
private bool ValidateNonce(PublicEntry entry, ExecutionEnvironment env, ITxTracer txTracer) { if (entry.Nonce == _stateProvider.GetNonce(env.Sender)) { return(true); } TraceLogInvalidTx(entry, $"WRONG_TRANSACTION_NONCE: {entry.Nonce.ToString()} (expected {_stateProvider.GetNonce(env.Sender).ToString()})"); QuickFail(entry, env, txTracer); return(false); }
public static CancellationTxTracer WithCancellation(this ITxTracer txTracer, CancellationToken cancellationToken, bool setDefaultCancellations = true) { return(!setDefaultCancellations ? new(txTracer, cancellationToken) : new (txTracer, cancellationToken) { IsTracingActions = true, IsTracingOpLevelStorage = true, IsTracingInstructions = true, // a little bit costly but almost all are simple calls IsTracingRefunds = true }); }
private void QuickFail(Transaction tx, BlockHeader block, ITxTracer txTracer, string reason) { block.GasUsed += tx.GasLimit; Address recipient = tx.To ?? ContractAddress.From(tx.SenderAddress, _stateProvider.GetNonce(tx.SenderAddress)); _stateProvider.RecalculateStateRoot(); Keccak stateRoot = _specProvider.GetSpec(block.Number).IsEip658Enabled ? null : _stateProvider.StateRoot; if (txTracer.IsTracingReceipt) { txTracer.MarkAsFailed(recipient, tx.GasLimit, Array.Empty <byte>(), reason ?? "invalid", stateRoot); } }
public void Can_serialize_reward() { Block block = Build.A.Block.WithNumber(long.Parse("4563918244f40000".AsSpan(), NumberStyles.AllowHexSpecifier)).TestObject; IBlockTracer blockTracer = new ParityLikeBlockTracer(ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); blockTracer.StartNewBlockTrace(block); ITxTracer txTracer = blockTracer.StartNewTxTrace(null); txTracer.ReportBalanceChange(TestItem.AddressA, 0, 3.Ether()); blockTracer.EndTxTrace(); blockTracer.ReportReward(TestItem.AddressA, "block", UInt256.One); ParityLikeTxTrace trace = ((ParityLikeBlockTracer)blockTracer).BuildResult().SingleOrDefault(); TestOneWaySerialization(trace, "{\"trace\":[{\"action\":{\"callType\":\"reward\",\"from\":null,\"gas\":\"0x0\",\"input\":null,\"to\":null,\"value\":\"0x1\"},\"blockHash\":\"0xfed4f714d3626e046786ef043cbb30a4b87cdc288469d0b70e4529bbd4e15396\",\"blockNumber\":\"0x4563918244f40000\",\"result\":{\"gasUsed\":\"0x0\",\"output\":null},\"subtraces\":0,\"traceAddress\":\"[]\",\"transactionHash\":null,\"transactionPosition\":null,\"type\":\"reward\"}],\"stateDiff\":{\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\":{\"balance\":{\"*\":{\"from\":\"0x0\",\"to\":\"0x29a2241af62c0000\"}},\"code\":\"=\",\"nonce\":\"=\",\"storage\":{}}}}"); }
public void Can_serialize_reward_state_only() { Block block = Build.A.Block.WithNumber(long.Parse("4563918244f40000".AsSpan(), NumberStyles.AllowHexSpecifier)).TestObject; IBlockTracer blockTracer = new ParityLikeBlockTracer(ParityTraceTypes.StateDiff); blockTracer.StartNewBlockTrace(block); ITxTracer txTracer = blockTracer.StartNewTxTrace(null); txTracer.ReportBalanceChange(TestItem.AddressA, 0, 3.Ether()); blockTracer.EndTxTrace(); blockTracer.ReportReward(TestItem.AddressA, "block", UInt256.One); ParityLikeTxTrace trace = ((ParityLikeBlockTracer)blockTracer).BuildResult().SingleOrDefault(); TestOneWaySerialization(trace, "{\"trace\":null,\"stateDiff\":{\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\":{\"balance\":{\"*\":{\"from\":\"0x0\",\"to\":\"0x29a2241af62c0000\"}},\"code\":\"=\",\"nonce\":\"=\",\"storage\":{}}}}"); }
public void Can_serialize_reward() { Block block = Build.A.Block.WithNumber(long.Parse("4563918244f40000".AsSpan(), NumberStyles.AllowHexSpecifier)).TestObject; IBlockTracer blockTracer = new ParityLikeBlockTracer(ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); blockTracer.StartNewBlockTrace(block); ITxTracer txTracer = blockTracer.StartNewTxTrace(null); txTracer.ReportBalanceChange(TestItem.AddressA, 0, 3.Ether()); blockTracer.EndTxTrace(); blockTracer.ReportReward(TestItem.AddressA, "block", UInt256.One); ParityLikeTxTrace trace = ((ParityLikeBlockTracer)blockTracer).BuildResult().SingleOrDefault(); TestToJson(new ParityTxTraceFromReplay(trace), "{\"output\":null,\"stateDiff\":{\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\":{\"balance\":{\"*\":{\"from\":\"0x0\",\"to\":\"0x29a2241af62c0000\"}},\"code\":\"=\",\"nonce\":\"=\",\"storage\":{}}},\"trace\":[{\"action\":{\"author\":\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\",\"rewardType\":\"block\",\"value\":\"0x1\"},\"result\":null,\"subtraces\":0,\"traceAddress\":[],\"type\":\"reward\"}],\"vmTrace\":null}"); }
private (bool Success, string Error) TryCallAndRestore( BlockHeader blockHeader, long number, UInt256 timestamp, Transaction transaction, ITxTracer tracer) { try { CallAndRestore(blockHeader, number, timestamp, transaction, tracer); return(true, string.Empty); } catch (InsufficientBalanceException ex) { return(false, ex.Message); } }
private bool ValidateSenderBalance(PublicEntry entry, ExecutionEnvironment env, ulong intrinsicGas, ITxTracer txTracer) { var senderBalance = _stateProvider.GetBalance(env.Sender); if (intrinsicGas * env.GasPrice + env.Value <= senderBalance) { return(true); } TraceLogInvalidTx(entry, $"INSUFFICIENT_SENDER_BALANCE: ({env.Sender})_BALANCE = {senderBalance.ToString()}"); QuickFail(entry, env, txTracer); return(false); }
public ITxTracer StartNewTxTrace(Transaction?tx) { IList <IBlockTracer> childBlockTracers = _childTracers; List <ITxTracer> tracers = new(childBlockTracers.Count); for (int i = 0; i < childBlockTracers.Count; i++) { IBlockTracer childBlockTracer = childBlockTracers[i]; ITxTracer txTracer = childBlockTracer.StartNewTxTrace(tx); if (txTracer != NullTxTracer.Instance) { tracers.Add(txTracer); } } return(tracers.Count > 0 ? new CompositeTxTracer(tracers) : NullTxTracer.Instance); }
public CompositeTxTracer(IList <ITxTracer> txTracers) { _txTracers = txTracers; for (int index = 0; index < txTracers.Count; index++) { ITxTracer t = txTracers[index]; IsTracingState |= t.IsTracingState; IsTracingReceipt |= t.IsTracingReceipt; IsTracingActions |= t.IsTracingActions; IsTracingOpLevelStorage |= t.IsTracingOpLevelStorage; IsTracingMemory |= t.IsTracingMemory; IsTracingInstructions |= t.IsTracingInstructions; IsTracingRefunds |= t.IsTracingRefunds; IsTracingCode |= t.IsTracingCode; IsTracingStack |= t.IsTracingStack; IsTracingBlockHash |= t.IsTracingBlockHash; IsTracingStorage |= t.IsTracingStorage; IsTracingAccess |= t.IsTracingAccess; } }
private bool ValidateIntrinsicGas(PublicEntry entry, ExecutionEnvironment env, ulong intrinsicGas, ITxTracer txTracer) { if (_logger.IsEnabled(LogEventLevel.Verbose)) { _logger.Verbose("Intrinsic gas calculated for {entry}: {intrinsicGas}", entry, intrinsicGas); } if (entry.GasLimit >= intrinsicGas) { return(true); } TraceLogInvalidTx(entry, $"GAS_LIMIT_BELOW_INTRINSIC_GAS {entry.GasLimit.ToString()} < {intrinsicGas.ToString()}"); QuickFail(entry, env, txTracer); return(false); }