public static OpcodeDescriptorAttribute GetDescriptor(this InstructionOpcode opcode) { // Check our cache for our descriptor. if (_cachedDescriptors.TryGetValue(opcode, out var val)) { return(val); } // Cache miss, obtain our enum option's field info FieldInfo fi = opcode.GetType().GetField(opcode.ToString()); if (fi == null) { return(null); } // Obtain all attributes of type we are interested in. var attributes = fi.GetCustomAttributes <OpcodeDescriptorAttribute>(false).ToArray(); // If one exists, cache it and return it. if (attributes != null && attributes.Length > 0) { _cachedDescriptors[opcode] = attributes[0]; return(attributes[0]); } return(null); }
public static string GetIntelInstructionOpcode(this InstructionOpcode type) { const string result = "none"; switch (type) { case InstructionOpcode.None: break; case InstructionOpcode.Add: return("add"); case InstructionOpcode.Subtract: return("sub"); case InstructionOpcode.Multiply: return("imul"); case InstructionOpcode.Divide: return("idiv"); default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } return(result); }
public static string GetArguments(InstructionOpcode opcode) { var index = (byte)opcode; if (index >= Arguments.Count) { throw new ArgumentOutOfRangeException(nameof(opcode), $"Out-of-range: {opcode} with index {index}"); } return(Arguments[index]); }
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(); }
/// <summary> /// Obtains the base gas cost of executing the given opcode on the given Ethereum release version. /// </summary> /// <param name="currentVersion">The release of Ethereum to assume when obtaining the base gas cost for the given opcode.</param> /// <param name="opcode">The opcode to obtain the base gas cost for.</param> /// <returns>Returns the base gas cost for the given instruction on the given Ethereum release.</returns> public static uint?GetInstructionBaseGasCost(EthereumRelease currentVersion, InstructionOpcode opcode) { // Obtain the cost for this version. It is null if it does not exist yet, or was never declared. uint cost = 0; if (_baseGasLookup[currentVersion].TryGetValue(opcode, out cost)) { return(cost); } else { return(null); } }
public static OpcodeBaseGasCostAttribute[] GetBaseGasCosts(this InstructionOpcode opcode) { // Cache miss, obtain our enum option's field info FieldInfo fi = opcode.GetType().GetField(opcode.ToString()); if (fi == null) { return(null); } // Obtain all attributes of type we are interested in. var attributes = fi.GetCustomAttributes <OpcodeBaseGasCostAttribute>(false).ToArray(); return(attributes); }
public CpuContext( uint instructionAddress, uint programCounter, InstructionOpcode opcode, uint operands, bool error, CpuErrorCode errorCode) { InstructionAddress = instructionAddress; ProgramCounter = programCounter; Opcode = opcode; Operands = operands; Error = error; ErrorCode = errorCode; }
public Instruction(InstructionOpcode opcode, string parameter = null) { Opcode = opcode; Parameter = parameter; }