Example #1
0
        public static ITypeDescriptor ToMetadataType(this VMType type, ModuleDefinition module)
        {
            switch (type)
            {
            case VMType.Unknown:
            case VMType.Object:
                return(module.CorLibTypeFactory.Object);

            case VMType.Pointer:
                return(module.CorLibTypeFactory.IntPtr);

            case VMType.Byte:
                return(module.CorLibTypeFactory.Byte);

            case VMType.Word:
                return(module.CorLibTypeFactory.UInt16);

            case VMType.Dword:
                return(module.CorLibTypeFactory.UInt32);

            case VMType.Qword:
                return(module.CorLibTypeFactory.UInt64);

            case VMType.Real32:
                return(module.CorLibTypeFactory.Single);

            case VMType.Real64:
                return(module.CorLibTypeFactory.Double);

            default:
                throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }
Example #2
0
 public ContractEvent(byte value, string name, VMType returnType, byte[] description)
 {
     this.value       = value;
     this.name        = name;
     this.returnType  = returnType;
     this.description = description;
 }
Example #3
0
        public static ITypeDescriptor ToMetadataType(this VMType type, MetadataImage image)
        {
            switch (type)
            {
            case VMType.Unknown:
            case VMType.Object:
                return(image.TypeSystem.Object);

            case VMType.Pointer:
                return(image.TypeSystem.IntPtr);

            case VMType.Byte:
                return(image.TypeSystem.Byte);

            case VMType.Word:
                return(image.TypeSystem.UInt16);

            case VMType.Dword:
                return(image.TypeSystem.UInt32);

            case VMType.Qword:
                return(image.TypeSystem.UInt64);

            case VMType.Real32:
                return(image.TypeSystem.Single);

            case VMType.Real64:
                return(image.TypeSystem.Double);

            default:
                throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }
Example #4
0
        public async Task <IActionResult> Crear([FromBody] CrearViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }
            VMType vMType = new VMType
            {
                vmtypename        = model.vmtypename,
                vmtypedescription = model.vmtypedescription,
                vmtypeestado      = true
            };

            _context.VMTypes.Add(vMType);
            try
            {
                await _context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                return(BadRequest());
            }

            return(Ok());
        }
Example #5
0
        public static VMObject CastTo(VMObject srcObj, VMType type)
        {
            if (srcObj.Type == type)
            {
                var result = new VMObject();
                result.Copy(srcObj);
                return(result);
            }

            switch (type)
            {
            case VMType.None:
                return(new VMObject());

            case VMType.String:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsString());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Timestamp:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsTimestamp());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Bool:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsBool());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Bytes:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsByteArray());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Number:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsNumber());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Struct:
                switch (srcObj.Type)
                {
                case VMType.Object: return(CastViaReflection(srcObj.Data, 0));

                default: throw new Exception($"invalid cast: {srcObj.Type} to {type}");
                }

            default: throw new Exception($"invalid cast: {srcObj.Type} to {type}");
            }
        }
Example #6
0
 public ContractMethod(string name, VMType returnType, int offset, params ContractParameter[] parameters)
 {
     this.name       = name;
     this.offset     = offset;
     this.returnType = returnType;
     this.parameters = parameters;
 }
Example #7
0
        public static bool IsValidMethod(string methodName, VMType returnType)
        {
            if (string.IsNullOrEmpty(methodName) || methodName.Length < 3)
            {
                return(false);
            }

            if (methodName.StartsWith("is") && char.IsUpper(methodName[2]))
            {
                return(returnType == VMType.Bool);
            }

            // trigger
            if (methodName.StartsWith("on") && char.IsUpper(methodName[2]))
            {
                return(returnType == VMType.None);
            }

            // property
            if (methodName.StartsWith("get") && char.IsUpper(methodName[3]))
            {
                return(returnType != VMType.None);
            }

            return(true);
        }
Example #8
0
        private static ASTFunction ParseFunction()
        {
            VMType returnType = VMType.None;

            if (currentTokens[currentToken] is ReservedWordToken)
            {
                switch (currentTokens[currentToken].Token)
                {
                case "number":
                    returnType = VMType.Number;
                    break;

                case "string":
                    returnType = VMType.String;
                    break;

                case "object":
                    returnType = VMType.Object;
                    break;
                }
                currentToken++;
            }
            //else it is a constructor
            if (currentTokens[currentToken] is IdentifierToken)
            {
                string name = currentTokens[currentToken].Token;
                currentToken++;
                List <ASTNode> parameter = ParseFunctionParameter();
                List <ASTNode> codeBlock = ParseCodeBlock();
                currentToken++;

                if (returnType == VMType.None)
                {
                    if (name != currentClassName)
                    {
                        throw new ParserException(string.Format("Constructor '{0}' needs the same name as Class '{1}'.", name, currentClassName), currentTokens[currentToken].LineNumber);
                    }
                    return(new ASTConstructor()
                    {
                        Name = name,
                        Parameter = parameter,
                        CodeBlock = codeBlock,
                        ReturnValue = returnType
                    });
                }

                return(new ASTFunction()
                {
                    Name = name,
                    Parameter = parameter,
                    CodeBlock = codeBlock,
                    ReturnValue = returnType
                });
            }
            else
            {
                throw new ParserException("Expected Function Name.", currentTokens[currentToken].LineNumber);
            }
        }
        public void EmitLoad(byte reg, byte[] bytes, VMType type = VMType.Bytes)
        {
            Emit(Opcode.LOAD);
            writer.Write((byte)reg);
            writer.Write((byte)type);

            writer.WriteVarInt(bytes.Length);
            writer.Write(bytes);
        }
Example #10
0
        public VMObject SetDefaultValue(VMType type)
        {
            this.Type       = type;
            this._localSize = 1; // TODO fixme

            switch (type)
            {
            case VMType.Bytes:
            {
                this.Data = new byte[0];
                break;
            }

            case VMType.Number:
            {
                this.Data = new BigInteger(0);
                break;
            }

            case VMType.String:
            {
                this.Data = "";
                break;
            }

            case VMType.Enum:
            {
                this.Data = (uint)0;
                break;
            }

            case VMType.Timestamp:
            {
                this.Data = new Timestamp(0);
                break;
            }

            case VMType.Bool:
            {
                this.Data = false;
                break;
            }

            case VMType.Object:
            {
                this.Data = null;
                break;
            }

            default:
            {
                throw new Exception("Cannot init default value for vmtype: " + type);
            }
            }

            return(this);
        }
Example #11
0
        public ScriptBuilder EmitLoad(byte reg, byte[] bytes, VMType type = VMType.Bytes)
        {
            Emit(Opcode.LOAD);
            writer.Write((byte)reg);
            writer.Write((byte)type);

            writer.WriteVarInt(bytes.Length);
            writer.Write(bytes);
            return(this);
        }
