Skip to content
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

Staking Precompiles #358

Merged
merged 102 commits into from
May 3, 2021
Merged

Staking Precompiles #358

merged 102 commits into from
May 3, 2021

Conversation

JoshOrndorff
Copy link
Contributor

@JoshOrndorff JoshOrndorff commented Apr 15, 2021

This PR adds a precompile to wrap the parachain staking functionality in the EVM. All staking functionality is in a single precompile. This precompile distinguishes what operation to perform by matching a four-byte "function selector" that conforms to solidity conventions. A corresponding solidity interface is provided to enable seamless interaction with users' contracts.

Basically we want to let EVM accounts, including contracts, interact with staking as first-class citizens.

Follow Ups

All follow ups are tracked in Jira Moonbeam-495

  • used_addresses to share between runtime and node instead of duplicating that code
  • put NominationDAO.sol in some other demo repo

Checklist

  • ❌ Does it require a purge of the network?
  • You bumped the runtime version if there are breaking changes in the runtime ?
  • ✔️ Does it require changes in documentation/tutorials ?

Copy link
Contributor

@4meta5 4meta5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM @JoshOrndorff let me know if there is anything else you'd like to be done and, if not, we can merge

@4meta5 4meta5 requested review from crystalin and notlesh April 29, 2021 05:04
Copy link
Contributor Author

@JoshOrndorff JoshOrndorff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple more little things. Please also update the description with links to the followup tickets.

runtime/Cargo.toml Outdated Show resolved Hide resolved
runtime/Cargo.toml Outdated Show resolved Hide resolved
runtime/precompiles/src/JoinCandidatesWrapper.sol Outdated Show resolved Hide resolved
runtime/precompiles/src/NominationDAO.sol Outdated Show resolved Hide resolved
runtime/precompiles/src/NominationDAO.sol Outdated Show resolved Hide resolved
Comment on lines 59 to 64
#[allow(dead_code)]
fn used_addresses() -> impl Iterator<Item = R::AccountId> {
sp_std::vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 256, 511]
.into_iter()
.map(|x| hash(x).into())
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just make sure there is a followup issue for this. Then I'm fine leaving it as it is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These addresses have been updated in master, by the way. We pushed some out to 1024 and I (somewhat arbitrarily) placed sacrifice at 4095.

runtime/precompiles/src/lib.rs Outdated Show resolved Hide resolved
runtime/precompiles/src/staking.rs Outdated Show resolved Hide resolved
runtime/precompiles/src/staking.rs Outdated Show resolved Hide resolved
tests/contracts/sources.ts Show resolved Hide resolved
node/src/chain_spec.rs Outdated Show resolved Hide resolved
runtime/precompiles/src/JoinCandidatesWrapper.sol Outdated Show resolved Hide resolved
runtime/precompiles/src/NominationDAO.sol Outdated Show resolved Hide resolved
runtime/precompiles/src/staking.rs Outdated Show resolved Hide resolved
runtime/precompiles/src/staking.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@notlesh notlesh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking awesome. I have a bunch of nits -- nothing big. I definitely think the logging should be turned down or removed...

node/src/chain_spec.rs Show resolved Hide resolved
// TODO Cleanly fetch the addresses from
// the runtime/moonbeam precompiles and systematically fill them with code
// that will revert if it is called by accident (it shouldn't be because
// it is shadowed by the precompile).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite following this TODO... is it still relevant / should it be done before merging?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we'll do it in a follow-up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a followup makes more sense. There is a design decision to be made. Basically the dilemna is this.

We need to get bogus code under every precompile address. The precompile addresses are codified in the precompiles crate, but the genesis config (which includes the pre-deployed bogus code) is set up here.

So the decision is whether we have the list of addresses in both places (as we do now), or do we call into the precompiles crate to get them somehow. I started sketching that also, but still didn't like it because even the way I sketched it the addresses were still in two places (although at least they were in the same file).

// Now the dispatchables

