polygon-edge
polygon-edge copied to clipboard
Custom contract predeployment
Description
This PR adds support for custom SC predeployment.
Changes include
- [ ] Bugfix (non-breaking change that solves an issue)
- [ ] Hotfix (change that solves an urgent issue, and requires immediate attention)
- [x] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (change that is not backwards-compatible and/or changes current functionality)
Checklist
- [x] I have assigned this PR to myself
- [x] I have added at least 1 reviewer
- [x] I have added the relevant labels
- [x] I have updated the official documentation
- [x] I have added sufficient documentation in code
Testing
- [x] I have tested this code with the official test suite
- [x] I have tested this code manually
Manual tests
Manual testing was done with varying Smart Contracts that have different constructor params on a running Edge chain.
Documentation update
Additional comments
Fixes EDGE-491 Fixes EDGE-492
Codecov Report
Merging #536 (9505935) into develop (66897d8) will decrease coverage by
0.40%
. The diff coverage is29.65%
.
:exclamation: Current head 9505935 differs from pull request most recent head 973243a. Consider uploading reports for the commit 973243a to get more accurate results
@@ Coverage Diff @@
## develop #536 +/- ##
===========================================
- Coverage 52.70% 52.30% -0.41%
===========================================
Files 130 132 +2
Lines 17146 17436 +290
===========================================
+ Hits 9037 9120 +83
- Misses 7461 7651 +190
- Partials 648 665 +17
Impacted Files | Coverage Δ | |
---|---|---|
helper/predeployment/predeployment.go | 0.00% <0.00%> (ø) |
|
state/executor.go | 3.86% <0.00%> (-0.08%) |
:arrow_down: |
state/txn.go | 19.76% <0.00%> (-0.10%) |
:arrow_down: |
helper/predeployment/argparser.go | 55.48% <55.48%> (ø) |
|
syncer/client.go | 61.79% <0.00%> (-1.42%) |
:arrow_down: |
:mega: We’re building smart automated test selection to slash your CI/CD build times. Learn more
I tried to pre deploy contract according to the description of the flows in doc https://github.com/maticnetwork/matic-docs/pull/1028.
My contract code is here:
pragma solidity ^0.8.7;
contract Greeter {
struct MyStruct {
string name;
int256 number;
}
MyStruct[] private greetings;
int256[] nums;
string str;
constructor(
MyStruct[] memory myGreetings,
int256[] memory myArgNums,
string memory myStr
) {
for(uint256 i = 0; i < myGreetings.length; i++) {
greetings.push(myGreetings[i]);
}
nums = myArgNums;
str = myStr;
}
function getGreeting(uint256 index) public view returns (MyStruct memory) {
return greetings[index];
}
function getNum(uint256 index) public view returns (int256) {
return nums[index];
}
function getStr() public view returns (string memory) {
return str;
}
}
And the script for predeployment I ran is here:
polygon-edge genesis predeploy --chain ./genesis.json --artifacts-path ./Greeter.json --predeploy-address "0x1110" --constructor-args "[[\"value 1\", 123],[\"value 2\", 456],[\"value 3\", 789]]" --constructor-args "[1,2,3,4]" --constructor-args "hello, world"
(I confirmed I pulled latest commit and build the program before running this command.)
According the section Combination of all types as arguments
in the doc, the way to give arguments into --constructor-args
looks correct.
I tried to fetch contract state after I ran genesis predeploy
command and started nodes.
The script to get contract state is as follows:
import { ethers } from "hardhat";
import { Greeter } from "../types/Greeter";
async function main() {
console.log("Check current contract information");
const greeter = (await ethers.getContractAt(
"Greeter",
"0x0000000000000000000000000000000000001110"
)) as Greeter;
console.log("greetings[0] => ", await greeter.getGreeting(0));
console.log("greetings[1] => ", await greeter.getGreeting(1));
console.log("greetings[2] => ", await greeter.getGreeting(2));
console.log("nums[0] => ", await greeter.getNum(0));
console.log("nums[1] => ", await greeter.getNum(1));
console.log("nums[2] => ", await greeter.getNum(2));
console.log("nums[3] => ", await greeter.getNum(3));
console.log("str => ", await greeter.getStr());
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
But I've got the following result:
Generating typings for: 0 artifacts in dir: types for target: ethers-v5
Successfully generated 3 typings!
Successfully generated 3 typings for external artifacts!
Check current contract information
ProviderError: execution was reverted
at HttpProvider.request (/home/kourin/polygon/polygon_edge/staking-contracts/node_modules/hardhat/src/internal/core/providers/http.ts:49:19)
at LocalAccountsProvider.request (/home/kourin/polygon/polygon_edge/staking-contracts/node_modules/hardhat/src/internal/core/providers/accounts.ts:187:34)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async EthersProviderWrapper.send (/home/kourin/polygon/polygon_edge/staking-contracts/node_modules/@nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)
When I commented out the section of getting struct values, it worked.
// console.log("greetings[0] => ", await greeter.getGreeting(0));
// console.log("greetings[1] => ", await greeter.getGreeting(1));
// console.log("greetings[2] => ", await greeter.getGreeting(2));
console.log("nums[0] => ", await greeter.getNum(0));
console.log("nums[1] => ", await greeter.getNum(1));
console.log("nums[2] => ", await greeter.getNum(2));
console.log("nums[3] => ", await greeter.getNum(3));
console.log("str => ", await greeter.getStr());
...
Generating typings for: 0 artifacts in dir: types for target: ethers-v5
Successfully generated 3 typings!
Successfully generated 3 typings for external artifacts!
Check current contract information
nums[0] => BigNumber { value: "1" }
nums[1] => BigNumber { value: "2" }
nums[2] => BigNumber { value: "3" }
nums[3] => BigNumber { value: "4" }
str => hello, world
This means error happened when getting struct state. You may think the way to get struct state is wrong. But I tried to deploy contract in the normal way with the following script. The arguments of constructor are the same with what I gave in genesis predeploy
command.
import { ContractFactory } from "ethers";
import { ethers } from "hardhat";
import { Greeter } from "../types/Greeter";
async function main() {
console.log("Check current contract information");
const greeterFactory = (await ethers.getContractFactory(
"Greeter",
))
const greeter = await greeterFactory.deploy(
// myGreetings
[
{
name: "value 1",
number: 123,
},
{
name: "value 2",
number: 456,
},
{
name: "value 3",
number: 789
}
],
// myArgNums
[1, 2, 3, 4],
// myStr,
"hello, world"
) as Greeter;
await greeter.deployed()
console.log('Greeter deployed', greeter.address)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
And I got the states correctly:
Generating typings for: 0 artifacts in dir: types for target: ethers-v5
Successfully generated 3 typings!
Successfully generated 3 typings for external artifacts!
Check current contract information
greetings[0] => [
'value 1',
BigNumber { value: "123" },
name: 'value 1',
number: BigNumber { value: "123" }
]
greetings[1] => [
'value 2',
BigNumber { value: "456" },
name: 'value 2',
number: BigNumber { value: "456" }
]
greetings[2] => [
'value 3',
BigNumber { value: "789" },
name: 'value 3',
number: BigNumber { value: "789" }
]
nums[0] => BigNumber { value: "1" }
nums[1] => BigNumber { value: "2" }
nums[2] => BigNumber { value: "3" }
nums[3] => BigNumber { value: "4" }
str => hello, world
Please kindly tell me what is wrong point with this.
https://github.com/0xPolygon/polygon-edge/pull/536#issuecomment-1228292292
Fixed this issue and predeploy function is available with the constructor that takes nested object
contract HRM {
struct Group {
string name;
uint128 number;
bool flag;
}
struct Human {
address addr;
string name;
int128 number;
}
int256 private id;
string private name;
Group[] private groups;
mapping(uint256 => mapping(uint256 => Human)) people;
struct ArgGroup {
string name;
uint128 number;
bool flag;
Human[] people;
}
constructor(
int256 _id,
string memory _name,
ArgGroup[] memory _groups
) {
id = _id;
name = _name;
for (uint256 idx = 0; idx < _groups.length; idx++) {
groups.push(
Group({
name: _groups[idx].name,
number: _groups[idx].number,
flag: _groups[idx].flag
})
);
for (uint256 jdx = 0; jdx < _groups[idx].people.length; jdx++) {
people[idx][jdx] = Human({
addr: _groups[idx].people[jdx].addr,
name: _groups[idx].people[jdx].name,
number: _groups[idx].people[jdx].number
});
}
}
}
}
Rebased back to develop
due to a mistake