diff --git a/contract/AElf.Contracts.Genesis/BasicContractZero.cs b/contract/AElf.Contracts.Genesis/BasicContractZero.cs index 76207e1a62..ceaa6405be 100644 --- a/contract/AElf.Contracts.Genesis/BasicContractZero.cs +++ b/contract/AElf.Contracts.Genesis/BasicContractZero.cs @@ -103,8 +103,15 @@ public override Address DeploySystemSmartContract(SystemContractDeploymentInput var code = input.Code.ToByteArray(); var transactionMethodCallList = input.TransactionMethodCallList; + if (name != null) + Assert(State.NameAddressMapping[name] == null, "contract name has already been registered before"); // Context.Sender should be identical to Genesis contract address before initialization in production - var address = DeploySmartContract(name, category, code, true, Context.Sender, false); + var reg = Extensions.CreateNewSmartContractRegistration(category, code).SetIsSystemContract(true); + AssertContractNotExists(reg.CodeHash); + var address = DeploySmartContractInternal(reg, Context.Sender, name); + + if (name != null) + State.NameAddressMapping[name] = address; if (transactionMethodCallList != null) foreach (var methodCall in transactionMethodCallList.Value) @@ -126,10 +133,10 @@ public override Hash ProposeNewContract(ContractDeploymentInput input) if (input.ContractOperation != null) { ValidateContractOperation(input.ContractOperation, 0, codeHash); - + // Remove one time signer if exists. Signer is only needed for validating signature. RemoveOneTimeSigner(input.ContractOperation.Deployer); - + AssertContractAddressAvailable(input.ContractOperation.Deployer, input.ContractOperation.Salt); } @@ -308,11 +315,16 @@ public override Address DeploySmartContract(ContractDeploymentInput input) var inputHash = CalculateHashFromInput(input); TryClearContractProposingData(inputHash, out var contractProposingInput); - var address = - DeploySmartContract(null, input.Category, input.Code.ToByteArray(), false, - DecideNonSystemContractAuthor(contractProposingInput?.Proposer, Context.Sender), false, - input.ContractOperation?.Deployer, input.ContractOperation?.Salt); - return address; + var reg = Extensions.CreateNewSmartContractRegistration(input.Category, input.Code.ToByteArray()); + AssertContractNotExists(reg.CodeHash); + var author = DecideNonSystemContractAuthor(contractProposingInput?.Proposer, Context.Sender); + if (input.RequiresDeterministicAddress()) + { + return DeploySmartContractInternal(reg, author, input.ContractOperation.Deployer, + input.ContractOperation.Salt); + } + + return DeploySmartContractInternal(reg, author); } public override Address UpdateSmartContract(ContractUpdateInput input) @@ -484,8 +496,12 @@ public override Address PerformDeployUserSmartContract(UserContractDeploymentInp var inputHash = CalculateHashFromInput(input); TryClearContractProposingData(inputHash, out var contractProposingInput); - var address = DeploySmartContract(null, input.Category, input.Code.ToByteArray(), false, - contractProposingInput.Author, true, contractProposingInput.Author, input.Salt); + var reg = Extensions.CreateNewSmartContractRegistration(input.Category, input.Code.ToByteArray()) + .SetIsUserContract(true); + var author = contractProposingInput.Author; + var deployer = contractProposingInput.Author; + var salt = input.Salt; + var address = DeploySmartContractInternal(reg, author, deployer, salt); return address; } diff --git a/contract/AElf.Contracts.Genesis/BasicContractZero_Helper.cs b/contract/AElf.Contracts.Genesis/BasicContractZero_Helper.cs index b82fd27996..81132ade75 100644 --- a/contract/AElf.Contracts.Genesis/BasicContractZero_Helper.cs +++ b/contract/AElf.Contracts.Genesis/BasicContractZero_Helper.cs @@ -12,85 +12,50 @@ namespace AElf.Contracts.Genesis; public partial class BasicContractZero { - private Address DeploySmartContract(Hash name, int category, byte[] code, bool isSystemContract, - Address author, bool isUserContract, Address deployer = null, Hash salt = null) + private void AddCodeHashToList(Hash codeHash) { - if (name != null) - Assert(State.NameAddressMapping[name] == null, "contract name has already been registered before"); - - var codeHash = HashHelper.ComputeFrom(code); - AssertContractNotExists(codeHash); - - long serialNumber; - Address contractAddress; + var contractCodeHashList = + State.ContractCodeHashListMap[Context.CurrentHeight] ?? new ContractCodeHashList(); + contractCodeHashList.Value.Add(codeHash); + State.ContractCodeHashListMap[Context.CurrentHeight] = contractCodeHashList; + } - if (salt == null) - { - serialNumber = State.ContractSerialNumber.Value; - // Increment - State.ContractSerialNumber.Value = serialNumber + 1; - contractAddress = AddressHelper.ComputeContractAddress(Context.ChainId, serialNumber); - } - else - { - serialNumber = 0; - contractAddress = AddressHelper.ComputeContractAddress(deployer, salt); - } + private ContractDeployed DeploySmartContractInternalCore(SmartContractRegistration reg, Address author, + Address contractAddress, long serialNumber, Hash name = null) + { + AssertContractNotExists(reg.CodeHash); Assert(State.ContractInfos[contractAddress] == null, "Contract address exists."); - - var info = new ContractInfo - { - SerialNumber = serialNumber, - Author = author, - Category = category, - CodeHash = codeHash, - IsSystemContract = isSystemContract, - Version = 1, - IsUserContract = isUserContract, - Deployer = deployer - }; - - var reg = new SmartContractRegistration - { - Category = category, - Code = ByteString.CopyFrom(code), - CodeHash = codeHash, - IsSystemContract = info.IsSystemContract, - Version = info.Version, - ContractAddress = contractAddress, - IsUserContract = isUserContract - }; - var contractInfo = Context.DeploySmartContract(contractAddress, reg, name); - info.ContractVersion = contractInfo.ContractVersion; - reg.ContractVersion = info.ContractVersion; + State.ContractInfos[contractAddress] = Extensions.CreateContractInfo(reg, author) + .SetSerialNumber(serialNumber) + .SetContractVersion(contractInfo.ContractVersion); + State.SmartContractRegistrations[reg.CodeHash] = reg.SetContractVersion(contractInfo.ContractVersion); + AddCodeHashToList(reg.CodeHash); - State.ContractInfos[contractAddress] = info; - State.SmartContractRegistrations[reg.CodeHash] = reg; + Context.LogDebug(() => "BasicContractZero - Deployment ContractHash: " + reg.CodeHash.ToHex()); + Context.LogDebug(() => "BasicContractZero - Deployment success: " + contractAddress.ToBase58()); + return Extensions.CreateContractDeployedEvent(reg, contractAddress).SetAuthor(author).SetName(name); + } - Context.Fire(new ContractDeployed - { - CodeHash = codeHash, - Address = contractAddress, - Author = author, - Version = info.Version, - Name = name, - ContractVersion = info.ContractVersion, - Deployer = deployer - }); + private Address DeploySmartContractInternal(SmartContractRegistration reg, Address author, Hash name = null) + { + var serialNumber = State.ContractSerialNumber.Value; + // Increment + State.ContractSerialNumber.Value = serialNumber + 1; + var contractAddress = AddressHelper.ComputeContractAddress(Context.ChainId, serialNumber); - Context.LogDebug(() => "BasicContractZero - Deployment ContractHash: " + codeHash.ToHex()); - Context.LogDebug(() => "BasicContractZero - Deployment success: " + contractAddress.ToBase58()); + Context.Fire(DeploySmartContractInternalCore(reg, author, contractAddress, serialNumber, name)); - if (name != null) - State.NameAddressMapping[name] = contractAddress; + return contractAddress; + } - var contractCodeHashList = - State.ContractCodeHashListMap[Context.CurrentHeight] ?? new ContractCodeHashList(); - contractCodeHashList.Value.Add(codeHash); - State.ContractCodeHashListMap[Context.CurrentHeight] = contractCodeHashList; + private Address DeploySmartContractInternal(SmartContractRegistration reg, Address author, Address deployer, + Hash salt) + { + var contractAddress = AddressHelper.ComputeContractAddress(deployer, salt); + Context.Fire(DeploySmartContractInternalCore(reg, author, contractAddress, 0, null)); return contractAddress; } diff --git a/contract/AElf.Contracts.Genesis/Extensions.cs b/contract/AElf.Contracts.Genesis/Extensions.cs new file mode 100644 index 0000000000..9b4fc3fddd --- /dev/null +++ b/contract/AElf.Contracts.Genesis/Extensions.cs @@ -0,0 +1,116 @@ +using AElf.Standards.ACS0; +using AElf.Types; +using Google.Protobuf; + +namespace AElf.Contracts.Genesis +{ + public static class Extensions + { + public static SmartContractRegistration CreateNewSmartContractRegistration(int category, byte[] code) + { + var codeHash = HashHelper.ComputeFrom(code); + return new SmartContractRegistration + { + Category = category, + Code = ByteString.CopyFrom(code), + CodeHash = codeHash + }; + } + + public static SmartContractRegistration SetIsUserContract(this SmartContractRegistration self, + bool isUserContract) + { + self.IsSystemContract = isUserContract; + return self; + } + + public static SmartContractRegistration SetVersion(this SmartContractRegistration self, int version) + { + self.Version = version; + return self; + } + + public static SmartContractRegistration SetContractVersion(this SmartContractRegistration self, + string contractVersion) + { + self.ContractVersion = contractVersion; + return self; + } + + public static SmartContractRegistration SetIsSystemContract(this SmartContractRegistration self, + bool isSystemContract) + { + self.IsSystemContract = isSystemContract; + return self; + } + + public static ContractInfo CreateContractInfo(SmartContractRegistration reg, Address author) + { + return new ContractInfo + { + Author = author, + Category = reg.Category, + CodeHash = reg.CodeHash, + IsSystemContract = reg.IsSystemContract, + Version = reg.Version, + IsUserContract = reg.IsUserContract + }; + } + + public static ContractInfo SetSerialNumber(this ContractInfo self, long serialNumber) + { + self.SerialNumber = serialNumber; + return self; + } + + public static ContractInfo SetContractVersion(this ContractInfo self, string contractVersion) + { + self.ContractVersion = contractVersion; + return self; + } + + public static ContractDeployed CreateContractDeployedEvent(SmartContractRegistration reg, Address contractAddress) + { + return new ContractDeployed + { + CodeHash = reg.CodeHash, + Version = reg.Version, + Address = contractAddress, + ContractVersion = reg.ContractVersion + }; + } + + public static ContractDeployed SetAuthor(this ContractDeployed self, Address author) + { + self.Author = author; + return self; + } + + public static ContractDeployed SetDeployer(this ContractDeployed self, Address deployer) + { + self.Deployer = deployer; + return self; + } + + public static ContractDeployed SetName(this ContractDeployed self, Hash name) + { + self.Name = name; + return self; + } + + public static bool RequiresDeterministicAddress(this ContractDeploymentInput self) + { + if (self.ContractOperation == null) + { + return false; + } + + if (self.ContractOperation.Salt == null) + { + return false; + } + + return self.ContractOperation.Deployer != null; + } + } +} \ No newline at end of file