diff --git a/Cargo.lock b/Cargo.lock index d10cd2db0..8577fbe39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2309,6 +2309,7 @@ dependencies = [ "dc-primitives", "frame-support", "frame-system", + "pallet-assets", "pallet-balances", "pallet-vesting", "parity-scale-codec", diff --git a/pallet/account-migration/Cargo.toml b/pallet/account-migration/Cargo.toml index ce1ea7764..a993aa93c 100644 --- a/pallet/account-migration/Cargo.toml +++ b/pallet/account-migration/Cargo.toml @@ -22,6 +22,7 @@ dc-primitives = { default-features = false, path = "../../core/primitives" } # substrate frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +pallet-assets = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } pallet-balances = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } pallet-vesting = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } @@ -47,6 +48,7 @@ std = [ # paritytech "frame-support/std", "frame-system/std", + "pallet-assets/std", "pallet-balances/std", "pallet-vesting/std", "sp-core/std", diff --git a/pallet/account-migration/src/lib.rs b/pallet/account-migration/src/lib.rs index 9a297e8e5..3e641e893 100644 --- a/pallet/account-migration/src/lib.rs +++ b/pallet/account-migration/src/lib.rs @@ -54,11 +54,13 @@ use darwinia_staking::Ledger; use dc_primitives::{AccountId as AccountId20, Balance, BlockNumber, Index}; // substrate use frame_support::{ - log, + log, migration, pallet_prelude::*, traits::{Currency, ExistenceRequirement::KeepAlive, LockableCurrency, WithdrawReasons}, + StorageHasher, }; use frame_system::{pallet_prelude::*, AccountInfo}; +use pallet_assets::AssetAccount; use pallet_balances::AccountData; use pallet_vesting::VestingInfo; use sp_core::sr25519::{Public, Signature}; @@ -118,6 +120,14 @@ pub mod pallet { pub type Accounts = StorageMap<_, Blake2_128Concat, AccountId32, AccountInfo>>; + /// [`pallet_asset::AssetAccount`] data. + /// + /// https://github.dev/paritytech/substrate/blob/polkadot-v0.9.30/frame/assets/src/types.rs#L115 + #[pallet::storage] + #[pallet::getter(fn kton_account_of)] + pub type KtonAccounts = + StorageMap<_, Blake2_128Concat, AccountId32, AssetAccount>; + /// [`pallet_vesting::Vesting`] data. /// /// @@ -203,6 +213,54 @@ pub mod pallet { >::insert(to, l); } + if let Some(a) = KtonAccounts::::take(&from) { + frame_system::Pallet::::inc_sufficients(&to); + + migration::put_storage_value( + b"Assets", + b"Account", + &[ + Blake2_128Concat::hash(&1026u64.encode()), + Blake2_128Concat::hash(&to.encode()), + ] + .concat(), + a.encode(), + ); + // The upstream structure cannot be accessed due to permission restrictions. + #[derive(Debug, Encode, Decode)] + pub struct AssetDetails { + pub owner: AccountId20, + pub issuer: AccountId20, + pub admin: AccountId20, + pub freezer: AccountId20, + pub supply: u128, + pub deposit: u128, + pub min_balance: u128, + pub is_sufficient: bool, + pub accounts: u32, + pub sufficients: u32, + pub approvals: u32, + pub is_frozen: bool, + } + + if let Some(mut asset_details) = migration::get_storage_value::( + b"Assets", + b"Asset", + &Blake2_128Concat::hash(&1026u64.encode()), + ) { + asset_details.accounts += 1; + asset_details.sufficients += 1; + + // Fresh to new details + migration::put_storage_value( + b"Assets", + b"Asset", + &Blake2_128Concat::hash(&1026u64.encode()), + asset_details.encode(), + ); + } + } + Self::deposit_event(Event::Migrated { from, to }); Ok(()) diff --git a/tool/state-processor/Cargo.lock b/tool/state-processor/Cargo.lock index c2153177b..36390ca6f 100644 --- a/tool/state-processor/Cargo.lock +++ b/tool/state-processor/Cargo.lock @@ -152,6 +152,18 @@ dependencies = [ "termcolor", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + [[package]] name = "funty" version = "2.0.0" @@ -197,6 +209,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "humantime" version = "1.3.0" @@ -206,6 +224,15 @@ dependencies = [ "quick-error", ] +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + [[package]] name = "impl-trait-for-tuples" version = "0.2.2" @@ -298,6 +325,17 @@ dependencies = [ "log", ] +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + [[package]] name = "proc-macro-crate" version = "1.2.1" @@ -386,6 +424,12 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + [[package]] name = "ryu" version = "1.0.11" @@ -445,6 +489,7 @@ dependencies = [ "once_cell", "parity-scale-codec", "pretty_env_logger", + "primitive-types", "serde", "serde_json", "subhasher", @@ -570,6 +615,18 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unicode-ident" version = "1.0.5" diff --git a/tool/state-processor/Cargo.toml b/tool/state-processor/Cargo.toml index 02e52387d..b12f4dcbe 100644 --- a/tool/state-processor/Cargo.toml +++ b/tool/state-processor/Cargo.toml @@ -13,6 +13,7 @@ log = { version = "0.4" } once_cell = { version = "1.16" } parity-scale-codec = { version = "3.2", features = ["derive"] } pretty_env_logger = { version = "0.4" } +primitive-types = { version = "0.12.1", features = ["codec"] } serde = { version = "1.0" } serde_json = { version = "1.0" } diff --git a/tool/state-processor/src/system/README.md b/tool/state-processor/src/system/README.md index af67521d6..52423c5c3 100644 --- a/tool/state-processor/src/system/README.md +++ b/tool/state-processor/src/system/README.md @@ -19,16 +19,19 @@ - remove para backing account - TODO - check remaining sum - TODO - XCM relate - TODO -- set KTON total issuances - TODO - - compare the calculated one with the storage one - - check remaining sum - TODO +- create KTON asset details - set accounts - if is EVM address + - insert to `Assets::Account` and `Assets::Approvals`(update kton asset details) - insert to `System::Account` - if is Substrate address - reset the nonce - - insert to `AccountMigration::Accounts` - - calculate misc frozen and fee frozen + - insert to `AccountMigration::KtonAccounts` + - insert to `AccountMigration::Accounts`\ +- set KTON total issuances + - compare the calculated one with the storage one + - check remaining sum - TODO +- set `Assets::Metadata` - some remaining accounts, bridge endpoint accounts - TODO - special accounts - TODO diff --git a/tool/state-processor/src/system/mod.rs b/tool/state-processor/src/system/mod.rs index 047917bbe..4441b2bff 100644 --- a/tool/state-processor/src/system/mod.rs +++ b/tool/state-processor/src/system/mod.rs @@ -1,5 +1,6 @@ // darwinia use crate::*; +use subhasher::blake2_128_concat; #[derive(Debug)] pub struct AccountAll { @@ -87,14 +88,24 @@ impl Processor { log::info!("set `Balances::TotalIssuance`"); self.shell_state.insert_value(b"Balances", b"TotalIssuance", "", ring_total_issuance); - log::info!("`kton_total_issuance({kton_total_issuance})`"); - log::info!("`kton_total_issuance_storage({kton_total_issuance_storage})`"); + let mut kton_details = AssetDetails { + owner: ROOT, + issuer: ROOT, + admin: ROOT, + freezer: ROOT, + supply: kton_total_issuance, + deposit: 0, + min_balance: 1, // The same as the value in the runtime. + is_sufficient: true, // The same as the value in the runtime. + sufficients: 0, + accounts: 0, + approvals: 0, + is_frozen: false, + }; - // TODO: set KTON total issuance - - log::info!("update ring misc frozen and fee frozen"); log::info!("set `System::Account`"); log::info!("set `Balances::Locks`"); + log::info!("set `Assets::Account` and `Assets::Approvals`"); accounts.into_iter().for_each(|(k, v)| { let key = get_last_64(&k); let mut a = AccountInfo { @@ -122,20 +133,96 @@ impl Processor { a.sufficients += 1; } + if v.kton != 0 || v.kton_reserved != 0 { + let aa = AssetAccount { + balance: v.kton, + is_frozen: false, + reason: ExistenceReason::Sufficient, + extra: (), + }; + + a.sufficients += 1; + kton_details.accounts += 1; + kton_details.sufficients += 1; + // Note: this is double map structure in the pallet-assets. + self.shell_state.insert_value( + b"Assets", + b"Account", + &format!( + "{}{}", + array_bytes::bytes2hex("", blake2_128_concat(&KTON_ID.encode())), + array_bytes::bytes2hex("", blake2_128_concat(&k.encode())), + ), + &aa, + ); + + // https://github.dev/darwinia-network/darwinia-common/blob/6a9392cfb9fe2c99b1c2b47d0c36125d61991bb7/frame/dvm/evm/precompiles/kton/src/lib.rs#L72 + let mut approves = Map::::default(); + self.solo_state.take_map( + b"KtonERC20", + b"Approves", + &mut approves, + get_hashed_key, + ); + approves.iter().for_each(|(k, v)| { + kton_details.approvals += 1; + self.shell_state.insert_value( + b"Assets", + b"Approvals", + &k, + Approval { amount: v.as_u128(), deposit: 0 }, + ); + }); + } + self.shell_state.insert_value( b"System", b"Account", &blake2_128_concat_to_string(k), a, ); - // TODO: migrate kton balances. } else { a.nonce = 0; + if v.kton != 0 || v.kton_reserved != 0 { + let aa = AssetAccount { + balance: v.kton, + is_frozen: false, + reason: ExistenceReason::Sufficient, + extra: (), + }; + + self.shell_state.insert_value(b"AccountMigration", b"KtonAccounts", &k, &aa); + } + self.shell_state.insert_value(b"AccountMigration", b"Accounts", &k, a); } }); + log::info!("set `Assets::Asset`"); + log::info!("kton_total_issuance({kton_total_issuance})"); + log::info!("kton_total_issuance_storage({kton_total_issuance_storage})"); + self.shell_state.insert_value( + b"Assets", + b"Asset", + &array_bytes::bytes2hex("", blake2_128_concat(&KTON_ID.encode())), + kton_details, + ); + + log::info!("set `Assets::Metadata`"); + self.shell_state.insert_value( + b"Assets", + b"Metadata", + &array_bytes::bytes2hex("", blake2_128_concat(&KTON_ID.encode())), + AssetMetadata { + deposit: 0, + name: b"Darwinia Commitment Token".to_vec(), + symbol: b"KTON".to_vec(), + decimals: 18, + is_frozen: false, + }, + ); + self } diff --git a/tool/state-processor/src/type_registry.rs b/tool/state-processor/src/type_registry.rs index 1f82c7d1d..dd2abf298 100644 --- a/tool/state-processor/src/type_registry.rs +++ b/tool/state-processor/src/type_registry.rs @@ -2,6 +2,9 @@ use parity_scale_codec::{Decode, Encode}; pub const GWEI: u128 = 1_000_000_000; +pub const KTON_ID: u64 = 1026; +// https://github.dev/darwinia-network/darwinia-2.0/blob/c9fdfa170501648102bd0137c0437e367e743770/runtime/common/src/gov_origin.rs#L46 +pub const ROOT: [u8; 20] = [0x72, 0x6f, 0x6f, 0x74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; #[derive(Default, Debug, Encode, Decode)] pub struct AccountInfo { @@ -25,6 +28,7 @@ pub struct BalanceLock { pub amount: u128, pub reasons: Reasons, } + #[allow(clippy::unnecessary_cast)] #[derive(Debug, PartialEq, Eq, Encode, Decode)] pub enum Reasons { @@ -96,3 +100,59 @@ pub struct Ledger { pub unstaking_kton: Vec<(u128, u32)>, pub unstaking_deposits: Vec<(u16, u32)>, } + +// https://github.dev/paritytech/substrate/blob/polkadot-v0.9.30/frame/assets/src/types.rs#L33 +#[derive(Debug, Encode, Decode)] +pub struct AssetDetails { + pub owner: [u8; 20], + pub issuer: [u8; 20], + pub admin: [u8; 20], + pub freezer: [u8; 20], + pub supply: u128, + pub deposit: u128, + pub min_balance: u128, + pub is_sufficient: bool, + pub accounts: u32, + pub sufficients: u32, + pub approvals: u32, + pub is_frozen: bool, +} + +// https://github.dev/paritytech/substrate/blob/polkadot-v0.9.30/frame/assets/src/types.rs#L115 +#[derive(Debug, Encode, Decode)] +pub struct AssetAccount { + pub balance: u128, + pub is_frozen: bool, + pub reason: ExistenceReason, + pub extra: (), +} + +// https://github.dev/paritytech/substrate/blob/polkadot-v0.9.30/frame/assets/src/types.rs#L88 +#[derive(Debug, Encode, Decode)] +pub enum ExistenceReason { + #[codec(index = 0)] + Consumer, + #[codec(index = 1)] + Sufficient, + #[codec(index = 2)] + DepositHeld(u128), + #[codec(index = 3)] + DepositRefunded, +} + +// https://github.dev/paritytech/substrate/blob/polkadot-v0.9.30/frame/assets/src/types.rs#L73 +#[derive(Debug, Encode, Decode)] +pub struct Approval { + pub amount: u128, + pub deposit: u128, +} + +// https://github.dev/paritytech/substrate/blob/polkadot-v0.9.30/frame/assets/src/types.rs#L127 +#[derive(Clone, Encode, Decode)] +pub struct AssetMetadata { + pub deposit: u128, + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub is_frozen: bool, +}