예제 #1
0
        private ContractState Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data)
        {
            if (engine.ScriptContainer is not Transaction tx)
            {
                throw new InvalidOperationException();
            }
            if (nefFile.Length == 0)
            {
                throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}");
            }
            if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength)
            {
                throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}");
            }

            engine.AddGas(Math.Max(
                              engine.StoragePrice * (nefFile.Length + manifest.Length),
                              GetMinimumDeploymentFee(engine.Snapshot)
                              ));

            NefFile          nef            = nefFile.AsSerializable <NefFile>();
            ContractManifest parsedManifest = ContractManifest.Parse(manifest);
            UInt160          hash           = Helper.GetContractHash(tx.Sender, nef.CheckSum, parsedManifest.Name);
            StorageKey       key            = CreateStorageKey(Prefix_Contract).Add(hash);

            if (engine.Snapshot.Contains(key))
            {
                throw new InvalidOperationException($"Contract Already Exists: {hash}");
            }
            ContractState contract = new ContractState
            {
                Id            = GetNextAvailableId(engine.Snapshot),
                UpdateCounter = 0,
                Nef           = nef,
                Hash          = hash,
                Manifest      = parsedManifest
            };

            if (!contract.Manifest.IsValid(hash))
            {
                throw new InvalidOperationException($"Invalid Manifest Hash: {hash}");
            }

            engine.Snapshot.Add(key, new StorageItem(contract));

            // Execute _deploy

            ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy", 2);

            if (md != null)
            {
                engine.CallFromNativeContract(Hash, hash, md.Name, data, false);
            }

            engine.SendNotification(Hash, "Deploy", new VM.Types.Array {
                contract.Hash.ToArray()
            });

            return(contract);
        }
예제 #2
0
        internal bool Invoke(ApplicationEngine engine)
        {
            if (!engine.CurrentScriptHash.Equals(Hash))
            {
                return(false);
            }
            string operation = engine.CurrentContext.EvaluationStack.Pop().GetString();
            Array  args      = (Array)engine.CurrentContext.EvaluationStack.Pop();

            if (!methods.TryGetValue(operation, out ContractMethodMetadata method))
            {
                return(false);
            }
            ExecutionContextState state = engine.CurrentContext.GetState <ExecutionContextState>();

            if (!state.CallFlags.HasFlag(method.RequiredCallFlags))
            {
                return(false);
            }
            if (!engine.AddGas(method.Price))
            {
                return(false);
            }
            StackItem result = method.Delegate(engine, args);

            engine.CurrentContext.EvaluationStack.Push(result);
            return(true);
        }
예제 #3
0
        private void Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data)
        {
            if (nefFile is null && manifest is null)
            {
                throw new ArgumentException();
            }

            engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0)));

            var contract = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable <ContractState>();

            if (contract is null)
            {
                throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}");
            }

            if (nefFile != null)
            {
                if (nefFile.Length == 0)
                {
                    throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}");
                }

                // Update nef
                contract.Nef = nefFile.AsSerializable <NefFile>();
            }
            if (manifest != null)
            {
                if (manifest.Length == 0)
                {
                    throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}");
                }
                ContractManifest manifest_new = ContractManifest.Parse(manifest);
                if (manifest_new.Name != contract.Manifest.Name)
                {
                    throw new InvalidOperationException("The name of the contract can't be changed.");
                }
                if (!manifest_new.IsValid(contract.Hash))
                {
                    throw new InvalidOperationException($"Invalid Manifest Hash: {contract.Hash}");
                }
                contract.Manifest = manifest_new;
            }
            Check(contract.Nef.Script, contract.Manifest.Abi);
            contract.UpdateCounter++; // Increase update counter
            if (nefFile != null)
            {
                ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy", 2);
                if (md != null)
                {
                    engine.CallFromNativeContract(Hash, contract.Hash, md.Name, data, true);
                }
            }
            engine.SendNotification(Hash, "Update", new VM.Types.Array {
                contract.Hash.ToArray()
            });
        }
