Skip to content

Commit

Permalink
introduce unified-accounts feature gating
Browse files Browse the repository at this point in the history
  • Loading branch information
bernardoaraujor committed Sep 6, 2023
1 parent 0383d21 commit 5e6bd90
Show file tree
Hide file tree
Showing 7 changed files with 308 additions and 12 deletions.
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 `unified-accounts` 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 --release # this builds a runtime with H256 -> H160
mapping
$ cargo build --release --features unified-accounts # this build 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

0 comments on commit 5e6bd90

Please sign in to comment.