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); }