fix(runtime): FIX-5 governability (pallet-sudo to Root) + FIX-2 StorageVersion (4 pallets)
Build + tests verde (exit 0, runtime 27 tests incl. sudo_pallet_index_12). Verificacion adversarial ultracode (5 skeptics): 4 confirmed + 1 partial. FIX-5 — governability (audit V2-CA1): - pallet-sudo 43.0.0 wired Index 12 (workspace + runtime Cargo.toml + std). - impl pallet_sudo::Config (RuntimeEvent/RuntimeCall/WeightInfo) en configs.rs. - genesis: sudo key en los 3 presets — dev/local=Alice, mainnet=foundation_treasury (NO una dev key; el verificador confirmo que no hay backdoor critico). - Da Root origin -> las dispatchables ensure_root de Governance (add/remove council, mark/unmark advisor, treasury_disbursement) dejan de ser no-invocables. Verificado extremo-a-extremo: sudo() despacha RawOrigin::Root, que es exactamente lo que ensure_root acepta. - Sunset documentado (codigo + doc): sudo -> governance real (pallet-collective/ referenda) ANTES de mainnet. Sudo key unica = riesgo de centralizacion aceptable solo como interim/testnet. FIX-2 — lifecycle (audit V1-H2/V2-CA2): - StorageVersion::new(0) + pallet::storage_version en los 4 pallets (provenance/fees/agent-identity/governance). Aditivo, in-code==on-chain==0, sin migracion forzada. Habilita migraciones futuras. CAVEAT honesto (hallazgo high del red-team, NO defecto de FIX-5/FIX-2): treasury_disbursement solo DECREMENTA un contador u128 (Treasury StorageValue), NO mueve OGC real via pallet_balances. FIX-5 restaura la GOBERNABILIDAD (la dispatchable es invocable), pero mover los 250M reales es FIX-6: anadir type Currency al Config + T::Currency::transfer desde una cuenta-tesoreria derivada (PalletId) + financiarla en genesis + test del free_balance. NO se afirma "tesoreria descongelada de verdad" — solo "gobernabilidad restaurada". PENDIENTE: - FIX-2 AGI key recovery (rotate/revoke/active en agent-identity): diferido — necesita un DC de semantica de recovery #41 (single-sig vs multisig threshold, DID estable vs rota, recovery de agent_chain vacio). No se construye contra spec no-ratificada. - pallet-sudo no en feature runtime-benchmarks (inerte hoy: el runtime no impl el Benchmark API). Follow-up con weights benchmarking. - mainnet Foundation sudo key (FNDT placeholder): David ratifica la key real (multisig) pre-launch Q1 2027 (documentado). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
68fb969875
commit
8a1f779c32
10 files changed
+105
-8
No files matched your search
Generated
+20
-3
@@ -6485,6 +6485,7 @@ dependencies = [
|
|||||||
"pallet-grandpa",
|
"pallet-grandpa",
|
||||||
"pallet-revive",
|
"pallet-revive",
|
||||||
"pallet-session",
|
"pallet-session",
|
||||||
|
"pallet-sudo",
|
||||||
"pallet-timestamp",
|
"pallet-timestamp",
|
||||||
"pallet-transaction-payment",
|
"pallet-transaction-payment",
|
||||||
"pallet-transaction-payment-rpc-runtime-api",
|
"pallet-transaction-payment-rpc-runtime-api",
|
||||||
@@ -6723,6 +6724,22 @@ dependencies = [
|
|||||||
"sp-trie",
|
"sp-trie",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pallet-sudo"
|
||||||
|
version = "43.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a5bd043ab6161ce4a06daab4fb646d6ea09058bb5021607386b5486dd0c6d79"
|
||||||
|
dependencies = [
|
||||||
|
"docify",
|
||||||
|
"frame-benchmarking",
|
||||||
|
"frame-support",
|
||||||
|
"frame-system",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"scale-info",
|
||||||
|
"sp-io 43.0.0",
|
||||||
|
"sp-runtime 44.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet-timestamp"
|
name = "pallet-timestamp"
|
||||||
version = "42.0.0"
|
version = "42.0.0"
|
||||||
@@ -7591,7 +7608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
|
checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"itertools 0.13.0",
|
"itertools 0.14.0",
|
||||||
"log",
|
"log",
|
||||||
"multimap",
|
"multimap",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -7624,7 +7641,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"itertools 0.13.0",
|
"itertools 0.14.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
@@ -7637,7 +7654,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
|
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"itertools 0.13.0",
|
"itertools 0.14.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
|
|||||||
@@ -94,6 +94,12 @@ pallet-grandpa = { version = "43.0.0", default-features = false }
|
|||||||
# FRAME pallets canonical Phase 1.5 — Session rotation per CHN-1 4h epochs (stable2509-3)
|
# FRAME pallets canonical Phase 1.5 — Session rotation per CHN-1 4h epochs (stable2509-3)
|
||||||
pallet-session = { version = "43.0.0", default-features = false }
|
pallet-session = { version = "43.0.0", default-features = false }
|
||||||
|
|
||||||
|
# FIX-5 governability (audit V2-CA1) — pallet-sudo da Root origin para invocar
|
||||||
|
# las dispatchables admin (council/advisor/treasury_disbursement, hoy muertas).
|
||||||
|
# Sunset canonical: sudo → governance real (pallet-collective/referenda) ANTES
|
||||||
|
# de mainnet. Sudo key interim = Foundation multisig humano (stable2509-3).
|
||||||
|
pallet-sudo = { version = "43.0.0", default-features = false }
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Phase 3 — pallet-revive smart contracts per SBS-5 ratified
|
# Phase 3 — pallet-revive smart contracts per SBS-5 ratified
|
||||||
# (supersedes CHN-6 v1.0 → CHN-6 v2.0 PolkaVM + ink! v6 + Solidity)
|
# (supersedes CHN-6 v1.0 → CHN-6 v2.0 PolkaVM + ink! v6 + Solidity)
|
||||||
|
|||||||
@@ -128,7 +128,12 @@ pub mod pallet {
|
|||||||
///
|
///
|
||||||
/// v0.0.24 scaffold: storage layout canonical + Config + Events + Errors +
|
/// v0.0.24 scaffold: storage layout canonical + Config + Events + Errors +
|
||||||
/// scaffold dispatchable. Real impl `register_agent_did` v0.0.26 next slice.
|
/// scaffold dispatchable. Real impl `register_agent_did` v0.0.26 next slice.
|
||||||
|
/// StorageVersion en código (FIX-2 lifecycle, audit V1-H2/V2-CA2): arranca
|
||||||
|
/// en 0 (genesis). Habilita migraciones futuras vía on_chain_storage_version().
|
||||||
|
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
|
#[pallet::storage_version(STORAGE_VERSION)]
|
||||||
pub struct Pallet<T>(_);
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
/// CHN-7 canonical: `Identities<StorageMap<AccountId, AgentIdentity>>` canonical.
|
/// CHN-7 canonical: `Identities<StorageMap<AccountId, AgentIdentity>>` canonical.
|
||||||
|
|||||||
@@ -118,7 +118,12 @@ pub mod pallet {
|
|||||||
/// v0.0.20 scaffold: storage layout canonical + Config + Events + Errors +
|
/// v0.0.20 scaffold: storage layout canonical + Config + Events + Errors +
|
||||||
/// scaffold dispatchable. Real impl wire-up Mathi `OitFeeSchedule` trait
|
/// scaffold dispatchable. Real impl wire-up Mathi `OitFeeSchedule` trait
|
||||||
/// vía Config canonical viene en v0.0.22.
|
/// vía Config canonical viene en v0.0.22.
|
||||||
|
/// StorageVersion en código (FIX-2 lifecycle, audit V1-H2/V2-CA2): arranca
|
||||||
|
/// en 0 (genesis). Habilita migraciones futuras vía on_chain_storage_version().
|
||||||
|
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
|
#[pallet::storage_version(STORAGE_VERSION)]
|
||||||
pub struct Pallet<T>(_);
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
/// PHASE 2.4 canonical: per-account fee history canonical.
|
/// PHASE 2.4 canonical: per-account fee history canonical.
|
||||||
|
|||||||
@@ -222,7 +222,13 @@ pub mod pallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Pallet definition canonical.
|
/// Pallet definition canonical.
|
||||||
|
///
|
||||||
|
/// StorageVersion en código (FIX-2 lifecycle, audit V1-H2/V2-CA2): arranca
|
||||||
|
/// en 0 (genesis). Habilita migraciones futuras vía on_chain_storage_version().
|
||||||
|
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
|
#[pallet::storage_version(STORAGE_VERSION)]
|
||||||
pub struct Pallet<T>(_);
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
/// CHN-4 canonical: `Proposals<StorageMap<ProposalId, Proposal>>` canonical.
|
/// CHN-4 canonical: `Proposals<StorageMap<ProposalId, Proposal>>` canonical.
|
||||||
|
|||||||
@@ -123,7 +123,12 @@ pub mod pallet {
|
|||||||
/// v0.0.15: `AssetAttestation.agent_chain` ahora es `BoundedVec<AccountId,
|
/// v0.0.15: `AssetAttestation.agent_chain` ahora es `BoundedVec<AccountId,
|
||||||
/// ConstU32<10>>` canonical → MaxEncodedLen ahora satisfied canonical →
|
/// ConstU32<10>>` canonical → MaxEncodedLen ahora satisfied canonical →
|
||||||
/// `#[pallet::without_storage_info]` ya NO necesario canonical.
|
/// `#[pallet::without_storage_info]` ya NO necesario canonical.
|
||||||
|
/// StorageVersion en código (FIX-2 lifecycle, audit V1-H2/V2-CA2): arranca
|
||||||
|
/// en 0 (genesis). Habilita migraciones futuras vía on_chain_storage_version().
|
||||||
|
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
|
#[pallet::storage_version(STORAGE_VERSION)]
|
||||||
pub struct Pallet<T>(_);
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
/// PROV-2 canonical: `StorageMap<AssetHash, AssetAttestation>` canonical.
|
/// PROV-2 canonical: `StorageMap<AssetHash, AssetAttestation>` canonical.
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ pallet-aura.workspace = true
|
|||||||
pallet-grandpa.workspace = true
|
pallet-grandpa.workspace = true
|
||||||
pallet-session.workspace = true
|
pallet-session.workspace = true
|
||||||
|
|
||||||
|
# FIX-5 governability v0.0.5x: pallet-sudo wired runtime composition Index 12
|
||||||
|
# (Root origin para dispatchables admin — sunset → governance real pre-mainnet)
|
||||||
|
pallet-sudo.workspace = true
|
||||||
|
|
||||||
# Charon custom pallets Phase 2.x (per DCs)
|
# Charon custom pallets Phase 2.x (per DCs)
|
||||||
# Phase 2.1 v0.0.15: pallet-origin-provenance scaffold canonical wired
|
# Phase 2.1 v0.0.15: pallet-origin-provenance scaffold canonical wired
|
||||||
origin-chain-provenance.workspace = true
|
origin-chain-provenance.workspace = true
|
||||||
@@ -122,6 +126,7 @@ std = [
|
|||||||
"pallet-aura/std",
|
"pallet-aura/std",
|
||||||
"pallet-grandpa/std",
|
"pallet-grandpa/std",
|
||||||
"pallet-session/std",
|
"pallet-session/std",
|
||||||
|
"pallet-sudo/std",
|
||||||
"origin-chain-provenance/std",
|
"origin-chain-provenance/std",
|
||||||
"origin-chain-fees/std",
|
"origin-chain-fees/std",
|
||||||
"origin-chain-agent-identity/std",
|
"origin-chain-agent-identity/std",
|
||||||
|
|||||||
@@ -515,3 +515,21 @@ impl pallet_revive::Config for Runtime {
|
|||||||
type FindAuthor = (); // returns None Slice 3.1 (sin pallet_authorship)
|
type FindAuthor = (); // returns None Slice 3.1 (sin pallet_authorship)
|
||||||
type UnsafeUnstableInterface = ConstBool<false>; // testnet-only feature gate
|
type UnsafeUnstableInterface = ConstBool<false>; // testnet-only feature gate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// pallet_sudo::Config — FIX-5 governability (Root origin, audit V2-CA1)
|
||||||
|
// ============================================================
|
||||||
|
//
|
||||||
|
// La cadena no se gobernaba: las dispatchables admin de Governance (add/remove
|
||||||
|
// council, mark/unmark advisor, treasury_disbursement — todas `ensure_root`)
|
||||||
|
// eran no-invocables sin un Root origin, y la tesorería 250M quedaba congelada.
|
||||||
|
// pallet-sudo provee Root origin canonical vía una sudo key única.
|
||||||
|
//
|
||||||
|
// SUNSET canonical: la sudo key es interim (Foundation multisig humano, seteada
|
||||||
|
// en genesis). ANTES de mainnet se migra a governance real (pallet-collective +
|
||||||
|
// pallet-referenda) y se remueve sudo — la cadena se auto-gobierna sin Root.
|
||||||
|
impl pallet_sudo::Config for Runtime {
|
||||||
|
type RuntimeEvent = RuntimeEvent;
|
||||||
|
type RuntimeCall = RuntimeCall;
|
||||||
|
type WeightInfo = pallet_sudo::weights::SubstrateWeight<Runtime>;
|
||||||
|
}
|
||||||
@@ -199,10 +199,11 @@ fn session_keys_canonical(aura: AuraId, grandpa: GrandpaId) -> SessionKeys {
|
|||||||
fn build_genesis(
|
fn build_genesis(
|
||||||
endowed_accounts: Vec<(ChainAccountId, Balance)>,
|
endowed_accounts: Vec<(ChainAccountId, Balance)>,
|
||||||
validators: Vec<(ChainAccountId, AuraId, GrandpaId)>,
|
validators: Vec<(ChainAccountId, AuraId, GrandpaId)>,
|
||||||
|
sudo_key: ChainAccountId,
|
||||||
) -> RuntimeGenesisConfig {
|
) -> RuntimeGenesisConfig {
|
||||||
use crate::{
|
use crate::{
|
||||||
AuraConfig, BalancesConfig, GrandpaConfig, ReviveConfig, SessionConfig, SystemConfig,
|
AuraConfig, BalancesConfig, GrandpaConfig, ReviveConfig, SessionConfig, SudoConfig,
|
||||||
TransactionPaymentConfig,
|
SystemConfig, TransactionPaymentConfig,
|
||||||
};
|
};
|
||||||
RuntimeGenesisConfig {
|
RuntimeGenesisConfig {
|
||||||
system: SystemConfig::default(),
|
system: SystemConfig::default(),
|
||||||
@@ -239,6 +240,11 @@ fn build_genesis(
|
|||||||
// contracts). Phase 3.x maduración añade dev mapped_accounts canonical
|
// contracts). Phase 3.x maduración añade dev mapped_accounts canonical
|
||||||
// para Alice/Bob testing + genesis contract templates (Slices 3.2-3.6).
|
// para Alice/Bob testing + genesis contract templates (Slices 3.2-3.6).
|
||||||
revive: ReviveConfig::default(),
|
revive: ReviveConfig::default(),
|
||||||
|
// FIX-5 governability: sudo key inicial = Root origin para las
|
||||||
|
// dispatchables admin de Governance (sunset → governance real pre-mainnet).
|
||||||
|
sudo: SudoConfig {
|
||||||
|
key: Some(sudo_key),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,8 +255,9 @@ pub fn development_config_genesis() -> RuntimeGenesisConfig {
|
|||||||
let alice_account = alice_authority.0.clone();
|
let alice_account = alice_authority.0.clone();
|
||||||
|
|
||||||
build_genesis(
|
build_genesis(
|
||||||
vec![(alice_account, 100_000_000_u128 * Ogc::ONE)],
|
vec![(alice_account.clone(), 100_000_000_u128 * Ogc::ONE)],
|
||||||
vec![alice_authority],
|
vec![alice_authority],
|
||||||
|
alice_account, // FIX-5: Alice = sudo key (Root) en dev
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,13 +278,14 @@ pub fn local_testnet_config_genesis() -> RuntimeGenesisConfig {
|
|||||||
|
|
||||||
build_genesis(
|
build_genesis(
|
||||||
vec![
|
vec![
|
||||||
(alice, endowment),
|
(alice.clone(), endowment),
|
||||||
(bob, endowment),
|
(bob, endowment),
|
||||||
(charlie, endowment),
|
(charlie, endowment),
|
||||||
(dave, endowment),
|
(dave, endowment),
|
||||||
(eve, endowment),
|
(eve, endowment),
|
||||||
],
|
],
|
||||||
vec![alice_authority, bob_authority],
|
vec![alice_authority, bob_authority],
|
||||||
|
alice, // FIX-5: Alice = sudo key (Root) en local_testnet
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,12 +325,16 @@ pub fn mainnet_genesis_config_genesis() -> RuntimeGenesisConfig {
|
|||||||
// BM V2 allocation canonical exact: 40/25/15/15/5 → 1B OGC total
|
// BM V2 allocation canonical exact: 40/25/15/15/5 → 1B OGC total
|
||||||
vec![
|
vec![
|
||||||
(ecosystem_pool, ECOSYSTEM_ALLOCATION),
|
(ecosystem_pool, ECOSYSTEM_ALLOCATION),
|
||||||
(foundation_treasury, FOUNDATION_ALLOCATION),
|
(foundation_treasury.clone(), FOUNDATION_ALLOCATION),
|
||||||
(public_sale, PUBLIC_SALE_ALLOCATION),
|
(public_sale, PUBLIC_SALE_ALLOCATION),
|
||||||
(founding_team, FOUNDING_TEAM_ALLOCATION),
|
(founding_team, FOUNDING_TEAM_ALLOCATION),
|
||||||
(exchange_liquidity, EXCHANGE_LIQUIDITY_ALLOCATION),
|
(exchange_liquidity, EXCHANGE_LIQUIDITY_ALLOCATION),
|
||||||
],
|
],
|
||||||
validators,
|
validators,
|
||||||
|
// FIX-5: Foundation Treasury = sudo key interim (Root) en mainnet
|
||||||
|
// (multisig humano). PRE-LAUNCH Q1 2027: David ratifica la key real +
|
||||||
|
// sunset a governance (pallet-collective/referenda).
|
||||||
|
foundation_treasury,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -367,6 +367,15 @@ mod runtime {
|
|||||||
#[runtime::pallet_index(11)]
|
#[runtime::pallet_index(11)]
|
||||||
pub type Revive = pallet_revive::Pallet<Runtime>;
|
pub type Revive = pallet_revive::Pallet<Runtime>;
|
||||||
|
|
||||||
|
/// Sudo pallet (FIX-5 governability per audit V2-CA1). Provee Root origin
|
||||||
|
/// para invocar las dispatchables admin de Governance (add/remove council,
|
||||||
|
/// mark/unmark advisor, treasury_disbursement — todas `ensure_root`, hoy
|
||||||
|
/// no-invocables) + descongela la tesorería 250M. Sunset canonical: sudo →
|
||||||
|
/// governance real (pallet-collective/referenda) ANTES de mainnet. Sudo key
|
||||||
|
/// interim = Foundation multisig humano (genesis).
|
||||||
|
#[runtime::pallet_index(12)]
|
||||||
|
pub type Sudo = pallet_sudo::Pallet<Runtime>;
|
||||||
|
|
||||||
// Substrate pallet-identity DEFERRED canonical (decision empírica
|
// Substrate pallet-identity DEFERRED canonical (decision empírica
|
||||||
// 2026-05-21 documentada en configs.rs). pallet-identity 41.0.0 ReservableCurrency
|
// 2026-05-21 documentada en configs.rs). pallet-identity 41.0.0 ReservableCurrency
|
||||||
// compat work canonical hereda al custom `pallet_agent_identity` Phase 2.7
|
// compat work canonical hereda al custom `pallet_agent_identity` Phase 2.7
|
||||||
@@ -933,6 +942,15 @@ mod tests {
|
|||||||
assert_eq!(<crate::Revive as PalletInfoAccess>::name(), "Revive");
|
assert_eq!(<crate::Revive as PalletInfoAccess>::name(), "Revive");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sudo_pallet_index_12_canonical_governability() {
|
||||||
|
// FIX-5: Sudo=12 (post Revive=11). Root origin para las dispatchables
|
||||||
|
// admin de Governance (audit V2-CA1). Sunset → governance real pre-mainnet.
|
||||||
|
use frame_support::traits::PalletInfoAccess;
|
||||||
|
assert_eq!(<crate::Sudo as PalletInfoAccess>::index(), 12);
|
||||||
|
assert_eq!(<crate::Sudo as PalletInfoAccess>::name(), "Sudo");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn revive_address_mapper_account32_returns_h160_canonical() {
|
fn revive_address_mapper_account32_returns_h160_canonical() {
|
||||||
// AccountId32Mapper canonical: AccountId32 → H160 mapping deterministic.
|
// AccountId32Mapper canonical: AccountId32 → H160 mapping deterministic.
|
||||||
|
|||||||
Reference in new issue
Block a user