예제 #1
0
        internal bool TransferTokens(RuntimeVM vm, string symbol, Address source, Address destination, BigInteger amount)
        {
            var Runtime = this;

            Runtime.Expect(amount > 0, "amount must be positive and greater than zero");
            Runtime.Expect(source != destination, "source and destination must be different");
            Runtime.Expect(Transaction.IsSignedBy(source), "invalid witness");
            Runtime.Expect(!Runtime.IsTrigger, "not allowed inside a trigger");

            if (destination.IsInterop)
            {
                Runtime.Expect(Runtime.Chain.IsRoot, "interop transfers only allowed in main chain");
                Runtime.CallContext("interop", "WithdrawTokens", source, destination, symbol, amount);
                return(true);
            }

            Runtime.Expect(Runtime.Nexus.TokenExists(symbol), "invalid token");
            var tokenInfo = Runtime.Nexus.GetTokenInfo(symbol);

            Runtime.Expect(tokenInfo.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");
            Runtime.Expect(tokenInfo.Flags.HasFlag(TokenFlags.Transferable), "token must be transferable");

            Runtime.Expect(Runtime.Nexus.TransferTokens(Runtime, symbol, source, destination, amount), "transfer failed");

            Runtime.Notify(EventKind.TokenSend, source, new TokenEventData()
            {
                chainAddress = Runtime.Chain.Address, value = amount, symbol = symbol
            });
            Runtime.Notify(EventKind.TokenReceive, destination, new TokenEventData()
            {
                chainAddress = Runtime.Chain.Address, value = amount, symbol = symbol
            });

            return(true);
        }
예제 #2
0
        // here we auto-initialize any fields from storage
        internal void LoadRuntimeData(RuntimeVM VM)
        {
            if (this.Runtime != null && this.Runtime != VM)
            {
                throw new ChainException("runtime already set on this contract");
            }

            this.Runtime = VM;

            var contractType = this.GetType();

            FieldInfo[] fields = contractType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);

            foreach (var field in fields)
            {
                var baseKey = $"_{this.Name}.{field.Name}".AsByteArray();

                var isStorageField = typeof(IStorageCollection).IsAssignableFrom(field.FieldType);
                if (isStorageField)
                {
                    var args = new object[] { baseKey, (StorageContext)VM.ChangeSet };
                    var obj  = Activator.CreateInstance(field.FieldType, args);

                    field.SetValue(this, obj);
                    continue;
                }

                if (typeof(ISerializable).IsAssignableFrom(field.FieldType))
                {
                    ISerializable obj;

                    if (VM.ChangeSet.Has(baseKey))
                    {
                        var bytes = VM.ChangeSet.Get(baseKey);
                        obj = (ISerializable)Activator.CreateInstance(field.FieldType);
                        using (var stream = new MemoryStream(bytes))
                        {
                            using (var reader = new BinaryReader(stream))
                            {
                                obj.UnserializeData(reader);
                            }
                        }

                        field.SetValue(this, obj);
                        continue;
                    }
                }

                if (VM.ChangeSet.Has(baseKey))
                {
                    var obj = VM.ChangeSet.Get(baseKey, field.FieldType);
                    field.SetValue(this, obj);
                    continue;
                }
            }
        }
예제 #3
0
        public static bool InvokeTriggerOnAccount(RuntimeVM runtimeVM, Address address, AccountTrigger trigger, params object[] args)
        {
            if (address.IsNull)
            {
                return(false);
            }

            if (address.IsUser)
            {
                var accountScript = runtimeVM.Nexus.LookUpAddressScript(address);
                return(InvokeTrigger(runtimeVM, accountScript, trigger.ToString(), args));
            }

            return(true);
        }
예제 #4
0
        internal object CallInternalMethod(RuntimeVM runtime, string name, object[] args)
        {
            Throw.If(!_methodTable.ContainsKey(name), "unknowm internal method");

            var method = _methodTable[name];

            Throw.IfNull(method, nameof(method));

            var parameters = method.GetParameters();

            for (int i = 0; i < parameters.Length; i++)
            {
                args[i] = CastArgument(runtime, args[i], parameters[i].ParameterType);
            }

            return(method.Invoke(this, args));
        }
예제 #5
0
        public static bool InvokeTrigger(RuntimeVM runtimeVM, byte[] script, string triggerName, params object[] args)
        {
            if (script == null || script.Length == 0)
            {
                return(true);
            }

            var leftOverGas = (uint)(runtimeVM.MaxGas - runtimeVM.UsedGas);
            var runtime     = new RuntimeVM(script, runtimeVM.Chain, runtimeVM.Epoch, runtimeVM.Block, runtimeVM.Transaction, runtimeVM.ChangeSet, false, true);

            runtime.ThrowOnFault = true;
            runtime.OracleReader = runtimeVM.OracleReader;

            for (int i = args.Length - 1; i >= 0; i--)
            {
                var obj = VMObject.FromObject(args[i]);
                runtime.Stack.Push(obj);
            }
            runtime.Stack.Push(VMObject.FromObject(triggerName));

            var state = runtime.Execute();

            // TODO catch VM exceptions?

            // propagate gas consumption
            // TODO this should happen not here but in real time during previous execution, to prevent gas attacks
            runtimeVM.ConsumeGas(runtime.UsedGas);

            if (state == ExecutionState.Halt)
            {
                // propagate events to the other runtime
                foreach (var evt in runtime.Events)
                {
                    runtimeVM.Notify(evt.Kind, evt.Address, evt.Data);
                }



                return(true);
            }
            else
            {
                return(false);
            }
        }