Example #12
0
        public VMObject SetValue(byte[] val, VMType type)
        {
            this.Type       = type;
            this._localSize = val.Length;

            switch (type)
            {
            case VMType.Bytes:
            {
                this.Data = val;
                break;
            }

            case VMType.Number:
            {
                this.Data = (val == null || val.Length == 0) ? new BigInteger(0) : BigInteger.FromSignedArray(val);
                break;
            }

            case VMType.String:
            {
                this.Data = Encoding.UTF8.GetString(val);
                break;
            }

            case VMType.Enum:
            {
                // TODO this will fail if val is not exactly 4 bytes long. Add code here to autopad with zeros if necessary
                this.Data = BitConverter.ToUInt32(val, 0);
                break;
            }

            case VMType.Timestamp:
            {
                var temp = BitConverter.ToUInt32(val, 0);
                this.Data = new Timestamp(temp);
                break;
            }

            case VMType.Bool:
            {
                this.Data = BitConverter.ToBoolean(val, 0);
                break;
            }

            default:
            {
                throw new Exception("Cannot set value for vmtype: " + type);
            }
            }

            return(this);
        }
Example #13
0
        public ScriptBuilder EmitLoad(byte reg, byte[] bytes, VMType type = VMType.Bytes)
        {
            Throw.If(bytes.Length > 0xFFFF, "tried to load too much data");

            Emit(Opcode.LOAD);
            writer.Write((byte)reg);
            writer.Write((byte)type);

            writer.WriteVarInt(bytes.Length);
            writer.Write(bytes);
            return(this);
        }
Example #14
0
        public void CastTo(VMType type)
        {
            if (this.Type == type)
            {
                return;
            }

            switch (type)
            {
            case VMType.String:
                this.Data = this.Data.ToString();     // TODO does this work for all types?
                break;

            case VMType.Bool:
                switch (this.Type)
                {
                case VMType.Number: this.Data = this.AsNumber() != 0; break;

                case VMType.String: this.Data = !(((string)this.Data).Equals("false", StringComparison.OrdinalIgnoreCase)); break;

                default: throw new Exception($"invalid cast: {this.Type} to {type}");
                }
                break;

            case VMType.Bytes:
                switch (this.Type)
                {
                case VMType.Bool: this.Data = new byte[] { (byte)(this.AsBool() ? 1 : 0) }; break;

                case VMType.String: this.Data = Encoding.UTF8.GetBytes((string)this.Data); break;

                case VMType.Number: this.Data = ((BigInteger)this.Data).ToByteArray(); break;

                default: throw new Exception($"invalid cast: {this.Type} to {type}");
                }
                break;

            case VMType.Number:
                switch (this.Type)
                {
                case VMType.Bool: this.Data = this.AsBool() ? 1 : 0; break;

                case VMType.String: this.Data = BigInteger.Parse((string)this.Data); break;

                case VMType.Bytes: this.Data = new BigInteger((byte[])this.Data); break;

                default: throw new Exception($"invalid cast: {this.Type} to {type}");
                }
                break;

            default: throw new NotImplementedException();
            }
        }
Example #15
0
        public VMObject SetValue(byte[] val, VMType type)
        {
            this.Type       = type;
            this._localSize = val.Length;

            switch (type)
            {
            case VMType.Bytes:
            {
                this.Data = val;
                break;
            }

            case VMType.Number:
            {
                this.Data = BigInteger.FromSignedArray(val);
                break;
            }

            case VMType.String:
            {
                this.Data = Encoding.UTF8.GetString(val);
                break;
            }

            case VMType.Enum:
            {
                this.Data = BitConverter.ToUInt32(val, 0);
                break;
            }

            case VMType.Timestamp:
            {
                var temp = BitConverter.ToUInt32(val, 0);
                this.Data = new Timestamp(temp);
                break;
            }

            case VMType.Bool:
            {
                this.Data = BitConverter.ToBoolean(val, 0);
                break;
            }

            default:
            {
                throw new Exception("Invalid cast");
            }
            }

            return(this);
        }
Example #16
0
        public bool MergeWith(SymbolicValue value)
        {
            if (ReferenceEquals(this, value))
            {
                return(false);
            }

            Type = value.Type;
            int size = DataSources.Count;

            DataSources.UnionWith(value.DataSources);
            return(size != DataSources.Count);
        }
Example #17
0
        public ContractMethod(string name, VMType returnType, Dictionary <string, int> labels, params ContractParameter[] parameters)
        {
            if (!labels.ContainsKey(name))
            {
                throw new Exception("Missing offset in label map for method " + name);
            }

            var offset = labels[name];

            this.name       = name;
            this.offset     = offset;
            this.returnType = returnType;
            this.parameters = parameters;
        }
Example #18
0
        public static ContractMethod Unserialize(BinaryReader reader)
        {
            var name       = reader.ReadVarString();
            var returnType = (VMType)reader.ReadByte();
            var len        = reader.ReadByte();
            var parameters = new VMType[len];

            for (int i = 0; i < len; i++)
            {
                parameters[i] = (VMType)reader.ReadByte();
            }

            return(new ContractMethod(name, returnType, parameters));
        }
Example #19
0
        public object AsType(VMType type)
        {
            switch (type)
            {
            case VMType.Bool: return(AsBool());

            case VMType.String: return(AsString());

            case VMType.Bytes: return(AsByteArray());

            case VMType.Number: return(AsNumber());

            default: throw new ArgumentException("Unsupported VM cast");
            }
        }
Example #20
0
        public static List <SqlColumnInfo> GetVMList(string table_name, VMType vmType, List <SqlColumnInfo> current)
        {
            List <SqlColumnInfo> result = new List <SqlColumnInfo>();
            var tbInfo = dataList.Find(p => p.db_name == Cache_Next.GetDbName() && p.table_name == table_name);

            if (tbInfo == null || (vmType == VMType.Add && tbInfo.add_list.Count == 0) ||
                (vmType == VMType.Edit && tbInfo.edit_list.Count == 0) ||
                (vmType == VMType.Query && tbInfo.query_list.Count == 0))
            {
                var info = dataList.Find(p => p.db_name == Cache_Next.GetDbName() && p.type == 0);
                if (info == null)
                {
                    return(current);
                }
                else
                {
                    if (vmType == VMType.Add)
                    {
                        return(current.FindAll(p => !info.add_list.Contains(p.Name)));
                    }
                    else if (vmType == VMType.Edit)
                    {
                        return(current.FindAll(p => !info.edit_list.Contains(p.Name)));
                    }
                    else
                    {
                        return(current.FindAll(p => !info.query_list.Contains(p.Name)));
                    }
                }
            }
            else
            {
                if (vmType == VMType.Add)
                {
                    return(current.FindAll(p => tbInfo.add_list.Contains(p.Name)));
                }
                else if (vmType == VMType.Edit)
                {
                    return(current.FindAll(p => tbInfo.edit_list.Contains(p.Name)));
                }
                else
                {
                    return(current.FindAll(p => tbInfo.query_list.Contains(p.Name)));
                }
            }
        }
