public void CallPrecompiledAddress(SolidityMessageCall msg, SolidityPrecompiledContract contract)
        {
            var data        = ChunkMemory(msg.InDataOffs.GetInt(), msg.InDataSize.GetInt());
            var contractOut = contract.Execute(data);

            SaveMemory(msg.OutDataOffs.GetInt(), contractOut.Value);
            StackPushOne();
        }
示例#2
0
        public void Step(SolidityProgram program, bool trace = false)
        {
            if (program == null) // http://solidity.readthedocs.io/en/develop/assembly.html
            {
                throw new ArgumentNullException(nameof(program));
            }

            var  solidityOpCode = SolidityOpCode.Instance();
            var  currentOpCode  = program.GetCurrentOpCode();
            var  opCode         = solidityOpCode.GetCode(currentOpCode);
            var  stack          = program.GetStack();
            var  oldMemSize     = program.GetMemorySize();
            long gasCost        = (long)solidityOpCode.GetTier(opCode.Value);

            switch (opCode)
            {
            case SolidityOpCodes.STOP:
                gasCost = SolidityGasCost.STOP;
                break;

            case SolidityOpCodes.SUICIDE:
                gasCost = SolidityGasCost.SUICIDE;
                break;

            case SolidityOpCodes.SSTORE:
                var sstoreNewValue = stack.ElementAt(stack.Count() - 2);
                var sstoreOldValue = program.StorageLoad(stack.Last());
                if (sstoreOldValue == null || !sstoreOldValue.IsZero())
                {
                    gasCost = SolidityGasCost.SET_SSTORE;
                }
                else if (sstoreOldValue != null && sstoreNewValue.IsZero())
                {
                    gasCost = SolidityGasCost.CLEAR_SSTORE;
                }
                else
                {
                    gasCost = SolidityGasCost.RESET_SSTORE;
                }
                break;

            case SolidityOpCodes.SLOAD:
                gasCost = SolidityGasCost.SLOAD;
                break;

            case SolidityOpCodes.MSTORE:
                gasCost += CalcMemGas(oldMemSize, MemNeeded(stack.Last(), new DataWord(32)), 0);
                break;

            case SolidityOpCodes.MSTORE8:
                gasCost += CalcMemGas(oldMemSize, MemNeeded(stack.Last(), new DataWord(1)), 0);
                break;

            case SolidityOpCodes.MLOAD:
                gasCost += CalcMemGas(oldMemSize, MemNeeded(stack.Last(), new DataWord(32)), 0);
                break;

            case SolidityOpCodes.RETURN:
            case SolidityOpCodes.REVERT:
                gasCost = SolidityGasCost.STOP + CalcMemGas(oldMemSize, MemNeeded(stack.Last(), stack.ElementAt(stack.Count() - 2)), 0);
                break;

            case SolidityOpCodes.SHA3:
                gasCost = SolidityGasCost.SHA3 + CalcMemGas(oldMemSize, MemNeeded(stack.Last(), stack.ElementAt(stack.Count() - 2)), 0);
                var size      = stack.ElementAt(stack.Count() - 2);
                var chunkUsed = (size.GetLongValueSafe() + 31) / 32;
                gasCost += chunkUsed * SolidityGasCost.SHA3_WORD;
                break;

            case SolidityOpCodes.CALLDATACOPY:
            case SolidityOpCodes.RETURNDATACOPY:
                gasCost += CalcMemGas(oldMemSize, MemNeeded(stack.Last(), stack.ElementAt(stack.Count() - 3)),
                                      stack.ElementAt(stack.Count() - 3).GetLongValueSafe());
                break;

            case SolidityOpCodes.CODECOPY:
                gasCost += CalcMemGas(oldMemSize,
                                      MemNeeded(stack.Last(), stack.ElementAt(stack.Count() - 3)),
                                      stack.ElementAt(stack.Count() - 3).GetLongValueSafe());
                break;

            case SolidityOpCodes.EXTCODESIZE:
                gasCost = SolidityGasCost.EXT_CODE_SIZE;
                break;

            case SolidityOpCodes.EXTCODECOPY:
                gasCost = SolidityGasCost.EXT_CODE_COPY + CalcMemGas(oldMemSize,
                                                                     MemNeeded(stack.ElementAt(stack.Count() - 2), stack.ElementAt(stack.Count() - 4)),
                                                                     stack.ElementAt(stack.Count() - 4).GetLongValueSafe());
                break;

            case SolidityOpCodes.CALL:
            // case SolidityOpCodes.CALLCODE:
            case SolidityOpCodes.DELEGATECALL:
            case SolidityOpCodes.STATICCALL:

                gasCost = SolidityGasCost.CALL;
                var callGasWord     = stack.ElementAt(stack.Count() - 1);
                var callAddressWord = stack.ElementAt(stack.Count() - 2);
                var value           = DataWord.ZERO;

                /*
                 * DataWord value = op.callHasValue() ?
                 *      stack.get(stack.size() - 3) : DataWord.ZERO;
                 */
                if (opCode == SolidityOpCodes.CALL)
                {
                    gasCost += SolidityGasCost.NEW_ACCT_CALL;
                }

                if (!value.IsZero())
                {
                    gasCost += SolidityGasCost.VT_CALL;
                }

                break;

            case SolidityOpCodes.EXP:

                DataWord exp           = stack.ElementAt(stack.Count() - 2);
                int      bytesOccupied = exp.GetBytesOccupied();
                gasCost = SolidityGasCost.EXP_GAS + SolidityGasCost.EXP_BYTE_GAS * bytesOccupied;
                break;
            }

            if (trace)
            {
                Trace.WriteLine("Operation " + Enum.GetName(typeof(SolidityOpCodes), opCode) + " " + program.GetPc() + " COST = " + gasCost);
                Trace.WriteLine("Stack: ");
                foreach (var s in program.GetStack())
                {
                    Trace.WriteLine(s.GetData().ToHexString());
                }

                Trace.WriteLine("Memory: ");
                Trace.WriteLine(program.GetMemory().ToHexString());
            }

            switch (opCode)
            {
            case SolidityOpCodes.PUSH1:
            case SolidityOpCodes.PUSH2:
            case SolidityOpCodes.PUSH3:
            case SolidityOpCodes.PUSH4:
            case SolidityOpCodes.PUSH5:
            case SolidityOpCodes.PUSH6:
            case SolidityOpCodes.PUSH7:
            case SolidityOpCodes.PUSH8:
            case SolidityOpCodes.PUSH9:
            case SolidityOpCodes.PUSH10:
            case SolidityOpCodes.PUSH11:
            case SolidityOpCodes.PUSH12:
            case SolidityOpCodes.PUSH13:
            case SolidityOpCodes.PUSH14:
            case SolidityOpCodes.PUSH15:
            case SolidityOpCodes.PUSH16:
            case SolidityOpCodes.PUSH17:
            case SolidityOpCodes.PUSH18:
            case SolidityOpCodes.PUSH19:
            case SolidityOpCodes.PUSH20:
            case SolidityOpCodes.PUSH21:
            case SolidityOpCodes.PUSH22:
            case SolidityOpCodes.PUSH23:
            case SolidityOpCodes.PUSH24:
            case SolidityOpCodes.PUSH25:
            case SolidityOpCodes.PUSH26:
            case SolidityOpCodes.PUSH27:
            case SolidityOpCodes.PUSH28:
            case SolidityOpCodes.PUSH29:
            case SolidityOpCodes.PUSH30:
            case SolidityOpCodes.PUSH31:
            case SolidityOpCodes.PUSH32:
                if (opCode == SolidityOpCodes.PUSH32)
                {
                    string sss = "";
                }
                program.Step();
                var nPush = SizeSolidityCodes[opCode.Value];
                var data  = program.Sweep(nPush);
                program.StackPush(data);
                break;

            case SolidityOpCodes.CALLDATALOAD:
                var pop       = program.StackPop();
                var dataValue = program.GetDataValue(pop);
                program.StackPush(dataValue);
                program.Step();
                break;

            case SolidityOpCodes.CALLDATACOPY:
                var memOffsetData  = program.StackPop();
                var dataOffsetData = program.StackPop();
                var lengthData     = program.StackPop();
                var msgData        = program.GetDataCopy(dataOffsetData, lengthData);
                program.SaveMemory(memOffsetData.GetIntValueSafe(), msgData.ToArray());
                program.Step();
                break;

            case SolidityOpCodes.ADDRESS:
                var address = program.GetOwnerAddress();
                program.StackPush(address);
                program.Step();
                break;

            case SolidityOpCodes.AND:
                var word1 = program.StackPop();
                var word2 = program.StackPop();
                word1.And(word2);
                program.StackPush(word1);
                program.Step();
                break;

            case SolidityOpCodes.OR:
                var w1 = program.StackPop();
                var w2 = program.StackPop();
                w1.Or(w2);
                program.StackPush(w1);
                program.Step();
                break;

            case SolidityOpCodes.XOR:
                var xorW1 = program.StackPop();
                var xorW2 = program.StackPop();
                xorW1.XOR(xorW2);
                program.StackPush(xorW1);
                program.Step();
                break;

            case SolidityOpCodes.BYTE:
                var      bw1    = program.StackPop();
                var      bw2    = program.StackPop();
                DataWord result = new DataWord();
                var      vBw1   = bw1.GetValue();
                if (!bw1.GetValue().Equals(BG_32))
                {
                    byte tmp = bw2.GetData()[bw1.GetInt()];
                    bw2.And(DataWord.ZERO);
                    bw2.GetData()[31] = tmp;
                    result            = bw2;
                }

                program.StackPush(result);
                program.Step();
                break;

            case SolidityOpCodes.ISZERO:
                var isZeroW1 = program.StackPop();
                // var isZeroW1 = stack.Last();
                if (isZeroW1.IsZero())
                {
                    isZeroW1.GetData()[31] = 1;
                }
                else
                {
                    isZeroW1.And(DataWord.ZERO);
                }

                program.StackPush(isZeroW1);
                program.Step();
                break;

            case SolidityOpCodes.EQ:
                var eqW1 = program.StackPop();
                var eqW2 = program.StackPop();
                if (eqW1.XOR(eqW2).IsZero())
                {
                    eqW1.And(DataWord.ZERO);
                    eqW1.GetData()[31] = 1;
                }
                else
                {
                    eqW1.And(DataWord.ZERO);
                }

                program.StackPush(eqW1);
                program.Step();
                break;

            case SolidityOpCodes.GT:
                var gtW1 = program.StackPop();
                var gtW2 = program.StackPop();
                if (gtW1.GetValue().CompareTo(gtW2.GetValue()) == 1)
                {
                    gtW1.And(DataWord.ZERO);
                    gtW1.GetData()[31] = 1;
                }
                else
                {
                    gtW1.And(DataWord.ZERO);
                }

                program.StackPush(gtW1);
                program.Step();
                break;

            case SolidityOpCodes.SGT:
                var sgtW1 = program.StackPop();
                var sgtW2 = program.StackPop();
                if (sgtW1.GetSValue().CompareTo(sgtW2.GetSValue()) == 1)
                {
                    sgtW1.And(DataWord.ZERO);
                    sgtW1.GetData()[31] = 1;
                }
                else
                {
                    sgtW1.And(DataWord.ZERO);
                }

                program.StackPush(sgtW1);
                program.Step();
                break;

            case SolidityOpCodes.LT:
                var ltW1 = program.StackPop();
                var ltW2 = program.StackPop();
                if (ltW1.GetValue().CompareTo(ltW2.GetValue()) == -1)
                {
                    ltW1.And(DataWord.ZERO);
                    ltW1.GetData()[31] = 1;
                }
                else
                {
                    ltW1.And(DataWord.ZERO);
                }

                program.StackPush(ltW1);
                program.Step();
                break;

            case SolidityOpCodes.SLT:
                var sltW1 = program.StackPop();
                var sltW2 = program.StackPop();
                if (sltW1.GetSValue().CompareTo(sltW2.GetSValue()) == -1)
                {
                    sltW1.And(DataWord.ZERO);
                    sltW1.GetData()[31] = 1;
                }
                else
                {
                    sltW1.And(DataWord.ZERO);
                }

                program.StackPush(sltW1);
                program.Step();
                break;

            case SolidityOpCodes.MSTORE:
                var msStoreW1 = program.StackPop();
                var msStoreW2 = program.StackPop();
                program.SaveMemory(msStoreW1, msStoreW2);
                program.Step();
                break;

            case SolidityOpCodes.MSTORE8:
                var    addr    = program.StackPop();
                var    value   = program.StackPop();
                byte[] byteVal = { value.GetData()[31] };
                program.SaveMemory(addr.GetIntValueSafe(), byteVal);
                program.Step();
                break;

            case SolidityOpCodes.CALLVALUE:
                var callValue = program.GetCallValue();
                program.StackPush(callValue);
                program.Step();
                break;

            case SolidityOpCodes.JUMPI:
                var pos  = program.StackPop();
                var cond = program.StackPop();
                if (!cond.IsZero() && !pos.IsZero())
                {
                    int nextPC = program.VerifyJumpDest(pos);
                    program.SetPc(nextPC);
                }
                else
                {
                    program.Step();
                }
                break;

            case SolidityOpCodes.JUMP:
                var jumpW1 = program.StackPop();
                var nextPc = program.VerifyJumpDest(jumpW1);
                program.SetPc(nextPc);
                break;

            case SolidityOpCodes.JUMPDEST:
                program.Step();
                break;

            case SolidityOpCodes.DUP1:
            case SolidityOpCodes.DUP2:
            case SolidityOpCodes.DUP3:
            case SolidityOpCodes.DUP4:
            case SolidityOpCodes.DUP5:
            case SolidityOpCodes.DUP6:
            case SolidityOpCodes.DUP7:
            case SolidityOpCodes.DUP8:
            case SolidityOpCodes.DUP9:
            case SolidityOpCodes.DUP10:
            case SolidityOpCodes.DUP11:
            case SolidityOpCodes.DUP12:
            case SolidityOpCodes.DUP13:
            case SolidityOpCodes.DUP14:
            case SolidityOpCodes.DUP15:
            case SolidityOpCodes.DUP16:
                var n      = SizeSolidityCodes[opCode.Value] - SizeSolidityCodes[SolidityOpCodes.DUP1] + 1;
                var dup1W1 = stack[stack.Count() - n];
                program.StackPush(dup1W1);
                program.Step();
                break;

            case SolidityOpCodes.CODECOPY:
                byte[] fullCode = ByteUtil.EMPTY_BYTE_ARRAY;
                fullCode = program.GetCode().ToArray();
                int copyDataW1     = program.StackPop().GetIntValueSafe();
                int copyDataW2     = program.StackPop().GetIntValueSafe();
                int copyDataW3     = program.StackPop().GetIntValueSafe();
                int sizeToBeCopied =
                    (long)copyDataW2 + copyDataW3 > fullCode.Length ?
                    (fullCode.Length < copyDataW2 ? 0 : fullCode.Length - copyDataW2)
                                    : copyDataW3;
                byte[] codeCopy = new byte[copyDataW3];
                if (copyDataW2 < fullCode.Length)
                {
                    Array.Copy(fullCode, copyDataW2, codeCopy, 0, sizeToBeCopied);
                }
                program.SaveMemory(copyDataW1, codeCopy);
                program.Step();
                break;

            case SolidityOpCodes.RETURN:
            case SolidityOpCodes.REVERT:
                int    retW1   = program.StackPop().GetIntValueSafe();
                int    retW2   = program.StackPop().GetIntValueSafe();
                byte[] hReturn = program.ChunkMemory(retW1, retW2);
                program.SetHReturn(hReturn);
                program.Step();
                program.Stop();
                if (opCode == SolidityOpCodes.REVERT)
                {
                    program.GetResult().SetRevert();
                }
                break;

            case SolidityOpCodes.SWAP1:
            case SolidityOpCodes.SWAP2:
            case SolidityOpCodes.SWAP3:
            case SolidityOpCodes.SWAP4:
            case SolidityOpCodes.SWAP5:
            case SolidityOpCodes.SWAP6:
            case SolidityOpCodes.SWAP7:
            case SolidityOpCodes.SWAP8:
            case SolidityOpCodes.SWAP9:
            case SolidityOpCodes.SWAP10:
            case SolidityOpCodes.SWAP11:
            case SolidityOpCodes.SWAP12:
            case SolidityOpCodes.SWAP13:
            case SolidityOpCodes.SWAP14:
            case SolidityOpCodes.SWAP15:
            case SolidityOpCodes.SWAP16:
                var sn = SizeSolidityCodes[opCode.Value] - SizeSolidityCodes[SolidityOpCodes.SWAP1] + 2;
                stack.Swap(stack.Count() - 1, stack.Count() - sn);
                program.Step();
                break;

            case SolidityOpCodes.DIV:
                var dW1 = program.StackPop();
                var dW2 = program.StackPop();
                dW1.Div(dW2);
                program.StackPush(dW1);
                program.Step();
                break;

            case SolidityOpCodes.POP:
                program.StackPop();
                program.Step();
                break;

            case SolidityOpCodes.MLOAD:
                var mloadW1  = program.StackPop();
                var memoryW2 = program.LoadMemory(mloadW1);
                program.StackPush(memoryW2);
                program.Step();
                break;

            case SolidityOpCodes.ADD:
                var addW1 = program.StackPop();
                var addW2 = program.StackPop();
                addW1.Add(addW2);
                program.StackPush(addW1);
                program.Step();
                break;

            case SolidityOpCodes.SUB:
                var subW1 = program.StackPop();
                var subW2 = program.StackPop();
                subW1.Sub(subW2);
                program.StackPush(subW1);
                program.Step();
                break;

            case SolidityOpCodes.MUL:
                var mulW1 = program.StackPop();
                var mulW2 = program.StackPop();
                mulW1.Mul(mulW2);
                program.StackPush(mulW1);
                program.Step();
                break;

            case SolidityOpCodes.CALL:     // CONTINUE TO DEVELOP METHOD CALL.
                program.StackPop();
                var codeAddress = program.StackPop();
                var cv          = program.StackPop();

                DataWord inDataOffs  = program.StackPop();
                DataWord inDataSize  = program.StackPop();
                DataWord outDataOffs = program.StackPop();
                DataWord outDataSize = program.StackPop();

                program.MemoryExpand(outDataOffs, outDataSize);
                var msg      = new SolidityMessageCall(opCode.Value, null, codeAddress, cv, inDataOffs, inDataSize, outDataOffs, outDataSize);
                var contract = SolidityPrecompiledContract.GetContractForAddress(codeAddress);

                if (contract != null)
                {
                    program.CallPrecompiledAddress(msg, contract);
                }

                program.Step();
                break;

            case SolidityOpCodes.NOT:
                var notW1 = program.StackPop();
                notW1.BNot();
                program.StackPush(notW1);
                program.Step();
                break;

            case SolidityOpCodes.EXP:
                var expWord1 = program.StackPop();
                var expWord2 = program.StackPop();
                expWord1.Exp(expWord2);
                program.StackPush(expWord1);
                program.Step();
                break;

            case SolidityOpCodes.CALLDATASIZE:
                var dataSize = program.GetDataSize();
                program.StackPush(dataSize);
                program.Step();
                break;

            case SolidityOpCodes.SSTORE:
                var sstoreWord1 = program.StackPop();
                var sstoreWord2 = program.StackPop();
                var tt          = sstoreWord1.GetData().ToHexString();
                var tt2         = sstoreWord2.GetData().ToHexString();
                program.SaveStorage(sstoreWord1, sstoreWord2);
                program.Step();
                break;

            case SolidityOpCodes.STOP:
                program.SetHReturn(SolidityMemory.EMPTY_BYTE_ARRAY);
                program.Stop();
                break;

            case SolidityOpCodes.SLOAD:
                var sLoadKey = program.StackPop();
                var sLoadVal = program.StorageLoad(sLoadKey);
                program.StackPush(sLoadVal); program.Step();
                break;

            case SolidityOpCodes.SHA3:
                var    sha3MemOffsetData = program.StackPop();
                var    sha3LengthData    = program.StackPop();
                byte[] buffer            = program.ChunkMemory(sha3MemOffsetData.GetIntValueSafe(), sha3LengthData.GetIntValueSafe());
                var    hash    = HashFactory.Crypto.SHA3.CreateBlake256();
                var    shaWord = hash.ComputeBytes(buffer).GetBytes();
                program.StackPush(shaWord);
                program.Step();
                break;

            case SolidityOpCodes.MSIZE:
                int memSize = program.GetMemorySize();
                var sizeW   = new DataWord(memSize);
                program.StackPush(sizeW);
                program.Step();
                break;

            case SolidityOpCodes.LOG0:
            case SolidityOpCodes.LOG1:
            case SolidityOpCodes.LOG2:
            case SolidityOpCodes.LOG3:
            case SolidityOpCodes.LOG4:
                var logAdr       = program.GetOwnerAddress();
                var logMemStart  = stack.Pop();
                var logMemOffset = stack.Pop();
                var nTopics      = SizeSolidityCodes[opCode.Value] - SizeSolidityCodes[SolidityOpCodes.LOG0];
                var topics       = new List <DataWord>();
                for (int i = 0; i < nTopics; ++i)
                {
                    DataWord topic = stack.Pop();
                    topics.Add(topic);
                }

                var logData = program.ChunkMemory(logMemStart.GetIntValueSafe(), logMemOffset.GetIntValueSafe());
                program.GetResult().AddLogInfo(new SolidityLogInfo(topics, logData));
                program.Step();
                break;
            }
        }