Esempio n. 1
0
        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");
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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");
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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");
        }
Esempio n. 7
0
        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);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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");
        }
Esempio n. 11
0
        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);
        }
Esempio n. 12
0
        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);
        }
Esempio n. 13
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());
        }
Esempio n. 14
0
        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);
        }
Esempio n. 15
0
        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));
        }