Exemple #1
0
        /// <summary>
        /// Execute the next instruction only.
        /// </summary>
        /// <returns>Returns false if execution ended, and true otherwise.</returns>
        public async Task <bool> executeOnce()
        {
            fetchInstruction();
            switch (m_op)
            {
            //
            // Call-related instructions
            //
            case (Instruction.CREATE2):
            case (Instruction.CREATE):
            case (Instruction.DELEGATECALL):
            case (Instruction.STATICCALL):
            case (Instruction.CALL):
            case (Instruction.CALLCODE):
                // Calling external contracts not supported yet (fixing this is not too hard though. PR welcomed)
                throw new EVMInstructionNotYetSupported();

            case (Instruction.RETURN):
            // Reverting state is not handled but only indicated by a flag
            case (Instruction.REVERT):
                updateMem(memNeed(m_stack[0], m_stack[1]));
                // A hopefully it ain't trying to return more than 0x0fffffff bytes of data lol
                m_return = new byte[m_stack[1].ToUInt32()];
                m_memory.CopyTo((int)m_stack[0].ToUInt32(), m_return, 0, m_return.Length);
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                m_flagReverted = m_op == Instruction.REVERT;
                return(false);

            case (Instruction.SUICIDE):
                //Suicide not handled either
                m_stack.RemoveAt(0);
                m_flagSuicided = true;
                return(false);

            case (Instruction.STOP):
                return(false);

            //
            // instructions potentially expanding memory
            //

            case (Instruction.MLOAD):
                updateMem(m_stack[0] + 32);
                byte[] bytesMloaded = new byte[32];
                m_memory.CopyTo((int)m_stack[0].ToUInt32(), bytesMloaded, 0, 32);
                m_stack[0] = new uint256(bytesMloaded);
                m_pc++;
                break;

            case (Instruction.MSTORE):
                updateMem(m_stack[0] + 32);
                int mstoreStartIndex = (int)m_stack[0].ToUInt32();
                for (int i = 0; i < 32; i++)
                {
                    m_memory[mstoreStartIndex + i] = m_stack[1].bytes[i];
                }
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.MSTORE8):
                updateMem(m_stack[0] + 1);
                m_memory[(int)m_stack[0].ToUInt32()] = m_stack[1].bytes[31];
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.SHA3):
                updateMem(memNeed(m_stack[0], m_stack[1]));
                int    sha3Offset = (int)m_stack[0].ToUInt32();
                int    sha3Size   = (int)m_stack[1].ToUInt32();
                byte[] sha3Input  = new byte[sha3Size];
                m_memory.CopyTo(sha3Offset, sha3Input, 0, sha3Size);
                m_stack.RemoveAt(0);
                m_stack[0] = new uint256(keccak.ComputeHash(sha3Input));
                m_pc++;
                break;

            case (Instruction.LOG0):
            case (Instruction.LOG1):
            case (Instruction.LOG2):
            case (Instruction.LOG3):
            case (Instruction.LOG4):
                updateMem(memNeed(m_stack[0], m_stack[1]));
                List <uint256> listOfTopics = new List <uint256>();
                int            noOfTopics   = (int)m_op - (int)Instruction.LOG0;
                int            logOffset    = (int)m_stack[0].ToUInt32();
                int            logSize      = (int)m_stack[1].ToUInt32();
                byte[]         logData      = new byte[logSize];
                m_memory.CopyTo(logOffset, logData, 0, logSize);
                for (int i = 0; i < noOfTopics; i++)
                {
                    listOfTopics.Add(m_stack[i + 2]);
                }
                m_log.Add(new EVMLog()
                {
                    topics = listOfTopics,
                    data   = logData
                });
                for (int i = 0; i < noOfTopics + 2; i++)
                {
                    m_stack.RemoveAt(0);
                }
                m_pc++;
                break;

            case (Instruction.EXP):
                m_stack[1] = m_stack[0].exp(m_stack[1]);
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            //
            // ordinary instructions
            //

            case (Instruction.ADD):
                m_stack[1] = m_stack[0] + m_stack[1];
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.MUL):
                m_stack[1] = m_stack[0] * m_stack[1];
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.SUB):
                m_stack[1] = m_stack[0] - m_stack[1];
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.DIV):
                if (m_stack[1] != 0)
                {
                    m_stack[1] = m_stack[0] / m_stack[1];
                }
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.SDIV):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.MOD):
                if (m_stack[1] != 0)
                {
                    m_stack[1] = m_stack[0] % m_stack[1];
                }
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.SMOD):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.NOT):
                m_stack[0] = !m_stack[0];
                m_pc++;
                break;

            case (Instruction.LT):
                m_stack[1] = m_stack[0] < m_stack[1] ? 1 : 0;
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.GT):
                m_stack[1] = m_stack[0] > m_stack[1] ? 1 : 0;
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.SLT):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.SGT):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.EQ):
                m_stack[1] = m_stack[0] == m_stack[1] ? 1 : 0;
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.ISZERO):
                m_stack[0] = m_stack[0] == 0 ? 1 : 0;
                m_pc++;
                break;

            case (Instruction.AND):
                m_stack[1] = m_stack[0] & m_stack[1];
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.OR):
                m_stack[1] = m_stack[0] | m_stack[1];
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.XOR):
                m_stack[1] = m_stack[0] ^ m_stack[1];
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.BYTE):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.ADDMOD):
                if (m_stack[2] != 0)
                {
                    m_stack[2] = (m_stack[0] + m_stack[1]) % m_stack[2];
                }
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.MULMOD):
                if (m_stack[2] != 0)
                {
                    m_stack[2] = (m_stack[0] * m_stack[1]) % m_stack[2];
                }
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.SIGNEXTEND):
                throw new EVMInstructionNotYetSupported();

            // EIP 615 NOT supported
            case (Instruction.JUMPTO):
            case (Instruction.JUMPIF):
            case (Instruction.JUMPV):
            case (Instruction.JUMPSUB):
            case (Instruction.JUMPSUBV):
            case (Instruction.RETURNSUB):
            case (Instruction.BEGINSUB):
            case (Instruction.BEGINDATA):
            case (Instruction.GETLOCAL):
            case (Instruction.PUTLOCAL):
                throw new EVMEIPNotYetSupported();

            // EIP 616 NOT supported
            case (Instruction.XADD):
            case (Instruction.XMUL):
            case (Instruction.XSUB):
            case (Instruction.XDIV):
            case (Instruction.XSDIV):
            case (Instruction.XMOD):
            case (Instruction.XSMOD):
            case (Instruction.XLT):
            case (Instruction.XGT):
            case (Instruction.XSLT):
            case (Instruction.XSGT):
            case (Instruction.XEQ):
            case (Instruction.XISZERO):
            case (Instruction.XAND):
            case (Instruction.XOOR):
            case (Instruction.XXOR):
            case (Instruction.XNOT):
            case (Instruction.XSHL):
            case (Instruction.XSHR):
            case (Instruction.XSAR):
            case (Instruction.XROL):
            case (Instruction.XROR):
            case (Instruction.XMLOAD):
            case (Instruction.XMSTORE):
            case (Instruction.XSLOAD):
            case (Instruction.XSSTORE):
            case (Instruction.XVTOWIDE):
            case (Instruction.XWIDETOV):
            case (Instruction.XPUSH):
            case (Instruction.XPUT):
            case (Instruction.XGET):
            case (Instruction.XSWIZZLE):
            case (Instruction.XSHUFFLE):
                throw new EVMEIPNotYetSupported();

            // 00000000
            case (Instruction.ADDRESS):
                m_stack.Insert(0, transaction.to);
                m_pc++;
                break;

            case (Instruction.ORIGIN):
                // TODO: REMEMBER TO MODIFY THIS AFTER CALLING IS SUPPORTED
                // OR IT WILL BECOME A VERY HARD TO FIND BUG
                m_stack.Insert(0, transaction.sender);
                m_pc++;
                break;

            case (Instruction.BALANCE):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.CALLER):
                m_stack.Insert(0, transaction.sender);
                m_pc++;
                break;

            case (Instruction.CALLVALUE):
                m_stack.Insert(0, transaction.value);
                m_pc++;
                break;

            case (Instruction.CALLDATALOAD):
                byte[] cdloadBytes  = new byte[32];
                int    cdloadOffset = (int)m_stack[0].ToUInt32();
                for (int i = 0; i < 32; i++)
                {
                    cdloadBytes[i] = cdloadOffset + i < transaction.data.Length ? transaction.data[cdloadOffset + i] : (byte)0;
                }
                m_stack[0] = new uint256(cdloadBytes);
                m_pc++;
                break;

            case (Instruction.CALLDATASIZE):
                m_stack.Insert(0, transaction.data.Length);
                m_pc++;
                break;

            case (Instruction.RETURNDATASIZE):
            case (Instruction.CODESIZE):
            case (Instruction.EXTCODESIZE):
            case (Instruction.CALLDATACOPY):
            case (Instruction.RETURNDATACOPY):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.CODECOPY):
                updateMem(memNeed(m_stack[0], m_stack[1]));
                copyDataToMemory(byteCode, m_stack[0], m_stack[1], m_stack[2]);
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.EXTCODECOPY):
            case (Instruction.GASPRICE):
            case (Instruction.BLOCKHASH):
            case (Instruction.COINBASE):
            case (Instruction.TIMESTAMP):
            case (Instruction.NUMBER):
            case (Instruction.DIFFICULTY):
            case (Instruction.GASLIMIT):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.POP):
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.PUSHC):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.PUSH1):
                m_pc++;
                m_stack.Insert(0, new uint256(new byte[] { byteCode[m_pc] }));
                m_pc++;
                break;

            case (Instruction.PUSH2):
            case (Instruction.PUSH3):
            case (Instruction.PUSH4):
            case (Instruction.PUSH5):
            case (Instruction.PUSH6):
            case (Instruction.PUSH7):
            case (Instruction.PUSH8):
            case (Instruction.PUSH9):
            case (Instruction.PUSH10):
            case (Instruction.PUSH11):
            case (Instruction.PUSH12):
            case (Instruction.PUSH13):
            case (Instruction.PUSH14):
            case (Instruction.PUSH15):
            case (Instruction.PUSH16):
            case (Instruction.PUSH17):
            case (Instruction.PUSH18):
            case (Instruction.PUSH19):
            case (Instruction.PUSH20):
            case (Instruction.PUSH21):
            case (Instruction.PUSH22):
            case (Instruction.PUSH23):
            case (Instruction.PUSH24):
            case (Instruction.PUSH25):
            case (Instruction.PUSH26):
            case (Instruction.PUSH27):
            case (Instruction.PUSH28):
            case (Instruction.PUSH29):
            case (Instruction.PUSH30):
            case (Instruction.PUSH31):
            case (Instruction.PUSH32):
                m_pc++;
                int    pushLength = m_op - Instruction.PUSH1 + 1;
                byte[] pushBytes  = new byte[pushLength];
                Array.Copy(m_byteCode, m_pc, pushBytes, 0, pushLength);
                m_stack.Insert(0, new uint256(pushBytes));
                m_pc += pushLength;
                break;

            case (Instruction.JUMP):
                if (m_byteCode[(int)m_stack[0].ToUInt32()] != (int)Instruction.JUMPDEST)
                {
                    throw new EVMNotJumpDestException();
                }
                m_pc = (int)m_stack[0].ToUInt32();
                m_stack.RemoveAt(0);
                break;

            case (Instruction.JUMPI):
                if (m_stack[1] != 0)
                {
                    if (m_byteCode[(int)m_stack[0].ToUInt32()] != (int)Instruction.JUMPDEST)
                    {
                        throw new EVMNotJumpDestException();
                    }
                    m_pc = (int)m_stack[0].ToUInt32();
                }
                else
                {
                    m_pc++;
                }
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                break;

            case (Instruction.JUMPC):
                m_pc = (int)m_stack[0].ToUInt32();
                m_stack.RemoveAt(0);
                break;

            case (Instruction.JUMPCI):
                if (m_stack[1] == 0)
                {
                    m_pc = (int)m_stack[0].ToUInt32();
                }
                else
                {
                    m_pc++;
                }
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                break;

            case (Instruction.DUP1):
            case (Instruction.DUP2):
            case (Instruction.DUP3):
            case (Instruction.DUP4):
            case (Instruction.DUP5):
            case (Instruction.DUP6):
            case (Instruction.DUP7):
            case (Instruction.DUP8):
            case (Instruction.DUP9):
            case (Instruction.DUP10):
            case (Instruction.DUP11):
            case (Instruction.DUP12):
            case (Instruction.DUP13):
            case (Instruction.DUP14):
            case (Instruction.DUP15):
            case (Instruction.DUP16):
                int dupN = (int)m_op - (int)Instruction.DUP1;
                m_stack.Insert(0, m_stack[dupN]);
                m_pc++;
                break;

            case (Instruction.SWAP1):
            case (Instruction.SWAP2):
            case (Instruction.SWAP3):
            case (Instruction.SWAP4):
            case (Instruction.SWAP5):
            case (Instruction.SWAP6):
            case (Instruction.SWAP7):
            case (Instruction.SWAP8):
            case (Instruction.SWAP9):
            case (Instruction.SWAP10):
            case (Instruction.SWAP11):
            case (Instruction.SWAP12):
            case (Instruction.SWAP13):
            case (Instruction.SWAP14):
            case (Instruction.SWAP15):
            case (Instruction.SWAP16):
                int     swapN    = (int)m_op - (int)Instruction.SWAP1 + 1;
                uint256 swapTemp = m_stack[0];
                m_stack[0]     = m_stack[swapN];
                m_stack[swapN] = swapTemp;
                m_pc++;
                break;

            case (Instruction.SLOAD):
                // If storage already exists (even with value 0x0), take that.
                // Other wise, find storage data online with DataGateway.
                // Take the storage data at the PREVIOUS block height
                if (!m_storage.ContainsKey(m_stack[0]))
                {
                    m_storage.Add(m_stack[0], await edg.getStorageAt(transaction.to, m_stack[0], (int)(ext.blockheight - 1).ToUInt32()));
                }
                m_stack[0] = m_storage[m_stack[0]];
                m_pc++;
                break;

            case (Instruction.SSTORE):
                if (!m_storage.ContainsKey(m_stack[0]))
                {
                    m_storage.Add(m_stack[0], m_stack[1]);
                }
                else
                {
                    m_storage[m_stack[0]] = m_stack[1];
                }
                m_stack.RemoveAt(0);
                m_stack.RemoveAt(0);
                m_pc++;
                break;

            case (Instruction.PC):
                m_stack.Insert(0, m_pc);
                m_pc++;
                break;

            case (Instruction.MSIZE):
                m_stack.Insert(0, m_memory.Count);
                m_pc++;
                break;

            case (Instruction.GAS):
                throw new EVMInstructionNotYetSupported();

            case (Instruction.JUMPDEST):
                m_pc++;
                break;

            case (Instruction.INVALID):
            default:
                throw new EVMInstructionNotYetSupported();
            }
            return(true);
        }