-
Notifications
You must be signed in to change notification settings - Fork 395
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added staking EVM precompiles (#425)
- Loading branch information
Showing
8 changed files
with
200 additions
and
13 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
[package] | ||
name = "pallet-precompile-staking" | ||
version = "0.1.0" | ||
authors = ["Stake Technologies <[email protected]>"] | ||
edition = "2018" | ||
license = "Apache-2.0" | ||
homepage = "https://astar.network" | ||
repository = "https://github.com/PlasmNetwork/Astar" | ||
description = "Collator staking EVM precompiles" | ||
|
||
[package.metadata.docs.rs] | ||
targets = ["x86_64-unknown-linux-gnu"] | ||
|
||
[dependencies] | ||
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } | ||
evm = { version="0.30.0", default-features = false } | ||
sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9", default-features = false } | ||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9", default-features = false } | ||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9", default-features = false } | ||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9", default-features = false } | ||
pallet-evm = { git="https://github.com/PlasmNetwork/frontier", branch = "polkadot-v0.9.9", default-features = false } | ||
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9", default-features = false } | ||
pallet-collator-selection = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.9", default-features = false } | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"codec/std", | ||
"evm/std", | ||
"sp-std/std", | ||
"sp-core/std", | ||
"frame-support/std", | ||
"frame-system/std", | ||
"pallet-evm/std", | ||
"pallet-session/std", | ||
"pallet-collator-selection/std", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
pragma solidity >=0.7.0; | ||
|
||
interface Staking { | ||
/* | ||
* @dev Set session keys of function caller. | ||
*/ | ||
function set_keys(bytes calldata keys) external; | ||
|
||
/* | ||
* @dev Removes any session keys of the function caller. | ||
*/ | ||
function purge_keys() external; | ||
|
||
/* | ||
* @dev Register function caller as collation candidate. | ||
* @note Collation staking deposit will be locked. | ||
*/ | ||
function register_as_candidate() external; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
//! Astar collator staking interface. | ||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
use codec::Decode; | ||
use evm::{executor::PrecompileOutput, Context, ExitError, ExitSucceed}; | ||
use frame_support::dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}; | ||
use pallet_evm::{AddressMapping, GasWeightMapping, Precompile}; | ||
use sp_std::{marker::PhantomData, vec::Vec}; | ||
|
||
pub struct Staking<R>(PhantomData<R>); | ||
|
||
impl<R> Staking<R> | ||
where | ||
R: pallet_session::Config + pallet_collator_selection::Config, | ||
R::Call: From<pallet_session::Call<R>> + From<pallet_collator_selection::Call<R>>, | ||
{ | ||
fn set_keys(keys: Vec<u8>) -> Result<R::Call, ExitError> { | ||
let keys = <R as pallet_session::Config>::Keys::decode(&mut &keys[..]) | ||
.map_err(|_| ExitError::Other("Unable to decode session keys".into()))?; | ||
Ok(pallet_session::Call::<R>::set_keys(keys, Default::default()).into()) | ||
} | ||
|
||
fn purge_keys() -> R::Call { | ||
pallet_session::Call::<R>::purge_keys().into() | ||
} | ||
|
||
fn register_as_candidate() -> R::Call { | ||
pallet_collator_selection::Call::<R>::register_as_candidate().into() | ||
} | ||
} | ||
|
||
impl<R> Precompile for Staking<R> | ||
where | ||
R: pallet_evm::Config + pallet_session::Config + pallet_collator_selection::Config, | ||
R::Call: From<pallet_session::Call<R>> | ||
+ From<pallet_collator_selection::Call<R>> | ||
+ Dispatchable<PostInfo = PostDispatchInfo> | ||
+ GetDispatchInfo, | ||
<R::Call as Dispatchable>::Origin: From<Option<R::AccountId>>, | ||
{ | ||
fn execute( | ||
input: &[u8], | ||
target_gas: Option<u64>, | ||
context: &Context, | ||
) -> Result<PrecompileOutput, ExitError> { | ||
const SELECTOR_SIZE_BYTES: usize = 4; | ||
|
||
if input.len() < SELECTOR_SIZE_BYTES { | ||
return Err(ExitError::Other("input length less than 4 bytes".into())); | ||
} | ||
|
||
// ======= Staking.sol:Staking ======= | ||
// Function signatures: | ||
// bcb24ddc: set_keys(bytes) | ||
// 321c9b7a: purge_keys() | ||
// d09b6ba5: register_as_candidate() | ||
let call = match input[0..SELECTOR_SIZE_BYTES] { | ||
[0xbc, 0xb2, 0x4d, 0xdc] => { | ||
if input.len() < SELECTOR_SIZE_BYTES + 32 * 2 { | ||
return Err(ExitError::Other("input length less than 36 bytes".into())); | ||
} | ||
// Low level argument parsing | ||
let len_offset = SELECTOR_SIZE_BYTES + 32; | ||
let keys_offset = len_offset + 32; | ||
let keys_len = sp_core::U256::from_big_endian(&input[len_offset..keys_offset]); | ||
let keys = input[keys_offset..(keys_offset + keys_len.as_usize())].to_vec(); | ||
Self::set_keys(keys)? | ||
} | ||
[0x32, 0x1c, 0x9b, 0x7a] => Self::purge_keys(), | ||
[0xd0, 0x9b, 0x6b, 0xa5] => Self::register_as_candidate(), | ||
_ => { | ||
return Err(ExitError::Other( | ||
"No method at selector given selector".into(), | ||
)) | ||
} | ||
}; | ||
|
||
let info = call.get_dispatch_info(); | ||
if let Some(gas_limit) = target_gas { | ||
let required_gas = R::GasWeightMapping::weight_to_gas(info.weight); | ||
if required_gas > gas_limit { | ||
return Err(ExitError::OutOfGas); | ||
} | ||
} | ||
|
||
let origin = R::AddressMapping::into_account_id(context.caller); | ||
let post_info = call | ||
.dispatch(Some(origin).into()) | ||
.map_err(|_| ExitError::Other("Method call via EVM failed".into()))?; | ||
|
||
let gas_used = | ||
R::GasWeightMapping::weight_to_gas(post_info.actual_weight.unwrap_or(info.weight)); | ||
Ok(PrecompileOutput { | ||
exit_status: ExitSucceed::Stopped, | ||
cost: gas_used, | ||
output: Default::default(), | ||
logs: Default::default(), | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters