Esempio n. 1
0
        private void Step()
        {
            // Verify we're not at the end of the stream
            if (ExecutionState.PC >= Code.Length)
            {
                // If we reached the end, exit with the remainder of the gas and a success status.
                ExecutionState.Result = new EVMExecutionResult(this, null, true);
                return;
            }

            // Set our position back to the start of the instruction, grab our opcode and verify it.
            InstructionOpcode opcode = (InstructionOpcode)Code.Span[(int)ExecutionState.PC];

            // Obtain our base cost for this opcode. If we fail to, the instruction isn't implemented yet.
            uint?instructionBaseGasCost = GasDefinitions.GetInstructionBaseGasCost(State.Configuration.Version, opcode);

            if (instructionBaseGasCost == null)
            {
                throw new EVMException($"Invalid opcode {opcode.ToString()} read when executing!");
            }

            // If we just jumped, then this next opcode should be a JUMPDEST.
            if (ExecutionState.JumpedLastInstruction && opcode != InstructionOpcode.JUMPDEST)
            {
                throw new EVMException($"Invalid jump to offset {ExecutionState.PC} in code!");
            }

            // Obtain our instruction implementation for this opcode
            var             opcodeDescriptor = opcode.GetDescriptor();
            InstructionBase instruction      = opcodeDescriptor.GetInstructionImplementation(this);

            // Record our code coverage for this execution.
            CoverageMap?.RecordExecution(instruction.Offset, (ExecutionState.PC - instruction.Offset));

            // Record our instruction execution tracing
            if (State.Configuration.DebugConfiguration.IsTracing)
            {
                State.Configuration.DebugConfiguration.ExecutionTrace?.RecordExecution(this, instruction, GasState.Gas, (BigInteger)instructionBaseGasCost);
            }

            // Deduct base gas cost
            GasState.Deduct((BigInteger)instructionBaseGasCost);

            // Debug: Print out instruction execution information.
            //if (opcode == InstructionOpcode.JUMPDEST)
            //    Console.WriteLine($"\r\n---------------------------------------------------------------\r\n");
            //Console.WriteLine($"0x{instruction.Offset.ToString("X4")}: {instruction}");
            //Console.WriteLine($"Stack: {ExecutionState.Stack}");

            // Execute the instruction
            instruction.Execute();
        }
Esempio n. 2
0
        public void TestBaseGasCostUpdates()
        {
            // Make static assertions about updates made during Tangerine Whistle release.
            EthereumRelease[] releases = (EthereumRelease[])Enum.GetValues(typeof(EthereumRelease));
            foreach (EthereumRelease release in releases)
            {
                if (release < EthereumRelease.TangerineWhistle)
                {
                    Assert.Equal <uint>(20, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.BALANCE));
                    Assert.Equal <uint>(20, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.EXTCODESIZE));
                    Assert.Equal <uint>(20, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.EXTCODECOPY));
                    Assert.Equal <uint>(50, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.SLOAD));
                    Assert.Equal <uint>(40, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.CALL));
                    Assert.Equal <uint>(40, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.CALLCODE));

                    // DELEGATE CALL WAS INTRODUCED IN HOMESTEAD WITH 40 BASE GAS, NULL BEFORE.
                    if (release >= EthereumRelease.Homestead)
                    {
                        Assert.Equal <uint>(40, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.DELEGATECALL));
                    }
                    else
                    {
                        Assert.Null(GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.DELEGATECALL));
                    }

                    // STATIC CALL WAS INTRODUCED IN BYZANTIUM WITH 700 BASE GAS, NULL BEFORE
                    if (release >= EthereumRelease.Byzantium)
                    {
                        Assert.Equal <uint>(700, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.STATICCALL));
                    }
                    else
                    {
                        Assert.Null(GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.STATICCALL));
                    }

                    Assert.Equal <uint>(0, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.SELFDESTRUCT));
                }
                else
                {
                    Assert.Equal <uint>(400, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.BALANCE));
                    Assert.Equal <uint>(700, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.EXTCODESIZE));
                    Assert.Equal <uint>(700, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.EXTCODECOPY));
                    Assert.Equal <uint>(200, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.SLOAD));
                    Assert.Equal <uint>(700, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.CALL));
                    Assert.Equal <uint>(700, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.CALLCODE));
                    Assert.Equal <uint>(700, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.DELEGATECALL));
                    Assert.Equal <uint>(5000, (uint)GasDefinitions.GetInstructionBaseGasCost(release, InstructionOpcode.SELFDESTRUCT));
                }
            }
        }