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

introduce unified-accounts feature gating #1186

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 40 additions & 3 deletions docs/accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,45 @@ The Runtime's `Signature` type is configured as [`sp_runtime::MultiSignature`](h
- `Ed25519`
- `ECDSA`

# Native H160 via AccountId20
# Unified Accounts

The second strategy consists of using `fp-account` so that `AccountId20` is the Account type used for `frame_system::pallet::Config::AccountId`.
The second strategy was [originally implemented by Moonbeam](https://docs.moonbeam.network/learn/features/unified-accounts/).
It consists of using `fp-account` so that `AccountId20` is the Account type used for
`frame_system::pallet::Config::AccountId`.

The Runtime's `Signature` type is configured as `EthereumSigner`, which means only `ECDSA` signatures are supported.
The Runtime's `Signature` type is configured as `EthereumSigner`, which means only `ECDSA` signatures are supported.

Frontier's Template will pre-fund several well-known addresses that (mostly) contain the letters "th" in their names to remind you that they are for ethereum-compatible usage. These addresses are derived from Substrate's canonical mnemonic: `bottom drive obey lake curtain smoke basket hold race lonely fit walk`
```
# Alith:
- Address: 0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac
- PrivKey: 0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133

# Baltathar:
- Address: 0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0
- PrivKey: 0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b

# Charleth:
- Address: 0x798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc
- PrivKey: 0x0b6e18cafb6ed99687ec547bd28139cafdd2bffe70e6b688025de6b445aa5c5b

# Dorothy:
- Address: 0x773539d4Ac0e786233D90A233654ccEE26a613D9
- PrivKey: 0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68

# Ethan:
- Address: 0xFf64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB
- PrivKey: 0x7dce9bc8babb68fec1409be38c8e1a52650206a7ed90ff956ae8a6d15eeaaef4

# Faith:
- Address: 0xC0F0f4ab324C46e55D02D0033343B4Be8A55532d
- PrivKey: 0xb9d2ea9a615f3165812e8d44de0d24da9bbd164b65c4f0573e1ce2c8dbd9c8df
```

# Template Runtimes

Frontier provides two different runtimes, one for each strategy.
You can choose which one want to build by using the `--feature` flag. For example:
```
$ cargo build # this builds a runtime with H256 -> H160 mapping
$ cargo build --features unified-accounts # this builds a runtime with Unified Accounts
2 changes: 2 additions & 0 deletions template/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ sp-consensus-aura = { workspace = true, features = ["default"] }
sp-consensus-grandpa = { workspace = true, features = ["default"] }
sp-core = { workspace = true, features = ["default"] }
sp-inherents = { workspace = true, features = ["default"] }
sp-keyring = { workspace = true }
sp-offchain = { workspace = true, features = ["default"] }
sp-runtime = { workspace = true, features = ["default"] }
sp-session = { workspace = true, features = ["default"] }
Expand Down Expand Up @@ -92,6 +93,7 @@ default = [
"sql",
"txpool",
]
unified-accounts = []
rocksdb = [
"sc-cli/rocksdb",
"sc-service/rocksdb",
Expand Down
112 changes: 111 additions & 1 deletion template/node/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,27 @@ use scale_codec::Encode;
// Substrate
use sc_cli::Result;
use sc_client_api::BlockBackend;
use sp_core::{ecdsa, Pair};
#[cfg(feature = "unified-accounts")]
use sp_core::ecdsa;
#[cfg(not(feature = "unified-accounts"))]
use sp_core::sr25519;
use sp_core::Pair;
use sp_inherents::{InherentData, InherentDataProvider};
#[cfg(not(feature = "unified-accounts"))]
use sp_keyring::Sr25519Keyring;
use sp_runtime::{generic::Era, OpaqueExtrinsic, SaturatedConversion};
// Frontier
#[cfg(not(feature = "unified-accounts"))]
use fp_account as _;
#[cfg(feature = "unified-accounts")]
use fp_account::AccountId20;
use frontier_template_runtime::{self as runtime, AccountId, Balance, BalancesCall, SystemCall};
#[cfg(not(feature = "unified-accounts"))]
use hex_literal as _;
#[cfg(feature = "unified-accounts")]
use sp_keyring as _;
#[cfg(not(feature = "unified-accounts"))]
use sp_runtime::AccountId32;

use crate::client::Client;

Expand All @@ -57,6 +72,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder {
"remark"
}

#[cfg(feature = "unified-accounts")]
fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
let acc = ecdsa::Pair::from_string("//Bob", None).expect("static values are valid; qed");
let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic(
Expand All @@ -69,6 +85,20 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder {

Ok(extrinsic)
}

#[cfg(not(feature = "unified-accounts"))]
fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
let acc = Sr25519Keyring::Bob.pair();
let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic(
self.client.as_ref(),
acc,
SystemCall::remark { remark: vec![] }.into(),
nonce,
)
.into();

Ok(extrinsic)
}
}

/// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks.
Expand Down Expand Up @@ -100,6 +130,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder {
"transfer_keep_alive"
}

#[cfg(feature = "unified-accounts")]
fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
let acc = ecdsa::Pair::from_string("//Bob", None).expect("static values are valid; qed");
let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic(
Expand All @@ -116,8 +147,27 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder {

Ok(extrinsic)
}

#[cfg(not(feature = "unified-accounts"))]
fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
let acc = Sr25519Keyring::Bob.pair();
let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic(
self.client.as_ref(),
acc,
BalancesCall::transfer_keep_alive {
dest: self.dest.clone().into(),
value: self.value,
}
.into(),
nonce,
)
.into();

Ok(extrinsic)
}
}

#[cfg(feature = "unified-accounts")]
/// Create a transaction using the given `call`.
///
/// Note: Should only be used for benchmarking.
Expand Down Expand Up @@ -177,6 +227,66 @@ pub fn create_benchmark_extrinsic(
)
}

#[cfg(not(feature = "unified-accounts"))]
/// Create a transaction using the given `call`.
///
/// Note: Should only be used for benchmarking.
pub fn create_benchmark_extrinsic(
client: &Client,
sender: sr25519::Pair,
call: runtime::RuntimeCall,
nonce: u32,
) -> runtime::UncheckedExtrinsic {
let genesis_hash = client
.block_hash(0)
.ok()
.flatten()
.expect("Genesis block exists; qed");
let best_hash = client.chain_info().best_hash;
let best_block = client.chain_info().best_number;

let period = runtime::BlockHashCount::get()
.checked_next_power_of_two()
.map(|c| c / 2)
.unwrap_or(2) as u64;
let extra: runtime::SignedExtra = (
frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
frame_system::CheckTxVersion::<runtime::Runtime>::new(),
frame_system::CheckGenesis::<runtime::Runtime>::new(),
frame_system::CheckMortality::<runtime::Runtime>::from(Era::mortal(
period,
best_block.saturated_into(),
)),
frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
frame_system::CheckWeight::<runtime::Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
);

let raw_payload = runtime::SignedPayload::from_raw(
call.clone(),
extra.clone(),
(
(),
runtime::VERSION.spec_version,
runtime::VERSION.transaction_version,
genesis_hash,
best_hash,
(),
(),
(),
),
);
let signature = raw_payload.using_encoded(|e| sender.sign(e));

runtime::UncheckedExtrinsic::new_signed(
call,
AccountId32::from(sender.public()).into(),
runtime::Signature::Sr25519(signature),
extra,
)
}

/// Generates inherent data for the `benchmark overhead` command.
///
/// Note: Should only be used for benchmarking.
Expand Down
111 changes: 106 additions & 5 deletions template/node/src/chain_spec.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::{collections::BTreeMap, str::FromStr};

#[cfg(feature = "unified-accounts")]
use hex_literal::hex;
use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, str::FromStr};
// Substrate
use sc_chain_spec::{ChainType, Properties};
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_consensus_grandpa::AuthorityId as GrandpaId;
#[allow(unused_imports)]
use sp_core::ecdsa;
#[cfg(not(feature = "unified-accounts"))]
use sp_core::sr25519;
use sp_core::{storage::Storage, Pair, Public, H160, U256};
use sp_runtime::traits::{IdentifyAccount, Verify};
use sp_state_machine::BasicExternalities;
Expand Down Expand Up @@ -56,7 +56,7 @@ pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Pu
type AccountPublic = <Signature as Verify>::Signer;

/// Generate an account ID from seed.
/// For use with `AccountId32`, `dead_code` if `AccountId20`.
/// For use with `AccountId32`, `dead_code` if `unified-accounts`.
#[allow(dead_code)]
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
Expand All @@ -79,6 +79,7 @@ fn properties() -> Properties {

const UNITS: Balance = 1_000_000_000_000_000_000;

#[cfg(feature = "unified-accounts")]
pub fn development_config(enable_manual_seal: Option<bool>) -> DevChainSpec {
let wasm_binary = WASM_BINARY.expect("WASM not available");

Expand Down Expand Up @@ -126,6 +127,53 @@ pub fn development_config(enable_manual_seal: Option<bool>) -> DevChainSpec {
)
}

#[cfg(not(feature = "unified-accounts"))]
pub fn development_config(enable_manual_seal: Option<bool>) -> DevChainSpec {
let wasm_binary = WASM_BINARY.expect("WASM not available");

DevChainSpec::from_genesis(
// Name
"Development",
// ID
"dev",
ChainType::Development,
move || {
DevGenesisExt {
genesis_config: testnet_genesis(
wasm_binary,
// Sudo account
get_account_id_from_seed::<sr25519::Public>("Alice"),
// Pre-funded accounts
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
],
// Initial PoA authorities
vec![authority_keys_from_seed("Alice")],
// Ethereum chain ID
SS58Prefix::get() as u64,
),
enable_manual_seal,
}
},
// Bootnodes
vec![],
// Telemetry
None,
// Protocol ID
None,
// Fork ID
None,
// Properties
Some(properties()),
// Extensions
None,
)
}

#[cfg(feature = "unified-accounts")]
pub fn local_testnet_config() -> ChainSpec {
let wasm_binary = WASM_BINARY.expect("WASM not available");

Expand Down Expand Up @@ -172,6 +220,59 @@ pub fn local_testnet_config() -> ChainSpec {
)
}

#[cfg(not(feature = "unified-accounts"))]
pub fn local_testnet_config() -> ChainSpec {
let wasm_binary = WASM_BINARY.expect("WASM not available");

ChainSpec::from_genesis(
// Name
"Local Testnet",
// ID
"local_testnet",
ChainType::Local,
move || {
testnet_genesis(
wasm_binary,
// Initial PoA authorities
// Sudo account
get_account_id_from_seed::<sr25519::Public>("Alice"),
// Pre-funded accounts
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Charlie"),
get_account_id_from_seed::<sr25519::Public>("Dave"),
get_account_id_from_seed::<sr25519::Public>("Eve"),
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
],
vec![
authority_keys_from_seed("Alice"),
authority_keys_from_seed("Bob"),
],
42,
)
},
// Bootnodes
vec![],
// Telemetry
None,
// Protocol ID
None,
// Fork ID
None,
// Properties
None,
// Extensions
None,
)
}

/// Configure initial storage state for FRAME modules.
fn testnet_genesis(
wasm_binary: &[u8],
Expand Down
1 change: 1 addition & 0 deletions template/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ substrate-wasm-builder = { workspace = true, optional = true }

[features]
default = ["std", "with-rocksdb-weights"]
unified-accounts = []
with-rocksdb-weights = []
with-paritydb-weights = []
std = [
Expand Down
Loading