예제 #6
0
        internal void SetRuntimeData(RuntimeVM VM)
        {
            this.Runtime = VM;

            var contractType = this.GetType();

            FieldInfo[] fields = contractType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);

            var storageFields = fields.Where(x => typeof(IStorageCollection).IsAssignableFrom(x.FieldType)).ToList();

            if (storageFields.Count > 0)
            {
                foreach (var field in storageFields)
                {
                    var baseKey = $"_{this.Name}.{field.Name}".AsByteArray();
                    var args    = new object[] { baseKey, (StorageContext)VM.ChangeSet };
                    var obj     = Activator.CreateInstance(field.FieldType, args);

                    field.SetValue(this, obj);
                }
            }
        }
예제 #7
0
        private object CastArgument(RuntimeVM runtime, object arg, Type expectedType)
        {
            var receivedType = arg.GetType();

            if (expectedType.IsArray && expectedType != typeof(byte[]))
            {
                var dic         = (Dictionary <VMObject, VMObject>)arg;
                var elementType = expectedType.GetElementType();
                var array       = Array.CreateInstance(elementType, dic.Count);
                for (int i = 0; i < array.Length; i++)
                {
                    var key = new VMObject();
                    key.SetValue(i);

                    var val = dic[key].Data;
                    val = CastArgument(runtime, val, elementType);
                    array.SetValue(val, i);
                }
                return(array);
            }

            if (expectedType.IsEnum)
            {
                if (!receivedType.IsEnum)
                {
                    arg = Enum.Parse(expectedType, arg.ToString());
                    return(arg);
                }
            }

            if (expectedType == typeof(Address))
            {
                if (receivedType == typeof(string))
                {
                    // when a string is passed instead of an address we do an automatic lookup and replace
                    var name    = (string)arg;
                    var address = runtime.Nexus.LookUpName(name);
                    return(address);
                }
            }

            /*
             * if (expectedType == typeof(BigInteger))
             * {
             *  if (receivedType == typeof(string))
             *  {
             *      var value = (string)arg;
             *      if (BigInteger.TryParse(value, out BigInteger number))
             *      {
             *          arg = number;
             *      }
             *  }
             * }*/

            if (typeof(ISerializable).IsAssignableFrom(expectedType))
            {
                if (receivedType == typeof(byte[]))
                {
                    var bytes = (byte[])arg;
                    arg = Serialization.Unserialize(bytes, expectedType);
                    return(arg);
                }
            }

            return(arg);
        }
예제 #8
0
 public static bool InvokeTriggerOnToken(RuntimeVM runtimeVM, TokenInfo token, TokenTrigger trigger, params object[] args)
 {
     return(InvokeTrigger(runtimeVM, token.Script, trigger.ToString(), args));
 }
예제 #9
0
        private object CastArgument(RuntimeVM runtime, object arg, Type expectedType)
        {
            if (arg == null)
            {
                if (expectedType.IsArray)
                {
                    var elementType = expectedType.GetElementType();
                    var result      = Array.CreateInstance(elementType, 0);
                    return(result);
                }
                throw new Exception("Invalid cast for null VM object");
            }

            var receivedType = arg.GetType();

            if (expectedType == receivedType)
            {
                return(arg);
            }

            if (expectedType.IsArray)
            {
                if (expectedType == typeof(byte[]))
                {
                    if (receivedType == typeof(string))
                    {
                        return(Encoding.UTF8.GetBytes((string)arg));
                    }

                    if (receivedType == typeof(BigInteger))
                    {
                        return(((BigInteger)arg).ToSignedByteArray());
                    }

                    if (receivedType == typeof(Hash))
                    {
                        return(((Hash)arg).ToByteArray());
                    }

                    if (receivedType == typeof(Address))
                    {
                        return(((Address)arg).PublicKey);
                    }

                    throw new Exception("cannot cast this object to a byte array");
                }
                else
                {
                    var dic         = (Dictionary <VMObject, VMObject>)arg;
                    var elementType = expectedType.GetElementType();
                    var array       = Array.CreateInstance(elementType, dic.Count);
                    for (int i = 0; i < array.Length; i++)
                    {
                        var key = new VMObject();
                        key.SetValue(i);

                        var val = dic[key].Data;
                        val = CastArgument(runtime, val, elementType);
                        array.SetValue(val, i);
                    }
                    return(array);
                }
            }

            if (expectedType.IsEnum)
            {
                if (!receivedType.IsEnum)
                {
                    arg = Enum.Parse(expectedType, arg.ToString());
                    return(arg);
                }
            }

            if (expectedType == typeof(Address))
            {
                if (receivedType == typeof(string))
                {
                    // when a string is passed instead of an address we do an automatic lookup and replace
                    var name    = (string)arg;
                    var address = runtime.Nexus.LookUpName(name);
                    return(address);
                }
            }

            /*
             * if (expectedType == typeof(BigInteger))
             * {
             *  if (receivedType == typeof(string))
             *  {
             *      var value = (string)arg;
             *      if (BigInteger.TryParse(value, out BigInteger number))
             *      {
             *          arg = number;
             *      }
             *  }
             * }*/

            if (typeof(ISerializable).IsAssignableFrom(expectedType))
            {
                if (receivedType == typeof(byte[]))
                {
                    var bytes = (byte[])arg;
                    arg = Serialization.Unserialize(bytes, expectedType);
                    return(arg);
                }
            }

            return(arg);
        }