/// Join the set of collator candidates
function join_candidates(uint256 amount) external;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be nice to document what this amount is (is it 10^-18 units?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it's used below as well, so maybe a comment at the top of the contract...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A better variable name would go a long way. maybe bond_amount. Good news the names don't affect the signatures so we wouldn't have to regenerate them. Agree about the units. Luckily solidity makes this nice with keywords like ether, wei, etc.

Comment on lines 63 to 84
// "42a72461": "at_stake(uint256,address)",
// "289b6ba7": "candidate_bond_less(uint256)",
// "c57bd3a8": "candidate_bond_more(uint256)",
// "96b41b5b": "candidate_pool()",
// "b0c0081f": "collator_commission()",
// "427c3c14": "exit_queue()",
// "767e0450": "go_offline()",
// "d2f73ceb": "go_online()",
// "10db2de9": "inflation_config()",
// "8545c833": "is_candidate(address)",
// "8e5080e7": "is_nominator(address)",
// "8f6d27c7": "is_selected_candidate(address)",
// "ad76ed5a": "join_candidates(uint256)",
// "b7694219": "leave_candidates()",
// "e8d68a37": "leave_nominators()",
// "82f2c8df": "nominate(address,uint256)",
// "f6a52569": "nominator_bond_less(address,uint256)",
// "971d44c8": "nominator_bond_more(address,uint256)",
// "9799b4e7": "points(uint256)",
// "4b65c34b": "revoke_nomination(address)",
// "98807d84": "staked(address)",
// "7b46e61b": "total_selected()"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the goal to have 1:1 wrapper functions for everything exposed from the pallet?

I'm resisting the urge to suggest we could generate this. Oops...

runtime/precompiles/src/staking.rs Outdated Show resolved Hide resolved
runtime/precompiles/src/staking.rs Outdated Show resolved Hide resolved
runtime/precompiles/src/staking.rs Show resolved Hide resolved

//TODO figure out how much gas it costs to check whether you're a collator candidate.
// That function will not naturally be benchmarked because it is not dispatchable
// I guess the heavy part will be one storage read.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be benchmarked -- benchmarking does support non-dispatchables. If we use that strategy to calculate gas, we'll also want to respect weight -> gas mapping here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would only need benchmarking for weight. Then we'll use the weight-gas-mapping at runtime.

@@ -98,6 +98,7 @@ export async function createContract(
return {
rawTx,
contract,
contractAddress,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can get the contract address from the contract object:

contract.options.address

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joelamouche This came from your integration test. I would like to get that test passing. I think it should be passing. Maybe you can take a look together with @4meta5 ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put that test in jira 495 because it wasn't passing and I was trying to reduce the scope to get this PR to a merge-able state. If you need the test in this PR, feel free to add it back and go for it.

Comment on lines 66 to 68
// "96b41b5b": "candidate_pool()",
// "b0c0081f": "collator_commission()",
// "427c3c14": "exit_queue()",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be removing these. If they aren't implemented, we should have followups. Actually having them in the code is more important than here. The code is what is used to generate these signatures.

Copy link
Contributor

@4meta5 4meta5 Apr 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be removing these. Actually having them in the code is more important than here. The code is what is used to generate these signatures.

Why do we want to include them if they're not implemented? It is easy to add them back and generate the right signatures. Moreover, removing the dead code does not effect the other signatures because each signature is independently generated.

If they aren't implemented, we should have followups.

All the followups are tracked in jira 495

@4meta5 4meta5 removed their assignment Apr 29, 2021
Copy link
Contributor Author

@JoshOrndorff JoshOrndorff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. I can't approve since I opened this PR :)

Thanks for getting the integration test working.

@JoshOrndorff JoshOrndorff requested review from notlesh and girazoki May 3, 2021 12:46
@albertov19
Copy link
Contributor

In terms of documentation I think we can do a Page under the Staking tab. We'll get the ball rolling once we can allocate some resources to this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants