Exemplo n.º 1
0
        public override void Execute()
        {
            // Obtain the memory offset and size
            BigInteger offset = Stack.Pop();
            BigInteger size   = Stack.Pop();

            // Deduct our gas accordingly.
            GasState.Deduct(EVMDefinitions.GetWordCount(size) * GasDefinitions.GAS_SHA3_WORD);

            // Read our data to hash
            byte[] data = Memory.ReadBytes((long)offset, (int)size);

            // Hash our read data.
            byte[] hash = KeccakHash.ComputeHashBytes(data);

            // Log our preimage
            EVM.State.Configuration.DebugConfiguration?.RecordPreimage(hash, data);

            // Push it onto our stack.
            Stack.Push(BigIntegerConverter.GetBigInteger(hash));
        }
Exemplo n.º 2
0
        public override void Execute()
        {
            // Obtain our code address
            Address externalCodeAddress = Stack.Pop();

            // Obtain our code segment
            byte[] codeSegment = EVM.State.GetCodeSegment(externalCodeAddress);

            // Obtain our offsets and sizes for the copy.
            BigInteger memoryOffset = Stack.Pop();
            BigInteger dataOffset   = Stack.Pop();
            BigInteger dataSize     = Stack.Pop();

            // This is considered a copy operation, so we charge for the size of the data.
            GasState.Deduct(GasDefinitions.GetMemoryCopyCost(Version, dataSize));

            // Read our data from the code segment (if our offset is wrong or we hit the end of the array, the rest should be zeroes).
            byte[] data   = new byte[(int)dataSize];
            int    length = data.Length;

            if (dataOffset > codeSegment.Length)
            {
                dataOffset = 0;
                length     = 0;
            }
            else if (dataOffset + length > codeSegment.Length)
            {
                length = codeSegment.Length - (int)dataOffset;
            }

            // Copy to the memory location.
            Array.Copy(codeSegment, (int)dataOffset, data, 0, length);

            // Write the data to our given memory offset.
            Memory.Write((long)memoryOffset, data);
        }
Exemplo n.º 3
0
        public override void Execute()
        {
            // If we're in a static context, we can't self destruct
            if (Message.IsStatic)
            {
                throw new EVMException($"{Opcode.ToString()} instruction cannot execute in a static context!");
            }

            // Obtain our address to
            Address    to = Stack.Pop();
            BigInteger balanceMessageTo = EVM.State.GetBalance(Message.To);
            BigInteger balanceTo        = EVM.State.GetBalance(to);

            // Calculate our extra gas costs for post-Tangerine Whistle.
            if (Version >= EthereumRelease.TangerineWhistle)
            {
                // If we had a balance to send (or are pre-spurious dragon which didn't care), and our account to send the balance to doesn't exist, charge for calling a new account.
                if (!EVM.State.ContainsAccount(to))
                {
                    if (balanceMessageTo > 0 || Version < EthereumRelease.SpuriousDragon)
                    {
                        GasState.Deduct(GasDefinitions.GAS_CALL_NEW_ACCOUNT);
                    }
                }
            }

            // Transfer our balance from our message recipient to
            EVM.State.SetBalance(to, balanceTo + balanceMessageTo);
            EVM.State.SetBalance(Message.To, 0);

            // Log our suicide in our state.
            EVM.State.QueueDeleteAccount(Message.To);

            // We'll want to return with no return data, our remaining gas, and indicating we don't wish to revert changes.
            Return(new EVMExecutionResult(EVM, null, true));
        }