예제 #4
0
        private async ContractTask <ContractState> Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data)
        {
            if (engine.ScriptContainer is not Transaction tx)
            {
                throw new InvalidOperationException();
            }
            if (nefFile.Length == 0)
            {
                throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}");
            }
            if (manifest.Length == 0)
            {
                throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}");
            }

            engine.AddGas(Math.Max(
                              engine.StoragePrice * (nefFile.Length + manifest.Length),
                              GetMinimumDeploymentFee(engine.Snapshot)
                              ));

            NefFile          nef            = nefFile.AsSerializable <NefFile>();
            ContractManifest parsedManifest = ContractManifest.Parse(manifest);

            Helper.Check(nef.Script, parsedManifest.Abi);
            UInt160 hash = Helper.GetContractHash(tx.Sender, nef.CheckSum, parsedManifest.Name);

            if (Policy.IsBlocked(engine.Snapshot, hash))
            {
                throw new InvalidOperationException($"The contract {hash} has been blocked.");
            }

            StorageKey key = CreateStorageKey(Prefix_Contract).Add(hash);

            if (engine.Snapshot.Contains(key))
            {
                throw new InvalidOperationException($"Contract Already Exists: {hash}");
            }
            ContractState contract = new()
            {
                Id            = GetNextAvailableId(engine.Snapshot),
                UpdateCounter = 0,
                Nef           = nef,
                Hash          = hash,
                Manifest      = parsedManifest
            };

            if (!contract.Manifest.IsValid(hash))
            {
                throw new InvalidOperationException($"Invalid Manifest Hash: {hash}");
            }

            engine.Snapshot.Add(key, new StorageItem(contract));

            await OnDeploy(engine, contract, data, false);

            return(contract);
        }
예제 #5
0
        private ContractState Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest)
        {
            if (!(engine.ScriptContainer is Transaction tx))
            {
                throw new InvalidOperationException();
            }
            if (nefFile.Length == 0)
            {
                throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}");
            }
            if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength)
            {
                throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}");
            }

            engine.AddGas(engine.StoragePrice * (nefFile.Length + manifest.Length));

            NefFile    nef  = nefFile.AsSerializable <NefFile>();
            UInt160    hash = Helper.GetContractHash(tx.Sender, nef.Script);
            StorageKey key  = CreateStorageKey(Prefix_Contract).Add(hash);

            if (engine.Snapshot.Storages.Contains(key))
            {
                throw new InvalidOperationException($"Contract Already Exists: {hash}");
            }
            ContractState contract = new ContractState
            {
                Id            = GetNextAvailableId(engine.Snapshot),
                UpdateCounter = 0,
                Script        = nef.Script,
                Hash          = hash,
                Manifest      = ContractManifest.Parse(manifest)
            };

            if (!contract.Manifest.IsValid(hash))
            {
                throw new InvalidOperationException($"Invalid Manifest Hash: {hash}");
            }

            engine.Snapshot.Storages.Add(key, new StorageItem(contract));

            // Execute _deploy

            ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy");

            if (md != null)
            {
                engine.CallFromNativeContract(Hash, hash, md.Name, false);
            }

            return(contract);
        }
예제 #6
0
        internal bool Invoke(ApplicationEngine engine)
        {
            if (!engine.CurrentScriptHash.Equals(Hash))
            {
                return(false);
            }
            if (!engine.TryPop(out string operation))
            {
                return(false);
            }
            if (!engine.TryPop(out Array args))
            {
                return(false);
            }
            if (!methods.TryGetValue(operation, out ContractMethodMetadata method))
            {
                return(false);
            }
            ExecutionContextState state = engine.CurrentContext.GetState <ExecutionContextState>();

            if (!state.CallFlags.HasFlag(method.RequiredCallFlags))
            {
                return(false);
            }
            if (!engine.AddGas(method.Price))
            {
                return(false);
            }
            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))
            {
                engine.Push(engine.Convert(returnValue));
            }
            return(true);
        }
예제 #7
0
        private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data)
        {
            if (nefFile is null && manifest is null)
            {
                throw new ArgumentException();
            }

            engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0)));

            var contract = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable <ContractState>();

            if (contract is null)
            {
                throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}");
            }
            if (contract.UpdateCounter == ushort.MaxValue)
            {
                throw new InvalidOperationException($"The contract reached the maximum number of updates.");
            }

            if (nefFile != null)
            {
                if (nefFile.Length == 0)
                {
                    throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}");
                }

                // Update nef
                contract.Nef = nefFile.AsSerializable <NefFile>();
            }
            if (manifest != null)
            {
                if (manifest.Length == 0)
                {
                    throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}");
                }
                ContractManifest manifest_new = ContractManifest.Parse(manifest);
                if (manifest_new.Name != contract.Manifest.Name)
                {
                    throw new InvalidOperationException("The name of the contract can't be changed.");
                }
                if (!manifest_new.IsValid(contract.Hash))
                {
                    throw new InvalidOperationException($"Invalid Manifest Hash: {contract.Hash}");
                }
                contract.Manifest = manifest_new;
            }
            Helper.Check(contract.Nef.Script, contract.Manifest.Abi);
            contract.UpdateCounter++; // Increase update counter
            return(OnDeploy(engine, contract, data, true));
        }
