예제 #1
0
        private static ExecutionState Runtime_UpgradeContract(RuntimeVM vm)
        {
            var tx = vm.Transaction;

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

            var pow = tx.Hash.GetDifficulty();

            vm.Expect(pow >= (int)ProofOfWork.Minimal, "expected proof of work");

            vm.ExpectStackSize(1);

            var from = vm.PopAddress();

            vm.Expect(from.IsUser, "address must be user");

            vm.Expect(vm.IsStakeMaster(from), "needs to be master");

            vm.Expect(vm.IsWitness(from), "invalid witness");

            var contractName = vm.PopString("contractName");

            var contractAddress = SmartContract.GetAddressForName(contractName);
            var deployed        = vm.Chain.IsContractDeployed(vm.Storage, contractAddress);

            vm.Expect(deployed, $"{contractName} does not exist");

            byte[]            script;
            ContractInterface abi;

            bool isNative = Nexus.IsNativeContract(contractName);

            vm.Expect(!isNative, "cannot upgrade native contract");

            bool isToken = ValidationUtils.IsValidTicker(contractName);

            script = vm.PopBytes("contractScript");

            var abiBytes = vm.PopBytes("contractABI");

            abi = ContractInterface.FromBytes(abiBytes);

            var fuelCost = vm.GetGovernanceValue(Nexus.FuelPerContractDeployTag);

            // governance value is in usd fiat, here convert from fiat to fuel amount
            fuelCost = vm.GetTokenQuote(DomainSettings.FiatTokenSymbol, DomainSettings.FuelTokenSymbol, fuelCost);

            // burn the "cost" tokens
            vm.BurnTokens(DomainSettings.FuelTokenSymbol, from, fuelCost);

            // ABI validation
            ValidateABI(vm, contractName, abi, isNative);

            SmartContract oldContract;

            if (isToken)
            {
                oldContract = vm.Nexus.GetTokenContract(vm.Storage, contractName);
            }
            else
            {
                oldContract = vm.Chain.GetContractByName(vm.Storage, contractName);
            }

            vm.Expect(oldContract != null, "could not fetch previous contract");
            vm.Expect(abi.Implements(oldContract.ABI), "new abi does not implement all methods of previous abi");
            vm.Expect(vm.InvokeTrigger(false, script, contractName, abi, AccountTrigger.OnUpgrade.ToString(), from) == TriggerResult.Success, "OnUpgrade trigger failed");

            if (isToken)
            {
                vm.Nexus.UpgradeTokenContract(vm.RootStorage, contractName, script, abi);
            }
            else
            {
                vm.Chain.UpgradeContract(vm.Storage, contractName, script, abi);
            }

            vm.Notify(EventKind.ContractUpgrade, from, contractName);

            return(ExecutionState.Running);
        }