Example #21
0
        public VMObject SetValue(byte[] val, VMType type)
        {
            this.Type       = type;
            this._localSize = val.Length;

            switch (type)
            {
            case VMType.Bytes:
            {
                this.Data = val;
                break;
            }

            case VMType.Number:
            {
                this.Data = new BigInteger(val, twosComplementFormatFlag: true);
                break;
            }

            case VMType.String:
            {
                this.Data = Encoding.UTF8.GetString(val);
                break;
            }

            case VMType.Enum:
            {
                this.Data = BitConverter.ToUInt32(val, 0);
                break;
            }

            case VMType.Bool:
            {
                this.Data = BitConverter.ToBoolean(val, 0);
                break;
            }

            default:
            {
                throw new Exception("Invalid cast");
            }
            }

            return(this);
        }
Example #22
0
        internal Transaction CreateContractMethodCallTx(ByteString callTxInput, VMType vmType)
        {
            var callTxBytes = new CallTx
            {
                VmType = vmType,
                Input  = callTxInput
            }.ToByteString();

            var msgTxBytes = new MessageTx
            {
                From = this.Caller.ToProtobufAddress(),
                To   = this.Address.ToProtobufAddress(),
                Data = callTxBytes
            }.ToByteString();

            return(new Transaction
            {
                Id = 2,
                Data = msgTxBytes
            });
        }