예제 #8
0
        private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey)
        {
            if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash()))
            {
                return(false);
            }
            engine.AddGas(GetRegisterPrice(engine.Snapshot));
            StorageKey     key   = CreateStorageKey(Prefix_Candidate).Add(pubkey);
            StorageItem    item  = engine.Snapshot.GetAndChange(key, () => new StorageItem(new CandidateState()));
            CandidateState state = item.GetInteroperable <CandidateState>();

            state.Registered = true;
            return(true);
        }
예제 #9
0
        private void Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest)
        {
            if (nefFile is null && manifest is null)
            {
                throw new ArgumentException();
            }

            engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0)));

            var contract = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable <ContractState>();

            if (contract is null)
            {
                throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}");
            }

            if (nefFile != null)
            {
                if (nefFile.Length == 0)
                {
                    throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}");
                }

                NefFile nef = nefFile.AsSerializable <NefFile>();

                // Update script
                contract.Script = nef.Script;
            }
            if (manifest != null)
            {
                if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength)
                {
                    throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}");
                }
                contract.Manifest = ContractManifest.Parse(manifest);
                if (!contract.Manifest.IsValid(contract.Hash))
                {
                    throw new InvalidOperationException($"Invalid Manifest Hash: {contract.Hash}");
                }
            }
            contract.UpdateCounter++; // Increase update counter
            if (nefFile != null)
            {
                ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy");
                if (md != null)
                {
                    engine.CallFromNativeContract(Hash, contract.Hash, md.Name, true);
                }
            }
        }
예제 #10
0
 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);
     }
 }
예제 #11
0
        private uint Renew(ApplicationEngine engine, string name)
        {
            if (!nameRegex.IsMatch(name))
            {
                throw new ArgumentException(null, nameof(name));
            }
            string[] names = name.Split('.');
            if (names.Length != 2)
            {
                throw new ArgumentException(null, nameof(name));
            }
            engine.AddGas(GetPrice(engine.Snapshot));
            byte[]    hash  = GetKey(Utility.StrictUTF8.GetBytes(name));
            NameState state = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Token).Add(hash)).GetInteroperable <NameState>();

            engine.Snapshot.Delete(CreateStorageKey(Prefix_Expiration).AddBigEndian(state.Expiration).Add(hash));
            state.Expiration += OneYear;
            engine.Snapshot.Add(CreateStorageKey(Prefix_Expiration).AddBigEndian(state.Expiration).Add(hash), new StorageItem(new byte[] { 0 }));
            return(state.Expiration);
        }
예제 #12
0
        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));
            }
        }
예제 #13
0
        private bool Register(ApplicationEngine engine, string name, UInt160 owner)
        {
            if (!nameRegex.IsMatch(name))
            {
                throw new ArgumentException(null, nameof(name));
            }
            string[] names = name.Split('.');
            if (names.Length != 2)
            {
                throw new ArgumentException(null, nameof(name));
            }
            if (!engine.CheckWitnessInternal(owner))
            {
                throw new InvalidOperationException();
            }
            byte[] hash = GetKey(Utility.StrictUTF8.GetBytes(name));
            if (engine.Snapshot.TryGet(CreateStorageKey(Prefix_Token).Add(hash)) is not null)
            {
                return(false);
            }
            StringList roots = engine.Snapshot[CreateStorageKey(Prefix_Roots)].GetInteroperable <StringList>();

            if (roots.BinarySearch(names[1]) < 0)
            {
                throw new InvalidOperationException();
            }
            engine.AddGas(GetPrice(engine.Snapshot));
            NameState state = new NameState
            {
                Owner       = owner,
                Name        = name,
                Description = "",
                Expiration  = (uint)(engine.PersistingBlock.Timestamp / 1000) + OneYear
            };

            Mint(engine, state);
            engine.Snapshot.Add(CreateStorageKey(Prefix_Expiration).AddBigEndian(state.Expiration).Add(hash), new StorageItem(new byte[] { 0 }));
            return(true);
        }
예제 #14
0
        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));
            }
        }