-
Couldn't load subscription status.
- Fork 81
Integrate T TokenStaking with RandomBeacon #2903
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
05ec8a2 to
8436925
Compare
We integrate RandomBeacon application with TokenStaking contract defined for Threshold Network. The source code is copied from work that was already done for ECDSA Wallets in #2850
We don't want to validate TokenStaking size as it's an external contract that we expect to be deployed separately.
TokenStaking contract expects amounts for slashing to be uint96. This is size of number exceeds the T token total supply enyways and is so big that will fit the slashing amount for sure.
Compile dependencies from external package to use in deployment and tests here.
We will use actual T token implementation instead of this TestToken.
Stores ethers Signer in the Operator instead of just an address to simplify usage.
We use minimumAuthorization parameters instead which is an application specific parameter.
We integrated with TokenStaking defined in Threshold Network's contracts so we can switch our tests to use the proper contracts. We use hardhat deployment fixture `TokenStaking` that is defined in @threshold-network/solidity-contracts to simplify deployment of contracts for tests.
The tests are covered byt the Authorization tests.
8436925 to
043a28f
Compare
TokenStaking contract operates on staking providers addresses. Group members are operators that are internal to RandomBeacon application. We need to map operator addresses to staking provider addresses for seize and slash functions calls.
To have the tests that are more reliable we neeed to ensure unique address is used for each of the roles registered in Token Staking. We need an unique address for 64 group members for each role: owner, staking provider, operator, beneficiary and authorizer. We introduced `unnamedSignersOffset` to specify from which unnamed signer account we should start obtaining signers. This is for a case where we want to pull some other accounts e.g. for third party and don't want to overlap.
getUnnamedSigners returns a signer so it simplifies the way we want to obtain the signer.
It's easier to modify the value in parameters without having to update all the hardcoded places.
We don't want to error on this check.
Our contracts grew to the point where a RandomBeaconStub is problematic to deploy. The RandomBeacon size is fine though. We can safely ignore contract size on deployment in hardhat network as contract size is verified by `contractSizer` and it will alert us if any of the contracts is too big.
We want to have unique signers for operators registration for each of 5 roles. This requires hardhat network configuration account count to be aligned. We want to ensure the configuration is correct and output a meaningfull error if it's not. Without that the test execution fails with an error that doesn't give much clue.
The rewards are calculated based on the multiplier and queue of slashed staking providers. We fix how the expected value is calculated.
We set minimumAuthorization to a value different than unauthorizedSigningSlashingAmount to not have false positive results in tests when the parameters would be confused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First round, more to come.
| .getIDOperators(groupMembers); | ||
|
|
||
| try staking.slash(slashingAmount, groupMembersAddresses) { | ||
| address[] memory stakingProvidersAddresses = new address[]( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to extract this piece of code to the Authorizations library (code snippet below) to reduce transaction costs, but unfortunately, it ended up being even more expensive:
method | min | max | avg
-------------------------------------------------------
submitRelayEntry | 213867 | 3735913 | 1779221
reportRelayEntryTimeout | 3683609 | 3701610 | 3696162
reportUnauthorizedSigning | - | - | 3816486
function operatorsToStakingProviders(
Data storage self,
address[] memory operators
) external returns (address[] memory) {
address[] memory stakingProviders = new address[](operators.length);
for (uint256 i = 0; i < operators.length; i++) {
stakingProviders[i] = self.operatorToStakingProvider[operators[i]];
}
return stakingProviders;
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will need to do some diligence here and figure out where does the cost of gas come from. If it is real TokenStaking or something else. TokenStaking writes to the queue so the cost could increase by 1.2M for a whole group slashed but what we see is an increase by 3.28M for reportUnauthorizedSigning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a group of 100 operators, the total cost of reportUnauthorizedSigning would be 5 726 857. It turns out that:
sortitionPool.getIDOperatorscosts326 864operatorToStakingProviderloop costs249 402tokenStaking.seizecosts4 858 014
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the TokenStaking perspective it's slashingQueue.push that produces such a cost burden. For tokenStaking.seize call mentioned above the slashingQueue.push execution consumes 4 546 619 out of the 4 858 014.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in threshold-network/solidity-contracts#87.
We no longer need this setting as there are no more matches in the tests.
| // unique addresses in staking for each operator. | ||
| accounts: { count: 10 + 5 * 64 }, | ||
| tags: ["local"], | ||
| allowUnlimitedContractSize: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only for RandomBeaconStub, right? It is quite dangerous because we may end up with non-deployable RandomBeacon and not even notice it. Would it be possible to branch-off from this PR, remove this line, and try to make tests passing by, for example, dividing RandomBeaconStub into several per-test stubs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the RandomBeaconStub is problematic. I already tried to reduce the size of the stub in #2906. There is not much room for RandomBeacon to grow as it's 24.091 KB already.
As I mentioned in the commit 90e6594 we're protected by the hardhat-contract-sizer. Whenever we run yarn build the plugin will verify the size of the RandomBeacon.
Would it be possible to branch-off from this PR, remove this line, and try to make tests passing by, for example, dividing RandomBeaconStub into several per-test stubs?
If the contract sizer is not enough in your opinion, I can try slicing the contract.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's try slicing and we'll see where we end up with. I am not a fan of stubs adding a lot of functionality because in the end, we do not know what we are testing - the final contract or stub. On the other hand, having just one stub could (unsure) be better for aggregating gas usage reports by hardhat plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW hardhat-contract-sizer will fail contracts build in case of a too big contract. It means that CI will fail and PR won't be mergeable. See example PR #2912
In keep-network/sortition-pools#149 we discontinued publishing `dev` packages for sortition pools, but use `pre` instead.
For consistency I aliased BeaconInactivity as we do for other Beacon* libraries. Also I gathered aliased imports together to make it prettier.
Some adjustments to tests to make them even more fabulous! 🌟
To be more clear about accounts configuration for tests we defined testConfig object that holds the config and those config are reused in operators registration. Additionally we validate on hardhat test start if the parameters are configured properly.
|
The problem of slashing gas costs mentioned in the PR description is addressed in threshold-network/solidity-contracts#87. |
Refs: #2850
Closes: #2715
Depends on: #2906
This PR integrates Random Beacon with Threshold Network
TokenStakingcontract.It implements functions to let the operator join the sortition pool and update its status in the sortition pool.
StakingStubcontract has been removed and all tests operate on a real TTokenStakingnow.The changes were already implemented in ECDSA Wallets in #2850 and this PR is based on it.
Operators To Staking Providers Mapping
Please note that due to 8e9b2a4 a gas cost of executing functions that call seize and slash grew significantly: