public void Can_trace_call_depth() { byte[] deployedCode = new byte[3]; byte[] initCode = Prepare.EvmCode .ForInitOf(deployedCode) .Done; byte[] createCode = Prepare.EvmCode .Create(initCode, 0) .Op(Instruction.STOP) .Done; TestState.CreateAccount(TestObject.AddressC, 1.Ether()); Keccak createCodeHash = TestState.UpdateCode(createCode); TestState.UpdateCodeHash(TestObject.AddressC, createCodeHash, Spec); byte[] code = Prepare.EvmCode .Call(TestObject.AddressC, 50000) .Op(Instruction.STOP) .Done; GethLikeTxTrace trace = ExecuteAndTrace(code); int[] depths = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL 3, 3, 3, 3, 3, 3, // CREATE 2, // STOP 1, // STOP }; Assert.AreEqual(depths.Length, trace.Entries.Count); for (int i = 0; i < depths.Length; i++) { Assert.AreEqual(depths[i], trace.Entries[i].Depth, $"entries[{i}]"); } }
public void Regression_mainnet_6108276() { Address deployed = Address.OfContract(TestObject.AddressC, 0); StorageAddress storageAddress = new StorageAddress(deployed, 1); byte[] deployedCode = new byte[100]; // cost is * 200 byte[] initCode = Prepare.EvmCode .PushData(1) .PushData(1) .Op(Instruction.SSTORE) .PushData(0) .PushData(1) .Op(Instruction.SSTORE) // here we reset storage so we would get refund of 15000 gas .ForInitOf(deployedCode).Done; byte[] createCode = Prepare.EvmCode .Create(initCode, 0) .PushData(0) .Op(Instruction.SSTORE) .Done; TestState.CreateAccount(TestObject.AddressC, 1.Ether()); Keccak createCodeHash = TestState.UpdateCode(createCode); TestState.UpdateCodeHash(TestObject.AddressC, createCodeHash, Spec); byte[] code = Prepare.EvmCode .Call(TestObject.AddressC, 32000 + 20003 + 20000 + 5000 + 500 + 0) // not enough .Done; var receipt = Execute(code); byte[] result = Storage.Get(storageAddress); Assert.AreEqual(new byte[] { 0 }, result, "storage reverted"); Assert.AreEqual(98777, receipt.GasSpent, "no refund"); byte[] returnData = Storage.Get(new StorageAddress(TestObject.AddressC, 0)); Assert.AreEqual(new byte[1], returnData, "address returned"); }
public void Self_destructed_returns_zero() { byte[] selfDestructCode = Prepare.EvmCode .PushData(Recipient) .Op(Instruction.SELFDESTRUCT).Done; TestState.CreateAccount(TestObject.AddressC, 1.Ether()); Keccak selfDestructCodeHash = TestState.UpdateCode(selfDestructCode); TestState.UpdateCodeHash(TestObject.AddressC, selfDestructCodeHash, Spec); byte[] code = Prepare.EvmCode .Call(TestObject.AddressC, 50000) .PushData(TestObject.AddressC) .Op(Instruction.EXTCODEHASH) .PushData(0) .Op(Instruction.SSTORE) .Done; Execute(code); AssertStorage(0, Keccak.Zero); }
public void Can_trace_nested_calls() { byte[] deployedCode = new byte[3]; byte[] initCode = Prepare.EvmCode .ForInitOf(deployedCode) .Done; byte[] createCode = Prepare.EvmCode .Create(initCode, 0) .Op(Instruction.STOP) .Done; TestState.CreateAccount(TestItem.AddressC, 1.Ether()); Keccak createCodeHash = TestState.UpdateCode(createCode); TestState.UpdateCodeHash(TestItem.AddressC, createCodeHash, Spec); byte[] code = Prepare.EvmCode .Call(TestItem.AddressC, 50000) .Op(Instruction.STOP) .Done; (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); int[] depths = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL 3, 3, 3, 3, 3, 3, // CREATE 2, // STOP 1, // STOP }; Assert.AreEqual(1, trace.Action.Subtraces.Count, "root subtraces"); Assert.AreEqual(1, trace.Action.Subtraces[0].Subtraces.Count, "[0] subtraces"); Assert.AreEqual(new[] { 0 }, trace.Action.Subtraces[0].TraceAddress, "[0] address"); Assert.AreEqual(0, trace.Action.Subtraces[0].Subtraces[0].Subtraces.Count, "[0, 0] subtraces"); Assert.AreEqual(new[] { 0, 0 }, trace.Action.Subtraces[0].Subtraces[0].TraceAddress, "[0, 0] address"); }
public void Should_fail_if_banned_opcode_is_used_when_call_depth_is_more_than_one(Instruction instruction, bool success) { byte[] deployedCode = Prepare.EvmCode .PushData("0x01") .PushData("0x69") .Op(instruction) .Done; TestState.CreateAccount(TestItem.AddressC, 1.Ether()); Keccak deployedCodeHash = TestState.UpdateCode(deployedCode); TestState.UpdateCodeHash(TestItem.AddressC, deployedCodeHash, Spec); byte[] code = Prepare.EvmCode .Call(TestItem.AddressC, 50000) .Op(Instruction.STOP) .Done; (UserOperationTxTracer tracer, _, _) = ExecuteAndTraceAccessCall(SenderRecipientAndMiner.Default, code); tracer.Success.Should().Be(success); }
public void Can_trace_storage_changes() { byte[] deployedCode = new byte[3]; byte[] initCode = Prepare.EvmCode .ForInitOf(deployedCode) .Done; byte[] createCode = Prepare.EvmCode .PersistData("0x1", HexZero) // just to test if storage is restored .Create(initCode, 0) .Op(Instruction.STOP) .Done; TestState.CreateAccount(TestItem.AddressC, 1.Ether()); Keccak createCodeHash = TestState.UpdateCode(createCode); TestState.UpdateCodeHash(TestItem.AddressC, createCodeHash, Spec); byte[] code = Prepare.EvmCode .PersistData("0x2", SampleHexData1) .PersistData("0x3", SampleHexData2) .Call(TestItem.AddressC, 70000) .Op(Instruction.STOP) .Done; (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); Assert.AreEqual(5, trace.StateChanges.Count, "state changes count"); Assert.True(trace.StateChanges.ContainsKey(Sender), "sender"); Assert.True(trace.StateChanges.ContainsKey(Recipient), "recipient"); Assert.True(trace.StateChanges.ContainsKey(TestItem.AddressC), "address c"); Assert.AreEqual(2, trace.StateChanges[Recipient].Storage.Count, "recipient storage count"); Assert.AreEqual(new byte[] { 0 }, trace.StateChanges[Recipient].Storage[2].Before, "recipient storage[2]"); Assert.AreEqual(Bytes.FromHexString(SampleHexData1), trace.StateChanges[Recipient].Storage[2].After, "recipient storage[2] after"); Assert.AreEqual(new byte[] { 0 }, trace.StateChanges[Recipient].Storage[3].Before, "recipient storage[3]"); Assert.AreEqual(Bytes.FromHexString(SampleHexData2), trace.StateChanges[Recipient].Storage[3].After, "recipient storage[3] after"); }
void DeployCodeAndAssertTx(string code, bool eip3541Enabled, ContractDeployment context, bool withoutAnyInvalidCodeErrors) { TestState.CreateAccount(TestItem.AddressC, 100.Ether()); byte[] salt = { 4, 5, 6 }; byte[] byteCode = Prepare.EvmCode .FromCode(code) .Done; byte[] createContract; switch (context) { case ContractDeployment.CREATE: createContract = Prepare.EvmCode.Create(byteCode, UInt256.Zero).Done; break; case ContractDeployment.CREATE2: createContract = Prepare.EvmCode.Create2(byteCode, salt, UInt256.Zero).Done; break; default: createContract = byteCode; break; } _processor = new TransactionProcessor(SpecProvider, TestState, Storage, Machine, LimboLogs.Instance); long blockNumber = eip3541Enabled ? LondonTestBlockNumber : LondonTestBlockNumber - 1; (Block block, Transaction transaction) = PrepareTx(blockNumber, 100000, createContract); transaction.GasPrice = 20.GWei(); transaction.To = null; transaction.Data = createContract; TestAllTracerWithOutput tracer = CreateTracer(); _processor.Execute(transaction, block.Header, tracer); Assert.AreEqual(withoutAnyInvalidCodeErrors, tracer.ReportedActionErrors.All(x => x != EvmExceptionType.InvalidCode), $"Code {code}, Context {context}"); }
protected (Block block, Transaction transaction) PrepareTx(long blockNumber, long gasLimit, byte[] code, SenderRecipientAndMiner senderRecipientAndMiner = null) { senderRecipientAndMiner ??= SenderRecipientAndMiner.Default; TestState.CreateAccount(senderRecipientAndMiner.Sender, 100.Ether()); TestState.CreateAccount(senderRecipientAndMiner.Recipient, 100.Ether()); Keccak codeHash = TestState.UpdateCode(code); TestState.UpdateCodeHash(senderRecipientAndMiner.Recipient, codeHash, SpecProvider.GenesisSpec); TestState.Commit(SpecProvider.GenesisSpec); TestState.CommitTree(); Transaction transaction = Build.A.Transaction .WithGasLimit(gasLimit) .WithGasPrice(1) .To(senderRecipientAndMiner.Recipient) .SignedAndResolved(_ethereumEcdsa, senderRecipientAndMiner.SenderKey) .TestObject; Block block = BuildBlock(blockNumber, senderRecipientAndMiner, transaction); return(block, transaction); }
private (Block block, Transaction transaction) PrepareTx(long blockNumber, long gasLimit, byte[] code, byte[] input, UInt256 value) { TestState.CreateAccount(Sender, 100.Ether()); TestState.CreateAccount(Recipient, 100.Ether()); Keccak codeHash = TestState.UpdateCode(code); TestState.UpdateCodeHash(TestItem.AddressB, codeHash, SpecProvider.GenesisSpec); TestState.Commit(SpecProvider.GenesisSpec); Transaction transaction = Build.A.Transaction .WithGasLimit(gasLimit) .WithGasPrice(1) .WithData(input) .WithValue(value) .To(TestItem.AddressB) .SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, blockNumber) .TestObject; Block block = BuildBlock(blockNumber); return(block, transaction); }
public void Can_trace_code_changes() { byte[] deployedCode = new byte[3]; byte[] initCode = Prepare.EvmCode .ForInitOf(deployedCode) .Done; byte[] createCode = Prepare.EvmCode .PersistData("0x1", HexZero) // just to test if storage is restored .Create(initCode, 0) .Op(Instruction.STOP) .Done; TestState.CreateAccount(TestObject.AddressC, 1.Ether()); Keccak createCodeHash = TestState.UpdateCode(createCode); TestState.UpdateCodeHash(TestObject.AddressC, createCodeHash, Spec); byte[] code = Prepare.EvmCode .PersistData("0x2", SampleHexData1) .PersistData("0x3", SampleHexData2) .Call(TestObject.AddressC, 70000) .Op(Instruction.STOP) .Done; (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); Assert.AreEqual(5, trace.StateChanges.Count, "state changes count"); Assert.True(trace.StateChanges.ContainsKey(TestObject.AddressC), "call target"); Assert.True(trace.StateChanges.ContainsKey(Sender), "sender"); Assert.True(trace.StateChanges.ContainsKey(Recipient), "recipient"); Assert.True(trace.StateChanges.ContainsKey(Miner), "miner"); Assert.AreEqual(Bytes.Empty, trace.StateChanges[Contract].Code.Before, "code before"); Assert.AreEqual(deployedCode, trace.StateChanges[Contract].Code.After, "code after"); }
public void Should_allow_external_storage_access_only_with_whitelisted_paymaster(bool paymasterValidation, bool whitelisted, Instruction opcodeToTest, bool shouldSucceed) { Address externalContractAddress = TestItem.GetRandomAddress(); Address paymasterContractAddress = TestItem.GetRandomAddress(); // simple storage access contract byte[] externalContractCalledByPaymasterCode = Prepare.EvmCode .PushData(69) .PushData(1) .Op(opcodeToTest) .Done; TestState.CreateAccount(externalContractAddress, 1.Ether()); Keccak externalContractDeployedCodeHash = TestState.UpdateCode(externalContractCalledByPaymasterCode); TestState.UpdateCodeHash(externalContractAddress, externalContractDeployedCodeHash, Spec); byte[] paymasterCode = Prepare.EvmCode .Call(externalContractAddress, 70000) .Done; TestState.CreateAccount(paymasterContractAddress, 1.Ether()); Keccak paymasterDeployedCodeHash = TestState.UpdateCode(paymasterCode); TestState.UpdateCodeHash(paymasterContractAddress, paymasterDeployedCodeHash, Spec); byte[] code = Prepare.EvmCode .Op(paymasterValidation ? Instruction.NUMBER : Instruction.BASEFEE) // switch to paymaster validation with NUMBER .Call(paymasterContractAddress, 100000) .Op(Instruction.STOP) .Done; (UserOperationTxTracer tracer, _, _) = ExecuteAndTraceAccessCall(SenderRecipientAndMiner.Default, code, whitelisted); tracer.Success.Should().Be(shouldSucceed); }
public void Destroy_restore_store_different_cells_previously_existing() { byte[] baseInitCodeStore = Prepare.EvmCode .PushData(2) .Op(Instruction.CALLVALUE) .Op(Instruction.SSTORE).Done; byte[] contractCode = Prepare.EvmCode .PushData(1) .Op(Instruction.SLOAD) .PushData(1) .Op(Instruction.EQ) .PushData(17) .Op(Instruction.JUMPI) .PushData(1) .PushData(1) .Op(Instruction.SSTORE) .PushData(21) .Op(Instruction.JUMP) .Op(Instruction.JUMPDEST) .PushData(0) .Op(Instruction.SELFDESTRUCT) .Op(Instruction.JUMPDEST) .Done; byte[] baseInitCodeAfterStore = Prepare.EvmCode .ForInitOf(contractCode) .Done; byte[] baseInitCode = Bytes.Concat(baseInitCodeStore, baseInitCodeAfterStore); byte[] create2Code = Prepare.EvmCode .ForCreate2Of(baseInitCode) .Done; byte[] initOfCreate2Code = Prepare.EvmCode .ForInitOf(create2Code) .Done; Address deployingContractAddress = ContractAddress.From(TestItem.PrivateKeyA.Address, 0); Address deploymentAddress = ContractAddress.From(deployingContractAddress, new byte[32], baseInitCode); byte[] deploy = Prepare.EvmCode .CallWithValue(deployingContractAddress, 100000) .Op(Instruction.STOP).Done; byte[] byteCode1 = Prepare.EvmCode .CallWithValue(deploymentAddress, 100000) .Op(Instruction.STOP).Done; byte[] byteCode2 = Prepare.EvmCode .CallWithValue(deploymentAddress, 100000) .Op(Instruction.STOP).Done; TestState.CreateAccount(TestItem.PrivateKeyA.Address, 100.Ether()); //TestState.Commit(SpecProvider.GenesisSpec); //TestState.CommitTree(0); TestState.CreateAccount(deploymentAddress, UInt256.One); Keccak codeHash = TestState.UpdateCode(contractCode); TestState.UpdateCodeHash(deploymentAddress, codeHash, MuirGlacier.Instance); Storage.Set(new StorageCell(deploymentAddress, 7), new byte[] { 7 }); Storage.Commit(); Storage.CommitTrees(0); TestState.Commit(MuirGlacier.Instance); TestState.CommitTree(0); long gasLimit = 1000000; EthereumEcdsa ecdsa = new(1, LimboLogs.Instance); // deploy create 2 Transaction tx0 = Build.A.Transaction.WithCode(initOfCreate2Code).WithGasLimit(gasLimit).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // call contract once Transaction tx1 = Build.A.Transaction.WithCode(byteCode1).WithGasLimit(gasLimit).WithNonce(1).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // self destruct contract Transaction tx2 = Build.A.Transaction.WithCode(byteCode2).WithGasLimit(gasLimit).WithNonce(2).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // deploy again using create2 Transaction tx3 = Build.A.Transaction.WithValue(3).WithCode(deploy).WithGasLimit(gasLimit).WithNonce(3).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // call newly deployed once Transaction tx4 = Build.A.Transaction.WithCode(byteCode1).WithGasLimit(gasLimit).WithNonce(4).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx0, tx1, tx2, tx3, tx4).WithGasLimit(2 * gasLimit).TestObject; ParityLikeTxTracer tracer = new(block, tx0, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx0, block.Header, tracer); tracer = new ParityLikeTxTracer(block, tx1, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx1, block.Header, tracer); // AssertStorage(new StorageCell(deploymentAddress, 7), 7); tracer = new ParityLikeTxTracer(block, tx2, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx2, block.Header, tracer); // AssertStorage(new StorageCell(deploymentAddress, 7), 0); tracer = new ParityLikeTxTracer(block, tx3, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx3, block.Header, tracer); AssertStorage(new StorageCell(deploymentAddress, 7), 0); tracer = new ParityLikeTxTracer(block, tx4, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx4, block.Header, tracer); AssertStorage(new StorageCell(deploymentAddress, 7), 0); }
public void tstore_from_nonstatic_reentrant_call_with_static_intermediary(Instruction callType, int expectedResult) { // If caller is self, TLOAD and return value (break recursion) // Else, TSTORE and call self, return the response byte[] contractCode = Prepare.EvmCode // Check call depth .PushData(0) .Op(Instruction.CALLDATALOAD) // Store input in mem and reload it to stack .DataOnStackToMemory(5) .PushData(5) .Op(Instruction.MLOAD) // See if we're at call depth 1 .PushData(1) .Op(Instruction.EQ) .PushData(84) .Op(Instruction.JUMPI) // See if we're at call depth 2 .PushData(5) .Op(Instruction.MLOAD) .PushData(2) .Op(Instruction.EQ) .PushData(140) .Op(Instruction.JUMPI) // Call depth = 0, call self after TSTORE 8 .StoreDataInTransientStorage(1, 8) // Recursive call with input // Depth++ .PushData(5) .Op(Instruction.MLOAD) .PushData(1) .Op(Instruction.ADD) .DynamicCallWithInput(callType, TestItem.AddressD, 50000) // TLOAD and return value .LoadDataFromTransientStorage(1) .DataOnStackToMemory(0) .PushData(32) .PushData(0) .Op(Instruction.RETURN) // Call depth 1, TSTORE 9 but REVERT after recursion .Op(Instruction.JUMPDEST) // PC = 84 // Recursive call with input // Depth++ .PushData(5) .Op(Instruction.MLOAD) .PushData(1) .Op(Instruction.ADD) .CallWithInput(TestItem.AddressD, 50000) // TLOAD and return value .LoadDataFromTransientStorage(1) .DataOnStackToMemory(0) .PushData(32) .PushData(0) .Op(Instruction.RETURN) // Call depth 2, TSTORE 10 and complete .Op(Instruction.JUMPDEST) // PC = 140 .StoreDataInTransientStorage(1, 10) // This will fail .Done; TestState.CreateAccount(TestItem.AddressD, 1.Ether()); Keccak contractCodeHash = TestState.UpdateCode(contractCode); TestState.UpdateCodeHash(TestItem.AddressD, contractCodeHash, Spec); // Return the result received from the contract byte[] code = Prepare.EvmCode .CallWithInput(TestItem.AddressD, 50000, new byte[32]) .ReturnInnerCallResult() .Done; TestAllTracerWithOutput result = Execute(MainnetSpecProvider.ShanghaiBlockNumber, 100000, code); // Should be original TSTORE value Assert.AreEqual(expectedResult, (int)result.ReturnValue.ToUInt256()); }
public void Destroy_restore_store() { TestState.CreateAccount(TestItem.PrivateKeyA.Address, 100.Ether()); TestState.Commit(SpecProvider.GenesisSpec); TestState.CommitTree(); byte[] baseInitCodeStore = Prepare.EvmCode .PushData(2) .PushData(2) .Op(Instruction.SSTORE).Done; byte[] baseInitCodeAfterStore = Prepare.EvmCode .ForInitOf( Prepare.EvmCode .PushData(1) .Op(Instruction.SLOAD) .PushData(1) .Op(Instruction.EQ) .PushData(17) .Op(Instruction.JUMPI) .PushData(1) .PushData(1) .Op(Instruction.SSTORE) .PushData(21) .Op(Instruction.JUMP) .Op(Instruction.JUMPDEST) .PushData(0) .Op(Instruction.SELFDESTRUCT) .Op(Instruction.JUMPDEST) .Done) .Done; byte[] baseInitCode = Bytes.Concat(baseInitCodeStore, baseInitCodeAfterStore); byte[] create2Code = Prepare.EvmCode .ForCreate2Of(baseInitCode) .Done; byte[] initOfCreate2Code = Prepare.EvmCode .ForInitOf(create2Code) .Done; Address deployingContractAddress = ContractAddress.From(TestItem.PrivateKeyA.Address, 0); Address deploymentAddress = ContractAddress.From(deployingContractAddress, new byte[32], baseInitCode); byte[] deploy = Prepare.EvmCode .Call(deployingContractAddress, 100000) .Op(Instruction.STOP).Done; byte[] byteCode1 = Prepare.EvmCode .Call(deploymentAddress, 100000) .Op(Instruction.STOP).Done; byte[] byteCode2 = Prepare.EvmCode .Call(deploymentAddress, 100000) .Op(Instruction.STOP).Done; long gasLimit = 1000000; EthereumEcdsa ecdsa = new EthereumEcdsa(1, LimboLogs.Instance); // deploy create 2 Transaction tx0 = Build.A.Transaction.WithInit(initOfCreate2Code).WithGasLimit(gasLimit).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // invoke create 2 to deploy contract Transaction tx1 = Build.A.Transaction.WithInit(deploy).WithGasLimit(gasLimit).WithNonce(1).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // call contract once Transaction tx2 = Build.A.Transaction.WithInit(byteCode1).WithGasLimit(gasLimit).WithNonce(2).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // self destruct contract Transaction tx3 = Build.A.Transaction.WithInit(byteCode2).WithGasLimit(gasLimit).WithNonce(3).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // deploy again using create2 Transaction tx4 = Build.A.Transaction.WithInit(deploy).WithGasLimit(gasLimit).WithNonce(4).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // call newly deployed once Transaction tx5 = Build.A.Transaction.WithInit(byteCode1).WithGasLimit(gasLimit).WithNonce(5).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx0, tx1, tx2, tx3, tx4, tx5).WithGasLimit(2 * gasLimit).TestObject; ParityLikeTxTracer tracer0 = new ParityLikeTxTracer(block, tx0, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx0, block.Header, tracer0); // AssertStorage(new StorageCell(deploymentAddress, 1), 0); ParityLikeTxTracer tracer = new ParityLikeTxTracer(block, tx1, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx1, block.Header, tracer); // AssertStorage(new StorageCell(deploymentAddress, 1), 0); // AssertStorage(new StorageCell(deploymentAddress, 2), 2); tracer = new ParityLikeTxTracer(block, tx2, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx2, block.Header, tracer); // AssertStorage(new StorageCell(deploymentAddress, 1), 1); // AssertStorage(new StorageCell(deploymentAddress, 2), 2); tracer = new ParityLikeTxTracer(block, tx3, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx3, block.Header, tracer); // AssertStorage(new StorageCell(deploymentAddress, 1), 0); // AssertStorage(new StorageCell(deploymentAddress, 2), 0); tracer = new ParityLikeTxTracer(block, tx4, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx4, block.Header, tracer); // AssertStorage(new StorageCell(deploymentAddress, 1), 0); // AssertStorage(new StorageCell(deploymentAddress, 2), 2); tracer = new ParityLikeTxTracer(block, tx5, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx5, block.Header, tracer); AssertStorage(new StorageCell(deploymentAddress, 1), 1); AssertStorage(new StorageCell(deploymentAddress, 2), 2); }
public void After_3529_self_destruct_has_zero_refund(bool eip3529Enabled) { TestState.CreateAccount(TestItem.PrivateKeyA.Address, 100.Ether()); TestState.Commit(SpecProvider.GenesisSpec); TestState.CommitTree(0); byte[] baseInitCodeStore = Prepare.EvmCode .PushData(2) .PushData(2) .Op(Instruction.SSTORE).Done; byte[] baseInitCodeAfterStore = Prepare.EvmCode .ForInitOf( Prepare.EvmCode .PushData(1) .Op(Instruction.SLOAD) .PushData(1) .Op(Instruction.EQ) .PushData(17) .Op(Instruction.JUMPI) .PushData(1) .PushData(1) .Op(Instruction.SSTORE) .PushData(21) .Op(Instruction.JUMP) .Op(Instruction.JUMPDEST) .PushData(0) .Op(Instruction.SELFDESTRUCT) .Op(Instruction.JUMPDEST) .Done) .Done; byte[] baseInitCode = Bytes.Concat(baseInitCodeStore, baseInitCodeAfterStore); byte[] create2Code = Prepare.EvmCode .ForCreate2Of(baseInitCode) .Done; byte[] initOfCreate2Code = Prepare.EvmCode .ForInitOf(create2Code) .Done; Address deployingContractAddress = ContractAddress.From(TestItem.PrivateKeyA.Address, 0); Address deploymentAddress = ContractAddress.From(deployingContractAddress, new byte[32], baseInitCode); byte[] deploy = Prepare.EvmCode .Call(deployingContractAddress, 100000) .Op(Instruction.STOP).Done; byte[] byteCode1 = Prepare.EvmCode .Call(deploymentAddress, 100000) .Op(Instruction.STOP).Done; byte[] byteCode2 = Prepare.EvmCode .Call(deploymentAddress, 100000) .Op(Instruction.STOP).Done; long gasLimit = 1000000; EthereumEcdsa ecdsa = new(1, LimboLogs.Instance); // deploy create 2 Transaction tx0 = Build.A.Transaction.WithCode(initOfCreate2Code).WithGasLimit(gasLimit).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // invoke create 2 to deploy contract Transaction tx1 = Build.A.Transaction.WithCode(deploy).WithGasLimit(gasLimit).WithNonce(1).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // call contract once Transaction tx2 = Build.A.Transaction.WithCode(byteCode1).WithGasLimit(gasLimit).WithNonce(2).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; // self destruct contract Transaction tx3 = Build.A.Transaction.WithCode(byteCode2).WithGasLimit(gasLimit).WithNonce(3).SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; int gasUsedByTx3 = 37767; long blockNumber = eip3529Enabled ? LondonTestBlockNumber : LondonTestBlockNumber - 1; Block block = Build.A.Block.WithNumber(blockNumber).WithTransactions(tx0, tx1, tx2, tx3).WithGasLimit(2 * gasLimit).TestObject; ParityLikeTxTracer tracer0 = new(block, tx0, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); _processor.Execute(tx0, block.Header, tracer0); TestAllTracerWithOutput tracer = CreateTracer(); _processor.Execute(tx1, block.Header, tracer); tracer = CreateTracer(); _processor.Execute(tx2, block.Header, tracer); tracer = CreateTracer(); _processor.Execute(tx3, block.Header, tracer); long expectedRefund = eip3529Enabled ? 0 : 24000; Assert.AreEqual(expectedRefund, tracer.Refund); AssertGas(tracer, gasUsedByTx3 + GasCostOf.Transaction - Math.Min((gasUsedByTx3 + GasCostOf.Transaction) / (eip3529Enabled ? RefundHelper.MaxRefundQuotientEIP3529 : RefundHelper.MaxRefundQuotient), expectedRefund)); }