protected NativeContract() { using (ScriptBuilder sb = new ScriptBuilder()) { sb.EmitPush(Name); sb.EmitSysCall(ApplicationEngine.Neo_Native_Call); this.Script = sb.ToArray(); } this.Hash = Script.ToScriptHash(); List <ContractMethodDescriptor> descriptors = new List <ContractMethodDescriptor>(); List <string> safeMethods = new List <string>(); foreach (MemberInfo member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) { ContractMethodAttribute attribute = member.GetCustomAttribute <ContractMethodAttribute>(); if (attribute is null) { continue; } ContractMethodMetadata metadata = new ContractMethodMetadata(member, attribute); descriptors.Add(new ContractMethodDescriptor { Name = metadata.Name, ReturnType = ToParameterType(metadata.Handler.ReturnType), Parameters = metadata.Parameters.Select(p => new ContractParameterDefinition { Type = ToParameterType(p.Type), Name = p.Name }).ToArray() }); if (!attribute.RequiredCallFlags.HasFlag(CallFlags.AllowModifyStates)) { safeMethods.Add(metadata.Name); } methods.Add(metadata.Name, metadata); } this.Manifest = new ContractManifest { Groups = System.Array.Empty <ContractGroup>(), Features = ContractFeatures.NoProperty, SupportedStandards = new string[0], Abi = new ContractAbi() { Hash = Hash, Events = System.Array.Empty <ContractEventDescriptor>(), Methods = descriptors.ToArray() }, Permissions = new[] { ContractPermission.DefaultPermission }, Trusts = WildcardContainer <UInt160> .Create(), SafeMethods = WildcardContainer <string> .Create(safeMethods.ToArray()), Extra = null }; contractsList.Add(this); contractsNameDictionary.Add(Name, this); contractsHashDictionary.Add(Hash, this); }
internal async void Invoke(ApplicationEngine engine, byte version) { try { if (version != 0) { throw new InvalidOperationException($"The native contract of version {version} is not active."); } ExecutionContext context = engine.CurrentContext; ContractMethodMetadata method = methods[context.InstructionPointer]; ExecutionContextState state = context.GetState <ExecutionContextState>(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) { throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); } engine.AddGas(method.CpuFee * Policy.GetExecFeeFactor(engine.Snapshot) + method.StorageFee * Policy.GetStoragePrice(engine.Snapshot)); List <object> parameters = new List <object>(); if (method.NeedApplicationEngine) { parameters.Add(engine); } if (method.NeedSnapshot) { parameters.Add(engine.Snapshot); } for (int i = 0; i < method.Parameters.Length; i++) { parameters.Add(engine.Convert(context.EvaluationStack.Pop(), method.Parameters[i])); } object returnValue = method.Handler.Invoke(this, parameters.ToArray()); if (returnValue is ContractTask task) { await task; returnValue = task.GetResult(); } if (method.Handler.ReturnType != typeof(void) && method.Handler.ReturnType != typeof(ContractTask)) { context.EvaluationStack.Push(engine.Convert(returnValue)); } } catch (Exception ex) { engine.Throw(ex); } }
internal void Invoke(ApplicationEngine engine, byte version) { if (ActiveBlockIndex > Ledger.CurrentIndex(engine.Snapshot)) { throw new InvalidOperationException($"The native contract {Name} is not active."); } if (version != 0) { throw new InvalidOperationException($"The native contract of version {version} is not active."); } ExecutionContext context = engine.CurrentContext; ContractMethodMetadata method = methods[context.InstructionPointer]; ExecutionContextState state = context.GetState <ExecutionContextState>(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) { throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); } engine.AddGas(method.Price); List <object> parameters = new List <object>(); if (method.NeedApplicationEngine) { parameters.Add(engine); } if (method.NeedSnapshot) { parameters.Add(engine.Snapshot); } for (int i = 0; i < method.Parameters.Length; i++) { parameters.Add(engine.Convert(context.EvaluationStack.Pop(), method.Parameters[i])); } object returnValue = method.Handler.Invoke(this, parameters.ToArray()); if (method.Handler.ReturnType != typeof(void)) { context.EvaluationStack.Push(engine.Convert(returnValue)); } }
internal void Invoke(ApplicationEngine engine) { if (!engine.CurrentScriptHash.Equals(Hash)) { throw new InvalidOperationException("It is not allowed to use Neo.Native.Call directly to call native contracts. System.Contract.Call should be used."); } ExecutionContext context = engine.CurrentContext; string operation = context.EvaluationStack.Pop().GetString(); Array args = context.EvaluationStack.Pop <Array>(); ContractMethodMetadata method = methods[operation]; ExecutionContextState state = context.GetState <ExecutionContextState>(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) { throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); } engine.AddGas(method.Price); List <object> parameters = new List <object>(); if (method.NeedApplicationEngine) { parameters.Add(engine); } if (method.NeedSnapshot) { parameters.Add(engine.Snapshot); } for (int i = 0; i < method.Parameters.Length; i++) { StackItem item = i < args.Count ? args[i] : StackItem.Null; parameters.Add(engine.Convert(item, method.Parameters[i])); } object returnValue = method.Handler.Invoke(this, parameters.ToArray()); if (method.Handler.ReturnType != typeof(void)) { context.EvaluationStack.Push(engine.Convert(returnValue)); } }
protected NativeContract() { this.Id = --id_counter; byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { sb.EmitPush(Id); sb.EmitSysCall(ApplicationEngine.System_Contract_CallNative); script = sb.ToArray(); } this.Nef = new NefFile { Compiler = nameof(ScriptBuilder), Version = "3.0", Tokens = System.Array.Empty <MethodToken>(), Script = script }; this.Nef.CheckSum = NefFile.ComputeChecksum(Nef); this.Hash = Helper.GetContractHash(UInt160.Zero, script); List <ContractMethodDescriptor> descriptors = new List <ContractMethodDescriptor>(); foreach (MemberInfo member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) { ContractMethodAttribute attribute = member.GetCustomAttribute <ContractMethodAttribute>(); if (attribute is null) { continue; } ContractMethodMetadata metadata = new ContractMethodMetadata(member, attribute); descriptors.Add(new ContractMethodDescriptor { Name = metadata.Name, ReturnType = ToParameterType(metadata.Handler.ReturnType), Parameters = metadata.Parameters.Select(p => new ContractParameterDefinition { Type = ToParameterType(p.Type), Name = p.Name }).ToArray(), Safe = (attribute.RequiredCallFlags & ~CallFlags.ReadOnly) == 0 }); methods.Add(metadata.Name, metadata); } this.Manifest = new ContractManifest { Name = Name, Groups = System.Array.Empty <ContractGroup>(), SupportedStandards = new string[0], Abi = new ContractAbi() { Events = System.Array.Empty <ContractEventDescriptor>(), Methods = descriptors.ToArray() }, Permissions = new[] { ContractPermission.DefaultPermission }, Trusts = WildcardContainer <UInt160> .Create(), Extra = null }; if (ProtocolSettings.Default.NativeActivations.TryGetValue(Name, out uint activationIndex)) { this.ActiveBlockIndex = activationIndex; } contractsList.Add(this); contractsIdDictionary.Add(Id, this); contractsHashDictionary.Add(Hash, this); }