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); }
// 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; } } }
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); }
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)); }
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); } }
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); } } }
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); }
public static bool InvokeTriggerOnToken(RuntimeVM runtimeVM, TokenInfo token, TokenTrigger trigger, params object[] args) { return(InvokeTrigger(runtimeVM, token.Script, trigger.ToString(), args)); }
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); }