Exemplo n.º 4
0
        public override void Execute()
        {
            // Obtain all of our values for the call (the value variable is only used in some calls, and is zero otherwise)
            BigInteger gas = Stack.Pop(); // The base amount of gas we allocate to the call.
            Address    to  = Stack.Pop(); // The address we're making the call to.

            BigInteger value = 0;

            if (Opcode == InstructionOpcode.CALL || Opcode == InstructionOpcode.CALLCODE)
            {
                value = Stack.Pop();
            }

            // Obtain the values for where our input memory comes from, and where our output memory will go to.
            BigInteger inputMemoryStart  = Stack.Pop();
            BigInteger inputMemorySize   = Stack.Pop();
            BigInteger outputMemoryStart = Stack.Pop();
            BigInteger outputMemorySize  = Stack.Pop();

            // CALL opcode can only make static calls with a zero value.
            if (Opcode == InstructionOpcode.CALL && Message.IsStatic && value != 0)
            {
                throw new EVMException($"Cannot use opcode {Opcode.ToString()} in a static context call with any value but zero.");
            }

            // Gas: Pre-Expand Memory (since it should be charged for expansion, then the call should be made, then written to)
            Memory.ExpandStream(inputMemoryStart, inputMemorySize);
            Memory.ExpandStream(outputMemoryStart, outputMemorySize);

            // Gas: Calculate extra gas costs based off of forks and what kind of call this is.
            BigInteger extraGasCost = 0;

            // Gas: If this is a call and the account doesn't exist
            if (Opcode == InstructionOpcode.CALL && !EVM.State.ContainsAccount(to))
            {
                // If the value is above zero (or if we're pre-spurious dragon) we charge for calling a new account.
                if (value > 0 || Version < EthereumRelease.SpuriousDragon)
                {
                    extraGasCost = GasDefinitions.GAS_CALL_NEW_ACCOUNT;
                }
            }

            // If we are transferring a value, we charge gas
            if (value > 0)
            {
                extraGasCost += GasDefinitions.GAS_CALL_VALUE;
            }

            // Tangerine whistle introduces new inner call gas limits
            // Source: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
            if (Version < EthereumRelease.TangerineWhistle)
            {
                // Prior to tangerine whistle, we need the provided gas + extra gas available
                GasState.Check(gas + extraGasCost);
            }
            else
            {
                // After tangerine whistle, we check that the desired gas amount for the call doesn't exceed our calculated max call gas (or else it's capped).
                GasState.Check(extraGasCost);
                gas = BigInteger.Min(gas, GasDefinitions.GetMaxCallGas(GasState.Gas - extraGasCost));
            }

            // Define how much gas our inner message can take.
            BigInteger innerCallGas = gas;

            if (value > 0)
            {
                innerCallGas += GasDefinitions.GAS_CALL_VALUE_STIPEND;
            }

            // Verify we have enough balance and call depth hasn't exceeded the maximum.
            if (EVM.State.GetBalance(Message.To) >= value && Message.Depth < EVMDefinitions.MAX_CALL_DEPTH)
            {
                // We're going to make an inner call, so we charge our gas and extra gas.
                GasState.Deduct(gas + extraGasCost);

                // Obtain our call data.
                byte[] callData = Memory.ReadBytes((long)inputMemoryStart, (int)inputMemorySize);

                // Create our message
                EVMMessage innerMessage = null;
                switch (Opcode)
                {
                case InstructionOpcode.CALL:
                    innerMessage = new EVMMessage(Message.To, to, value, innerCallGas, callData, Message.Depth + 1, to, true, Message.IsStatic);
                    break;

                case InstructionOpcode.DELEGATECALL:
                    innerMessage = new EVMMessage(Message.Sender, Message.To, Message.Value, innerCallGas, callData, Message.Depth + 1, to, false, Message.IsStatic);
                    break;

                case InstructionOpcode.STATICCALL:
                    innerMessage = new EVMMessage(Message.To, to, value, innerCallGas, callData, Message.Depth + 1, to, true, true);
                    break;

                case InstructionOpcode.CALLCODE:
                    innerMessage = new EVMMessage(Message.To, Message.To, value, innerCallGas, callData, Message.Depth + 1, to, true, Message.IsStatic);
                    break;
                }

                // Execute our message in an inner VM.
                EVMExecutionResult innerVMResult = MeadowEVM.Execute(EVM.State, innerMessage);

                // Refund our remaining gas that the inner VM didn't use.
                GasState.Refund(innerVMResult.RemainingGas);

                // Set our last call results
                ExecutionState.LastCallResult = innerVMResult;

                // Push a status indicating whether execution had succeeded without reverting changes.
                if (!innerVMResult.Succeeded)
                {
                    Stack.Push(0);
                }
                else
                {
                    Stack.Push(1);
                }

                // Determine how much we want to copy out.
                int returnCopyLength = Math.Min(ExecutionState.LastCallResult?.ReturnData.Length ?? 0, (int)outputMemorySize);
                if (returnCopyLength == 0 || ExecutionState.LastCallResult?.ReturnData == null)
                {
                    return;
                }

                // Copy our data out
                Memory.Write((long)outputMemoryStart, ExecutionState.LastCallResult.ReturnData.ToArray());
            }
            else
            {
                // We didn't have a sufficient balance or call depth so we push nothing to the stack. We push 0 (fail)
                Stack.Push(0);

                // Set our last call result as null.
                ExecutionState.LastCallResult = null;

                // Since we couldn't make an inner message call, we charge all the other extra charges, but not the inner message call cost. (Note: inner call gas comes from gas, so we put it here to offset potential extra cost from stipend)
                GasState.Deduct(gas + extraGasCost - innerCallGas);
            }
        }