Example #23
0
        public void Step(ref ExecutionFrame frame, Stack <VMObject> stack)
        {
            try
            {
                opcode = (Opcode)Read8();

                frame.VM.ValidateOpcode(opcode);

                switch (opcode)
                {
                case Opcode.NOP:
                {
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.MOVE:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    frame.Registers[dst] = frame.Registers[src];
                    frame.Registers[src] = new VMObject();
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.COPY:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    frame.Registers[dst].Copy(frame.Registers[src]);
                    break;
                }

                // args: byte dst_reg, byte type, var length, var data_bytes
                case Opcode.LOAD:
                {
                    var dst  = Read8();
                    var type = (VMType)Read8();
                    var len  = (int)ReadVar(0xFFFF);

                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var bytes = ReadBytes(len);
                    frame.Registers[dst].SetValue(bytes, type);

                    break;
                }

                // args: byte src_reg, dst_reg, byte type
                case Opcode.CAST:
                {
                    var src  = Read8();
                    var dst  = Read8();
                    var type = (VMType)Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var val = frame.Registers[src];
                    val = VMObject.CastTo(val, type);

                    frame.Registers[dst] = val;
                    break;
                }

                // args: byte src_reg
                case Opcode.PUSH:
                {
                    var src = Read8();
                    Expect(src < frame.Registers.Length, "invalid src register");

                    var val = frame.Registers[src];

                    var temp = new VMObject();
                    temp.Copy(val);
                    stack.Push(temp);
                    break;
                }

                // args: byte dest_reg
                case Opcode.POP:
                {
                    var dst = Read8();

                    Expect(stack.Count > 0, "stack is empty");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    frame.Registers[dst] = stack.Pop();
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.SWAP:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var temp = frame.Registers[src];
                    frame.Registers[src] = frame.Registers[dst];
                    frame.Registers[dst] = temp;

                    break;
                }

                // args: ushort offset, byte regCount
                case Opcode.CALL:
                {
                    var count = Read8();
                    var ofs   = Read16();

                    Expect(ofs < this.Script.Length, "invalid jump offset");
                    Expect(count >= 1, "at least 1 register required");
                    Expect(count <= VirtualMachine.MaxRegisterCount, "invalid register allocs");

                    frame.VM.PushFrame(this, InstructionPointer, count);
                    frame = frame.VM.CurrentFrame;

                    InstructionPointer = ofs;
                    break;
                }

                // args: byte srcReg
                case Opcode.EXTCALL:
                    using (var m = new ProfileMarker("EXTCALL"))
                    {
                        var src = Read8();
                        Expect(src < frame.Registers.Length, "invalid src register");

                        var method = frame.Registers[src].AsString();

                        var state = frame.VM.ExecuteInterop(method);
                        if (state != ExecutionState.Running)
                        {
                            throw new VMException(frame.VM, "VM extcall failed: " + method);
                        }

                        break;
                    }

                // args: ushort offset, byte src_reg
                // NOTE: JMP only has offset arg, not the rest
                case Opcode.JMP:
                case Opcode.JMPIF:
                case Opcode.JMPNOT:
                {
                    bool shouldJump;

                    if (opcode == Opcode.JMP)
                    {
                        shouldJump = true;
                    }
                    else
                    {
                        var src = Read8();
                        Expect(src < frame.Registers.Length, "invalid src register");

                        shouldJump = frame.Registers[src].AsBool();

                        if (opcode == Opcode.JMPNOT)
                        {
                            shouldJump = !shouldJump;
                        }
                    }

                    var newPos = (short)Read16();

                    Expect(newPos >= 0, "jump offset can't be negative value");
                    Expect(newPos < this.Script.Length, "trying to jump outside of script bounds");

                    if (shouldJump)
                    {
                        InstructionPointer = (uint)newPos;
                    }

                    break;
                }

                // args: var length, var bytes
                case Opcode.THROW:
                {
                    var src = Read8();

                    Expect(src < frame.Registers.Length, "invalid exception register");

                    var exception        = frame.Registers[src];
                    var exceptionMessage = exception.AsString();

                    throw new VMException(frame.VM, exceptionMessage);
                }

                // args: none
                case Opcode.RET:
                {
                    if (frame.VM.frames.Count > 1)
                    {
                        var temp = frame.VM.PeekFrame();

                        if (temp.Context.Name == this.Name)
                        {
                            InstructionPointer = frame.VM.PopFrame();
                            frame = frame.VM.CurrentFrame;
                        }
                        else
                        {
                            SetState(ExecutionState.Halt);
                        }
                    }
                    else
                    {
                        SetState(ExecutionState.Halt);
                    }
                    return;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.CAT:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length, "invalid srcA register");
                    Expect(srcB < frame.Registers.Length, "invalid srcB register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var A = frame.Registers[srcA];
                    var B = frame.Registers[srcB];

                    if (!A.IsEmpty)
                    {
                        if (B.IsEmpty)
                        {
                            frame.Registers[dst].Copy(A);
                        }
                        else
                        {
                            if (A.Type != B.Type)
                            {
                                throw new VMException(frame.VM, "Invalid cast during concat opcode");
                            }

                            var bytesA = A.AsByteArray();
                            var bytesB = B.AsByteArray();

                            var result = new byte[bytesA.Length + bytesB.Length];
                            Array.Copy(bytesA, result, bytesA.Length);
                            Array.Copy(bytesB, 0, result, bytesA.Length, bytesB.Length);

                            VMType type = A.Type;
                            frame.Registers[dst].SetValue(result, type);
                        }
                    }
                    else
                    {
                        if (B.IsEmpty)
                        {
                            frame.Registers[dst] = new VMObject();
                        }
                        else
                        {
                            frame.Registers[dst].Copy(B);
                        }
                    }

                    break;
                }

                case Opcode.SUBSTR:
                {
                    throw new NotImplementedException();
                }

                // args: byte src_reg, byte dest_reg, var length
                case Opcode.LEFT:
                {
                    var src = Read8();
                    var dst = Read8();
                    var len = (int)ReadVar(0xFFFF);

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var src_array = frame.Registers[src].AsByteArray();
                    Expect(len <= src_array.Length, "invalid length");

                    var result = new byte[len];

                    Array.Copy(src_array, result, len);

                    frame.Registers[dst].SetValue(result, VMType.Bytes);
                    break;
                }

                // args: byte src_reg, byte dest_reg, byte length
                case Opcode.RIGHT:
                {
                    var src = Read8();
                    var dst = Read8();
                    var len = (int)ReadVar(0xFFFF);

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var src_array = frame.Registers[src].AsByteArray();
                    Expect(len <= src_array.Length, "invalid length register");

                    var ofs = src_array.Length - len;

                    var result = new byte[len];
                    Array.Copy(src_array, ofs, result, 0, len);

                    frame.Registers[dst].SetValue(result, VMType.Bytes);
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.SIZE:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    int size;

                    var src_val = frame.Registers[src];

                    switch (src_val.Type)
                    {
                    case VMType.String:
                        size = src_val.AsString().Length;
                        break;

                    case VMType.Timestamp:
                    case VMType.Number:
                    case VMType.Enum:
                    case VMType.Bool:
                        size = 1;
                        break;

                    case VMType.None:
                        size = 0;
                        break;

                    default:
                        var src_array = src_val.AsByteArray();
                        size = src_array.Length;
                        break;
                    }

                    frame.Registers[dst].SetValue(size);
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.COUNT:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var val = frame.Registers[src];
                    int count;

                    switch (val.Type)
                    {
                    case VMType.Struct:
                    {
                        var children = val.GetChildren();
                        count = children.Count;
                        break;
                    }

                    default: count = 1; break;
                    }

                    frame.Registers[dst].SetValue(count);
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.NOT:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var val = frame.Registers[src].AsBool();

                    frame.Registers[dst].SetValue(!val);
                    break;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.AND:
                case Opcode.OR:
                case Opcode.XOR:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length, "invalid srcA register");
                    Expect(srcB < frame.Registers.Length, "invalid srcB register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var valA = frame.Registers[srcA];
                    var valB = frame.Registers[srcB];

                    switch (valA.Type)
                    {
                    case VMType.Bool:
                    {
                        Expect(valB.Type == VMType.Bool, $"expected {valA.Type} for logical op");

                        var a = valA.AsBool();
                        var b = valB.AsBool();

                        bool result;
                        switch (opcode)
                        {
                        case Opcode.AND: result = (a && b); break;

                        case Opcode.OR: result = (a || b); break;

                        case Opcode.XOR: result = (a ^ b); break;

                        default:
                        {
                            SetState(ExecutionState.Fault);
                            return;
                        }
                        }

                        frame.Registers[dst].SetValue(result);
                        break;
                    }

                    case VMType.Enum:
                    {
                        Expect(valB.Type == VMType.Enum, $"expected {valA.Type} for flag op");

                        var numA = valA.AsNumber();
                        var numB = valB.AsNumber();

                        Expect(numA.GetBitLength() <= 32, "too many bits");
                        Expect(numB.GetBitLength() <= 32, "too many bits");

                        var a = (uint)numA;
                        var b = (uint)numB;

                        if (opcode != Opcode.AND)
                        {
                            SetState(ExecutionState.Fault);
                        }

                        bool result = (a & b) != 0;

                        frame.Registers[dst].SetValue(result);
                        break;
                    }

                    case VMType.Number:
                    {
                        Expect(valB.Type == VMType.Number, $"expected {valA.Type} for logical op");

                        var numA = valA.AsNumber();
                        var numB = valB.AsNumber();

                        Expect(numA.GetBitLength() <= 64, "too many bits");
                        Expect(numB.GetBitLength() <= 64, "too many bits");

                        var a = (long)numA;
                        var b = (long)numB;

                        BigInteger result;
                        switch (opcode)
                        {
                        case Opcode.AND: result = (a & b); break;

                        case Opcode.OR: result = (a | b); break;

                        case Opcode.XOR: result = (a ^ b); break;

                        default:
                        {
                            SetState(ExecutionState.Fault);
                            return;
                        }
                        }

                        frame.Registers[dst].SetValue(result);
                        break;
                    }

                    default:
                        throw new VMException(frame.VM, "logical op unsupported for type " + valA.Type);
                    }

                    break;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.EQUAL:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length, "invalid srcA register");
                    Expect(srcB < frame.Registers.Length, "invalid srcB register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var a = frame.Registers[srcA];
                    var b = frame.Registers[srcB];

                    var result = a.Equals(b);
                    frame.Registers[dst].SetValue(result);

                    break;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.LT:
                case Opcode.GT:
                case Opcode.LTE:
                case Opcode.GTE:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length, "invalid srcA register");
                    Expect(srcB < frame.Registers.Length, "invalid srcB register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var a = frame.Registers[srcA].AsNumber();
                    var b = frame.Registers[srcB].AsNumber();

                    bool result;
                    switch (opcode)
                    {
                    case Opcode.LT: result = (a < b); break;

                    case Opcode.GT: result = (a > b); break;

                    case Opcode.LTE: result = (a <= b); break;

                    case Opcode.GTE: result = (a >= b); break;

                    default:
                    {
                        SetState(ExecutionState.Fault);
                        return;
                    }
                    }

                    frame.Registers[dst].SetValue(result);
                    break;
                }

                // args: byte reg
                case Opcode.INC:
                {
                    var dst = Read8();
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var val = frame.Registers[dst].AsNumber();
                    frame.Registers[dst].SetValue(val + 1);

                    break;
                }

                // args: byte reg
                case Opcode.DEC:
                {
                    var dst = Read8();
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var val = frame.Registers[dst].AsNumber();
                    frame.Registers[dst].SetValue(val - 1);

                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.SIGN:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var val = frame.Registers[src].AsNumber();

                    if (val == 0)
                    {
                        frame.Registers[dst].SetValue(BigInteger.Zero);
                    }
                    else
                    {
                        frame.Registers[dst].SetValue(val < 0 ? -1 : 1);
                    }

                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.NEGATE:
                {
                    var src = Read8();
                    var dst = Read8();
                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var val = frame.Registers[src].AsNumber();
                    frame.Registers[dst].SetValue(-val);

                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.ABS:
                {
                    var src = Read8();
                    var dst = Read8();
                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    var val = frame.Registers[src].AsNumber();
                    frame.Registers[dst].SetValue(val < 0 ? -val : val);

                    break;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.ADD:
                case Opcode.SUB:
                case Opcode.MUL:
                case Opcode.DIV:
                case Opcode.MOD:
                case Opcode.SHR:
                case Opcode.SHL:
                case Opcode.MIN:
                case Opcode.MAX:
                case Opcode.POW:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length, "invalid srcA register");
                    Expect(srcB < frame.Registers.Length, "invalid srcB register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    if (opcode == Opcode.ADD && frame.Registers[srcA].Type == VMType.String)
                    {
                        Expect(frame.Registers[srcB].Type == VMType.String, "invalid string as right operand");

                        var a = frame.Registers[srcA].AsString();
                        var b = frame.Registers[srcB].AsString();

                        var result = a + b;
                        frame.Registers[dst].SetValue(result);
                    }
                    else
                    {
                        var a = frame.Registers[srcA].AsNumber();
                        var b = frame.Registers[srcB].AsNumber();

                        BigInteger result;

                        switch (opcode)
                        {
                        case Opcode.ADD: result = a + b; break;

                        case Opcode.SUB: result = a - b; break;

                        case Opcode.MUL: result = a * b; break;

                        case Opcode.DIV: result = a / b; break;

                        case Opcode.MOD: result = a % b; break;

                        case Opcode.SHR: result = a >> (int)b; break;

                        case Opcode.SHL: result = a << (int)b; break;

                        case Opcode.MIN: result = a < b ? a : b; break;

                        case Opcode.MAX: result = a > b ? a : b; break;

                        case Opcode.POW: result = BigInteger.Pow(a, b); break;

                        default:
                        {
                            SetState(ExecutionState.Fault);
                            return;
                        }
                        }

                        frame.Registers[dst].SetValue(result);
                    }

                    break;
                }

                // args: byte src_reg, byte dest_reg, byte key
                case Opcode.PUT:
                {
                    var src    = Read8();
                    var dst    = Read8();
                    var keyReg = Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");
                    Expect(keyReg < frame.Registers.Length, "invalid key register");

                    var key = frame.Registers[keyReg];
                    Throw.If(key.Type == VMType.None, "invalid key type");

                    var value = frame.Registers[src];

                    frame.Registers[dst].SetKey(key, value);

                    break;
                }

                // args: byte src_reg, byte dest_reg, byte key
                case Opcode.GET:
                {
                    var src    = Read8();
                    var dst    = Read8();
                    var keyReg = Read8();

                    Expect(src < frame.Registers.Length, "invalid src register");
                    Expect(dst < frame.Registers.Length, "invalid dst register");
                    Expect(keyReg < frame.Registers.Length, "invalid key register");

                    var key = frame.Registers[keyReg];
                    Throw.If(key.Type == VMType.None, "invalid key type");

                    var val = frame.Registers[src].GetKey(key);

                    frame.Registers[dst] = val;

                    break;
                }

                // args: byte dest_reg
                case Opcode.CLEAR:
                {
                    var dst = Read8();

                    Expect(dst < frame.Registers.Length, "invalid dst register");

                    frame.Registers[dst] = new VMObject();

                    break;
                }

                // args: byte dest_reg, var key
                case Opcode.CTX:
                    using (var m = new ProfileMarker("CTX"))
                    {
                        var src = Read8();
                        var dst = Read8();

                        Expect(src < frame.Registers.Length, "invalid src register");
                        Expect(dst < frame.Registers.Length, "invalid dst register");

                        var contextName = frame.Registers[src].AsString();

                        ExecutionContext context = frame.VM.FindContext(contextName);

                        if (context == null)
                        {
                            throw new VMException(frame.VM, $"VM ctx instruction failed: could not find context with name '{contextName}'");
                        }

                        frame.Registers[dst].SetValue(context);

                        break;
                    }

                // args: byte src_reg
                case Opcode.SWITCH:
                    using (var m = new ProfileMarker("SWITCH"))
                    {
                        var src = Read8();
                        Expect(src < frame.Registers.Length, "invalid src register");

                        var context = frame.Registers[src].AsInterop <ExecutionContext>();

                        _state = frame.VM.SwitchContext(context, InstructionPointer);

                        if (_state == ExecutionState.Halt)
                        {
                            _state = ExecutionState.Running;
                            frame.VM.PopFrame();
                        }
                        else
                        {
                            throw new VMException(frame.VM, $"VM switch instruction failed: execution state did not halt");
                        }

                        break;
                    }

                // args: byte src_reg dst_reg
                case Opcode.UNPACK:
                    using (var m = new ProfileMarker("SWITCH"))
                    {
                        var src = Read8();
                        var dst = Read8();

                        Expect(src < frame.Registers.Length, "invalid src register");
                        Expect(dst < frame.Registers.Length, "invalid dst register");

                        var bytes = frame.Registers[src].AsByteArray();
                        frame.Registers[dst] = VMObject.FromBytes(bytes);
                        break;
                    }

                case Opcode.DEBUG:
                {
                    break;         // put here a breakpoint for debugging
                }

                default:
                {
                    throw new VMException(frame.VM, $"Unknown VM opcode: {(int)opcode}");
                }
                }
            }
            catch (Exception ex)
            {
                ex = ex.ExpandInnerExceptions();

                Trace.WriteLine(ex.ToString());
                SetState(ExecutionState.Fault);

                if (!(ex is VMException))
                {
                    ex = new VMException(frame.VM, ex.Message);
                }

                throw ex;
            }
        }
        /// <summary>
        /// Queries the current state of a contract.
        /// </summary>
        /// <typeparam name="T">The expected response type, must be deserializable with Newtonsoft.Json.</typeparam>
        /// <param name="contract">Address of the contract to query.</param>
        /// <param name="query">Raw query parameters data.</param>
        /// <param name="caller">Optional caller address.</param>
        /// <param name="vmType">Virtual machine type.</param>
        /// <returns>Deserialized response.</returns>
        internal async Task <T> QueryAsync <T>(Address contract, byte[] query, Address caller = default(Address), VMType vmType = VMType.Plugin)
        {
            var queryParams = new QueryParams
            {
                ContractAddress = contract.LocalAddress,
                Params          = query,
                VmType          = vmType
            };

            if (caller.LocalAddress != null && caller.ChainId != null)
            {
                queryParams.CallerAddress = caller.QualifiedAddress;
            }
            return(await this.readClient.SendAsync <T, QueryParams>("query", queryParams));
        }
 /// <summary>
 /// Queries the current state of a contract.
 /// </summary>
 /// <typeparam name="T">The expected response type, must be deserializable with Newtonsoft.Json.</typeparam>
 /// <param name="contract">Address of the contract to query.</param>
 /// <param name="query">Query parameters object.</param>
 /// <param name="caller">Optional caller address.</param>
 /// <param name="vmType">Virtual machine type.</param>
 /// <returns>Deserialized response.</returns>
 internal async Task <T> QueryAsync <T>(Address contract, IMessage query, Address caller = default(Address), VMType vmType = VMType.Plugin)
 {
     return(await QueryAsync <T>(contract, query.ToByteArray(), caller, vmType));
 }
        public void Step(ExecutionFrame frame, Stack <VMObject> stack)
        {
            try
            {
                var opcode = (Opcode)Read8();

                frame.VM.ValidateOpcode(opcode);

                switch (opcode)
                {
                case Opcode.NOP:
                {
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.MOVE:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    frame.Registers[dst] = frame.Registers[src];
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.COPY:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    frame.Registers[dst].Copy(frame.Registers[src]);
                    break;
                }

                // args: byte dst_reg, byte type, var length, var data_bytes
                case Opcode.LOAD:
                {
                    var dst  = Read8();
                    var type = (VMType)Read8();
                    var len  = (int)ReadVar(0xFFFF);

                    Expect(dst < frame.Registers.Length);

                    var bytes = ReadBytes(len);
                    frame.Registers[dst].SetValue(bytes, type);

                    break;
                }

                // args: byte src_reg, dst_reg, byte type
                case Opcode.CAST:
                {
                    var src  = Read8();
                    var dst  = Read8();
                    var type = (VMType)Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var val = frame.Registers[src];
                    val = VMObject.CastTo(val, type);

                    frame.Registers[dst] = val;
                    break;
                }

                // args: byte src_reg
                case Opcode.PUSH:
                {
                    var src = Read8();
                    Expect(src < frame.Registers.Length);

                    var val = frame.Registers[src];

                    var temp = new VMObject();
                    temp.Copy(val);
                    stack.Push(temp);
                    break;
                }

                // args: byte dest_reg
                case Opcode.POP:
                {
                    var dst = Read8();

                    Expect(stack.Count > 0);
                    Expect(dst < frame.Registers.Length);

                    frame.Registers[dst] = stack.Pop();
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.SWAP:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var temp = frame.Registers[src];
                    frame.Registers[src] = frame.Registers[dst];
                    frame.Registers[dst] = temp;

                    break;
                }

                // args: ushort offset, byte regCount
                case Opcode.CALL:
                {
                    var count = Read8();
                    var ofs   = Read16();

                    Expect(ofs < this.Script.Length);
                    Expect(count >= 1);
                    Expect(count <= VirtualMachine.MaxRegisterCount);

                    frame.VM.PushFrame(this, InstructionPointer, count);

                    InstructionPointer = ofs;
                    break;
                }

                // args: byte srcReg
                case Opcode.EXTCALL:
                    using (var m = new ProfileMarker("EXTCALL"))
                    {
                        var src = Read8();
                        Expect(src < frame.Registers.Length);

                        var method = frame.Registers[src].AsString();

                        var state = frame.VM.ExecuteInterop(method);
                        if (state != ExecutionState.Running)
                        {
                            throw new VMException(frame.VM, "VM extcall failed: " + method);
                        }

                        break;
                    }

                // args: ushort offset, byte src_reg
                // NOTE: JMP only has offset arg, not the rest
                case Opcode.JMP:
                case Opcode.JMPIF:
                case Opcode.JMPNOT:
                {
                    bool shouldJump;

                    if (opcode == Opcode.JMP)
                    {
                        shouldJump = true;
                    }
                    else
                    {
                        var src = Read8();
                        Expect(src < frame.Registers.Length);

                        shouldJump = frame.Registers[src].AsBool();

                        if (opcode == Opcode.JMPNOT)
                        {
                            shouldJump = !shouldJump;
                        }
                    }

                    var newPos = (short)Read16();

                    Expect(newPos >= 0);
                    Expect(newPos < this.Script.Length);

                    if (shouldJump)
                    {
                        InstructionPointer = (uint)newPos;
                    }

                    break;
                }

                // args: var length, var bytes
                case Opcode.THROW:
                {
                    var len = (int)ReadVar(1024);

                    if (len > 0)
                    {
                        var bytes = ReadBytes(len);
                    }

                    SetState(ExecutionState.Fault);
                    return;
                }

                // args: none
                case Opcode.RET:
                {
                    if (frame.VM.frames.Count > 1)
                    {
                        var temp = frame.VM.PeekFrame();

                        if (temp.Context == this)
                        {
                            InstructionPointer = frame.VM.PopFrame();
                            //Expect(InstructionPointer == this.Script.Length);
                        }
                        else
                        {
                            SetState(ExecutionState.Halt);
                        }
                    }
                    else
                    {
                        SetState(ExecutionState.Halt);
                    }
                    return;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.CAT:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length);
                    Expect(srcB < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var A = frame.Registers[srcA];
                    var B = frame.Registers[srcB];

                    if (!A.IsEmpty)
                    {
                        if (B.IsEmpty)
                        {
                            frame.Registers[dst].Copy(A);
                        }
                        else
                        {
                            var bytesA = A.AsByteArray();
                            var bytesB = B.AsByteArray();

                            var result = new byte[bytesA.Length + bytesB.Length];
                            Array.Copy(bytesA, result, bytesA.Length);
                            Array.Copy(bytesB, 0, result, bytesA.Length, bytesB.Length);

                            Expect(A.Type == B.Type);

                            VMType type = A.Type;
                            frame.Registers[dst].SetValue(result, type);
                        }
                    }
                    else
                    {
                        if (B.IsEmpty)
                        {
                            frame.Registers[dst] = new VMObject();
                        }
                        else
                        {
                            frame.Registers[dst].Copy(B);
                        }
                    }

                    break;
                }

                case Opcode.SUBSTR:
                {
                    throw new NotImplementedException();
                }

                // args: byte src_reg, byte dest_reg, var length
                case Opcode.LEFT:
                {
                    var src = Read8();
                    var dst = Read8();
                    var len = (int)ReadVar(0xFFFF);

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var src_array = frame.Registers[src].AsByteArray();
                    Expect(len <= src_array.Length);

                    var result = new byte[len];

                    Array.Copy(src_array, result, len);

                    frame.Registers[dst].SetValue(result, VMType.Bytes);
                    break;
                }

                // args: byte src_reg, byte dest_reg, byte length
                case Opcode.RIGHT:
                {
                    var src = Read8();
                    var dst = Read8();
                    var len = (int)ReadVar(0xFFFF);

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var src_array = frame.Registers[src].AsByteArray();
                    Expect(len <= src_array.Length);

                    var ofs = src_array.Length - len;

                    var result = new byte[len];
                    Array.Copy(src_array, ofs, result, 0, len);

                    frame.Registers[dst].SetValue(result, VMType.Bytes);
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.SIZE:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var src_array = frame.Registers[src].AsByteArray();
                    frame.Registers[dst].SetValue(src_array.Length);
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.COUNT:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var val = frame.Registers[src];
                    int count;

                    switch (val.Type)
                    {
                    case VMType.Struct:
                    {
                        var children = val.GetChildren();
                        count = children.Count;
                        break;
                    }

                    default: count = 1; break;
                    }

                    frame.Registers[dst].SetValue(count);
                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.NOT:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var val = frame.Registers[src].AsBool();

                    frame.Registers[dst].SetValue(!val);
                    break;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.AND:
                case Opcode.OR:
                case Opcode.XOR:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length);
                    Expect(srcB < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var a = frame.Registers[srcA].AsBool();
                    var b = frame.Registers[srcB].AsBool();

                    bool result;
                    switch (opcode)
                    {
                    case Opcode.AND: result = (a && b); break;

                    case Opcode.OR: result = (a || b); break;

                    case Opcode.XOR: result = (a ^ b); break;

                    default:
                    {
                        SetState(ExecutionState.Fault);
                        return;
                    }
                    }

                    frame.Registers[dst].SetValue(result);
                    break;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.EQUAL:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length);
                    Expect(srcB < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var a = frame.Registers[srcA];
                    var b = frame.Registers[srcB];

                    var result = a.Equals(b);
                    frame.Registers[dst].SetValue(result);

                    break;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.LT:
                case Opcode.GT:
                case Opcode.LTE:
                case Opcode.GTE:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length);
                    Expect(srcB < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var a = frame.Registers[srcA].AsNumber();
                    var b = frame.Registers[srcB].AsNumber();

                    bool result;
                    switch (opcode)
                    {
                    case Opcode.LT: result = (a < b); break;

                    case Opcode.GT: result = (a > b); break;

                    case Opcode.LTE: result = (a <= b); break;

                    case Opcode.GTE: result = (a >= b); break;

                    default:
                    {
                        SetState(ExecutionState.Fault);
                        return;
                    }
                    }

                    frame.Registers[dst].SetValue(result);
                    break;
                }

                // args: byte reg
                case Opcode.INC:
                {
                    var dst = Read8();
                    Expect(dst < frame.Registers.Length);

                    var val = frame.Registers[dst].AsNumber();
                    frame.Registers[dst].SetValue(val + 1);

                    break;
                }

                // args: byte reg
                case Opcode.DEC:
                {
                    var dst = Read8();
                    Expect(dst < frame.Registers.Length);

                    var val = frame.Registers[dst].AsNumber();
                    frame.Registers[dst].SetValue(val - 1);

                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.SIGN:
                {
                    var src = Read8();
                    var dst = Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var val = frame.Registers[src].AsNumber();

                    if (val == 0)
                    {
                        frame.Registers[dst].SetValue(BigInteger.Zero);
                    }
                    else
                    {
                        frame.Registers[dst].SetValue(val < 0 ? -1 : 1);
                    }

                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.NEGATE:
                {
                    var src = Read8();
                    var dst = Read8();
                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var val = frame.Registers[src].AsNumber();
                    frame.Registers[dst].SetValue(-val);

                    break;
                }

                // args: byte src_reg, byte dest_reg
                case Opcode.ABS:
                {
                    var src = Read8();
                    var dst = Read8();
                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var val = frame.Registers[src].AsNumber();
                    frame.Registers[dst].SetValue(val < 0 ? -val : val);

                    break;
                }

                // args: byte src_a_reg, byte src_b_reg, byte dest_reg
                case Opcode.ADD:
                case Opcode.SUB:
                case Opcode.MUL:
                case Opcode.DIV:
                case Opcode.MOD:
                case Opcode.SHR:
                case Opcode.SHL:
                case Opcode.MIN:
                case Opcode.MAX:
                {
                    var srcA = Read8();
                    var srcB = Read8();
                    var dst  = Read8();

                    Expect(srcA < frame.Registers.Length);
                    Expect(srcB < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);

                    var a = frame.Registers[srcA].AsNumber();
                    var b = frame.Registers[srcB].AsNumber();

                    BigInteger result;

                    switch (opcode)
                    {
                    case Opcode.ADD: result = a + b; break;

                    case Opcode.SUB: result = a - b; break;

                    case Opcode.MUL: result = a * b; break;

                    case Opcode.DIV: result = a / b; break;

                    case Opcode.MOD: result = a % b; break;

                    case Opcode.SHR: result = a >> (int)b; break;

                    case Opcode.SHL: result = a << (int)b; break;

                    case Opcode.MIN: result = a < b ? a : b; break;

                    case Opcode.MAX: result = a > b ? a : b; break;

                    default:
                    {
                        SetState(ExecutionState.Fault);
                        return;
                    }
                    }

                    frame.Registers[dst].SetValue(result);
                    break;
                }

                // args: byte src_reg, byte dest_reg, byte key
                case Opcode.PUT:
                {
                    var src    = Read8();
                    var dst    = Read8();
                    var keyReg = Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);
                    Expect(keyReg < frame.Registers.Length);

                    var key   = frame.Registers[keyReg];
                    var value = frame.Registers[src];

                    frame.Registers[dst].SetKey(key, value);

                    break;
                }

                // args: byte src_reg, byte dest_reg, byte key
                case Opcode.GET:
                {
                    var src    = Read8();
                    var dst    = Read8();
                    var keyReg = Read8();

                    Expect(src < frame.Registers.Length);
                    Expect(dst < frame.Registers.Length);
                    Expect(keyReg < frame.Registers.Length);

                    var key = frame.Registers[keyReg];
                    var val = frame.Registers[src].GetKey(key);

                    frame.Registers[dst] = val;

                    break;
                }

                // args: byte dest_reg
                case Opcode.THIS:
                {
                    var dst = Read8();
                    Expect(dst < frame.Registers.Length);

                    frame.Registers[dst].SetValue(this);

                    break;
                }

                // args: byte dest_reg, var key
                case Opcode.CTX:
                    using (var m = new ProfileMarker("CTX"))
                    {
                        var src = Read8();
                        var dst = Read8();

                        Expect(src < frame.Registers.Length);
                        Expect(dst < frame.Registers.Length);

                        var contextName = frame.Registers[src].AsString();

                        ExecutionContext context = frame.VM.FindContext(contextName);

                        if (context == null)
                        {
                            throw new VMException(frame.VM, $"VM ctx instruction failed: could not find context with name '{contextName}'");
                        }

                        frame.Registers[dst].SetValue(context);

                        break;
                    }

                // args: byte src_reg
                case Opcode.SWITCH:
                    using (var m = new ProfileMarker("SWITCH"))
                    {
                        var src = Read8();
                        Expect(src < frame.Registers.Length);

                        var context = frame.Registers[src].AsInterop <ExecutionContext>();

                        _state = frame.VM.SwitchContext(context, InstructionPointer);

                        if (_state == ExecutionState.Halt)
                        {
                            _state = ExecutionState.Running;
                            frame.VM.PopFrame();
                        }
                        else
                        {
                            throw new VMException(frame.VM, $"VM switch instruction failed: execution state did not halt");
                        }

                        break;
                    }

                default:
                {
                    throw new VMException(frame.VM, $"Unknown VM opcode: {(int)opcode}");
                }
                }
            }
            catch (Exception ex)
            {
                if (ex is TargetInvocationException)
                {
                    ex = ((TargetInvocationException)ex).InnerException;
                }

                Trace.WriteLine(ex.ToString());
                SetState(ExecutionState.Fault);

                if (!(ex is VMException))
                {
                    ex = new VMException(frame.VM, ex.Message);
                }

                if (frame.VM.ThrowOnFault) // enable this when debugging difficult stuff in the VM, should not be activated for production code
                {
                    throw ex;
                }
            }
        }
Example #27
0
 internal Transaction CreateContractMethodCallTx(string hexData, VMType vmType)
 {
     return(CreateContractMethodCallTx(ByteString.CopyFrom(CryptoUtils.HexStringToBytes(hexData)), vmType));
 }
Example #28
0
        private void ProcessLoad(ScriptBuilder sb)
        {
            if (Arguments.Length != 2 && Arguments.Length != 3)
            {
                throw new CompilerException(LineNumber, ERR_INCORRECT_NUMBER);
            }

            if (Arguments[0].IsRegister())
            {
                var reg = Arguments[0].AsRegister();

                VMType type = VMType.None;

                if (Arguments.Length == 3)
                {
                    if (!Enum.TryParse(Arguments[2], out type))
                    {
                        throw new CompilerException(LineNumber, ERR_INVALID_ARGUMENT);
                    }
                }

                if (Arguments[1].IsBytes())
                {
                    sb.EmitLoad(reg, Arguments[1].AsBytes());
                }
                else
                if (Arguments[1].IsBool())
                {
                    sb.EmitLoad(reg, Arguments[1].AsBool());
                }
                else
                if (Arguments[1].IsString())
                {
                    sb.EmitLoad(reg, Arguments[1].AsString());
                }
                else
                if (Arguments[1].IsNumber())
                {
                    if (type == VMType.Enum)
                    {
                        var num = (uint)Arguments[1].AsNumber();

                        using (var stream = new MemoryStream())
                        {
                            using (var writer = new BinaryWriter(stream))
                            {
                                writer.Write((byte)reg);
                                writer.Write((byte)VMType.Enum);
                                writer.Write((byte)4);

                                var numBytes = BitConverter.GetBytes(num);
                                writer.Write(numBytes);
                            }

                            var bytes = stream.ToArray();
                            sb.Emit(Opcode.LOAD, bytes);
                        }
                    }
                    else
                    if (type != VMType.None)
                    {
                        throw new CompilerException(LineNumber, ERR_INVALID_TYPE);
                    }
                    else
                    {
                        sb.EmitLoad(reg, Arguments[1].AsNumber());
                    }
                }
                else
                {
                    throw new CompilerException(LineNumber, ERR_INVALID_ARGUMENT);
                }
            }
            else
            {
                throw new CompilerException(LineNumber, ERR_INVALID_ARGUMENT);
            }
        }
Example #29
0
 public VCallAnnotation(VMCalls vmCall, VMType returnType)
 {
     VMCall     = vmCall;
     ReturnType = returnType;
 }
Example #30
0
        public VMObject SetValue(byte[] val, VMType type)
        {
            this.Type       = type;
            this._localSize = val != null ? val.Length : 0;

            switch (type)
            {
            case VMType.Bytes:
            {
                this.Data = val;
                break;
            }

            case VMType.Number:
            {
                this.Data = (val == null || val.Length == 0) ? new BigInteger(0) : BigInteger.FromSignedArray(val);
                break;
            }

            case VMType.String:
            {
                this.Data = Encoding.UTF8.GetString(val);
                break;
            }

            case VMType.Enum:
            {
                // TODO this will fail if val is not exactly 4 bytes long. Add code here to autopad with zeros if necessary
                this.Data = BitConverter.ToUInt32(val, 0);
                break;
            }

            case VMType.Timestamp:
            {
                var temp = BitConverter.ToUInt32(val, 0);
                this.Data = new Timestamp(temp);
                break;
            }

            case VMType.Bool:
            {
                this.Data = BitConverter.ToBoolean(val, 0);
                break;
            }

            default:
                if (val is byte[])
                {
                    var bytes = (byte[])val;

                    var len = bytes != null ? bytes.Length : 0;

                    switch (len)
                    {
                    case Address.LengthInBytes:
                        this.Data = Address.FromBytes(bytes);
                        break;

                    case Hash.Length:
                        this.Data = Hash.FromBytes(bytes);
                        break;

                    default:
                        try
                        {
                            this.UnserializeData(bytes);
                        }
                        catch (Exception e)
                        {
                            throw new Exception("Cannot decode interop object from bytes with length: " + len);
                        }
                        break;
                    }

                    break;
                }
                else
                {
                    throw new Exception("Cannot set value for vmtype: " + type);
                }
            }

            return(this);
        }