diff --git a/Cargo.lock b/Cargo.lock index d8caa07..00a6d07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4709,6 +4709,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", + "pallet-anonymous-account", "pallet-aura", "pallet-balances", "pallet-department-funding", @@ -4947,6 +4948,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.9.0)", ] [[package]] diff --git a/custom-pallets/anonymous-account/Cargo.toml b/custom-pallets/anonymous-account/Cargo.toml index 3000630..1f30c22 100644 --- a/custom-pallets/anonymous-account/Cargo.toml +++ b/custom-pallets/anonymous-account/Cargo.toml @@ -20,6 +20,7 @@ frame-support = { workspace = true } frame-system = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } +sp-std = { workspace = true } [dev-dependencies] diff --git a/custom-pallets/anonymous-account/src/extras.rs b/custom-pallets/anonymous-account/src/extras.rs index 2d1d9cf..f33adb8 100644 --- a/custom-pallets/anonymous-account/src/extras.rs +++ b/custom-pallets/anonymous-account/src/extras.rs @@ -1,7 +1,7 @@ use super::*; +use scale_info::prelude::vec::Vec; use sp_io::hashing::blake2_256; -use sp_runtime::AccountId32; impl Pallet { pub fn update_hash_incrementally(current_hash: [u8; 32], account_id: Vec) -> [u8; 32] { @@ -14,4 +14,11 @@ impl Pallet { // Recalculate the hash with the new account ID blake2_256(&input_data) } + + pub fn get_slice_hash( + department_id: DepartmentId, + slice_number: u32, + ) -> Result<[u8; 32], DispatchError> { + KYCHashes::::get(department_id, slice_number).ok_or(Error::::HashNotFound.into()) + } } diff --git a/custom-pallets/anonymous-account/src/lib.rs b/custom-pallets/anonymous-account/src/lib.rs index 4fee8bf..ec663b6 100644 --- a/custom-pallets/anonymous-account/src/lib.rs +++ b/custom-pallets/anonymous-account/src/lib.rs @@ -18,13 +18,16 @@ pub mod weights; pub use weights::*; pub type DepartmentId = u64; -use sp_runtime::AccountId32; + +use frame_support::pallet_prelude::DispatchError; +use sp_std::collections::btree_set::BTreeSet; #[frame_support::pallet(dev_mode)] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use scale_info::prelude::vec::Vec; #[pallet::pallet] #[pallet::without_storage_info] @@ -47,15 +50,19 @@ pub mod pallet { // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items pub type Something = StorageValue<_, u32>; + #[pallet::storage] + #[pallet::getter(fn kyc_account_ids)] + pub type KYCAccountIds = + StorageMap<_, Blake2_128Concat, DepartmentId, BTreeSet>; + #[pallet::storage] #[pallet::getter(fn kyc_accounts)] pub type KYCAccounts = - StorageMap<_, Blake2_128Concat, DepartmentId, Vec<(T::AccountId, [u8; 64])>>; - + StorageMap<_, Blake2_128Concat, DepartmentId, Vec<(T::AccountId, [u8; 64])>>; // Account Id, signature #[pallet::storage] - #[pallet::getter(fn hash_by_range)] - pub type HashByRange = - StorageMap<_, Blake2_128Concat, (DepartmentId, u32, u32), [u8; 32]>; + #[pallet::getter(fn kyc_hash)] + pub type KYCHashes = + StorageDoubleMap<_, Blake2_128Concat, DepartmentId, Blake2_128Concat, u32, [u8; 32]>; #[pallet::type_value] pub fn DefaultSliceRange() -> u32 { @@ -73,7 +80,16 @@ pub mod pallet { pub enum Event { /// Event documentation should end with an array that provides descriptive names for event /// parameters. [something, who] - SomethingStored { something: u32, who: T::AccountId }, + SomethingStored { + something: u32, + who: T::AccountId, + }, + + EncodeHash { + encode: Vec, + hash: [u8; 32], + account_id: T::AccountId, + }, } // Errors inform users that something went wrong. @@ -84,6 +100,10 @@ pub mod pallet { /// Errors should have helpful documentation associated with them. StorageOverflow, InvalidLength, + AccountAlreadyAdded, + NoAccounts, + IncompleteSlice, + HashNotFound, } // Dispatchable functions allows users to interact with the pallet and invoke state changes. @@ -93,27 +113,89 @@ pub mod pallet { impl Pallet { #[pallet::call_index(0)] #[pallet::weight(0)] + pub fn add_kyc_account( + origin: OriginFor, + department_id: DepartmentId, + signature: [u8; 64], + ) -> DispatchResult { + // ToDo! Check who has kyc. + // Ensure the caller is a signed origin (authenticated user). + let who = ensure_signed(origin)?; + + // Check if the caller (who) has already completed KYC for this department. + KYCAccountIds::::try_mutate(department_id, |account_ids| { + let account_ids = account_ids.get_or_insert_with(BTreeSet::new); + + // Ensure the account is not already in the KYC list. + ensure!(!account_ids.contains(&who), Error::::AccountAlreadyAdded); + + // Add the account ID to the set for quick lookup. + account_ids.insert(who.clone()); + + // Add the full account information to the main storage. + KYCAccounts::::try_mutate(department_id, |accounts| { + let accounts = accounts.get_or_insert_with(Vec::new); + accounts.push((who, signature)); + Ok(()) + }) + }) + } + + #[pallet::call_index(1)] + #[pallet::weight(0)] + pub fn calculate_slice_hash( + origin: OriginFor, + department_id: DepartmentId, + slice_number: u32, + ) -> DispatchResult { + let _ = ensure_signed(origin)?; + let slice_range = Self::slice_range() as usize; + let start_index = (slice_number as usize) * slice_range; + let end_index = start_index + slice_range; + + // Retrieve accounts and ensure the slice exists + let accounts = KYCAccounts::::get(department_id).ok_or(Error::::NoAccounts)?; + ensure!(accounts.len() >= end_index, Error::::IncompleteSlice); + + // Check if the hash for this slice already exists + if KYCHashes::::contains_key(department_id, slice_number) { + return Ok(()); // Hash already exists, no need to recalculate + } + + // Process accounts in the specified slice + let slice = &accounts[start_index..end_index]; + let mut current_hash = [0; 32]; // Initial hash for the slice + + for (account_id, _) in slice { + let encoded_id = account_id.encode(); + current_hash = Self::update_hash_incrementally(current_hash, encoded_id); + } + + // Store the computed hash in storage + KYCHashes::::insert(department_id, slice_number, current_hash); + + Ok(()) + } + + #[pallet::call_index(50)] + #[pallet::weight(0)] pub fn calculate_hash(origin: OriginFor) -> DispatchResult { - // Check that the extrinsic was signed and get the signer. - // This function will return an error if the extrinsic is not signed. - // https://docs.substrate.io/main-docs/build/origins/ let who = ensure_signed(origin)?; - // let account_id_bytes: [u8; 32] = who.encode(); let current_hash: [u8; 32] = [0; 32]; - - // let account_id: AccountId32 = AccountId32::new(account_id_bytes); + let encode = who.clone().encode(); let hash = Self::update_hash_incrementally(current_hash, who.encode()); + Self::deposit_event(Event::EncodeHash { encode, hash, account_id: who }); + // println!("hash {:?}", hash); - // Return a successful DispatchResultWithPostInfo Ok(()) } /// An example dispatchable that may throw a custom error. - #[pallet::call_index(1)] + #[pallet::call_index(51)] #[pallet::weight(T::WeightInfo::cause_error())] pub fn cause_error(origin: OriginFor) -> DispatchResult { let _who = ensure_signed(origin)?; diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index b465148..ab95265 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -17,16 +17,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ - "derive", + "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = [ - "derive", - "serde", + "derive", + "serde", ] } # frame frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false, features = [ - "experimental", + "experimental", ] } frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false } frame-try-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false, optional = true } @@ -44,25 +44,25 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/polkadot-sdk sp-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false } sp-block-builder = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false } sp-consensus-aura = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false, features = [ - "serde", + "serde", ] } sp-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false, features = [ - "serde", + "serde", ] } sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false, features = [ - "serde", + "serde", ] } sp-inherents = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false } sp-offchain = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false } sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false, features = [ - "serde", + "serde", ] } sp-session = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false } sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false } sp-storage = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false } sp-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false } sp-version = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0", default-features = false, features = [ - "serde", + "serde", ] } sp-genesis-builder = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.9.0" } @@ -93,6 +93,7 @@ pallet-positive-externality = { workspace = true } pallet-department-funding = { workspace = true } pallet-project-tips = { workspace = true } pallet-departments = { workspace = true } +pallet-anonymous-account = { workspace = true } profile-validation-runtime-api = { workspace = true } positive-externality-runtime-api = { workspace = true } @@ -106,97 +107,97 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk.git [features] default = ["std"] std = [ - "codec/std", - "scale-info/std", - - "frame-executive/std", - "frame-support/std", - "frame-system-benchmarking?/std", - "frame-system-rpc-runtime-api/std", - "frame-system/std", - - "frame-benchmarking?/std", - "frame-try-runtime?/std", - - "pallet-aura/std", - "pallet-balances/std", - "pallet-grandpa/std", - "pallet-sudo/std", - "pallet-template/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - - "sp-api/std", - "sp-block-builder/std", - "sp-consensus-aura/std", - "sp-consensus-grandpa/std", - "sp-core/std", - "sp-genesis-builder/std", - "sp-inherents/std", - "sp-offchain/std", - "sp-runtime/std", - "sp-session/std", - "sp-std/std", - "sp-storage/std", - "sp-transaction-pool/std", - "sp-version/std", - - "substrate-wasm-builder", - "pallet-insecure-randomness-collective-flip/std", - "pallet-sortition-sum-game/std", - "pallet-schelling-game-shared/std", - "pallet-profile-validation/std", - "pallet-shared-storage/std", - "pallet-positive-externality/std", - "pallet-department-funding/std", - "pallet-project-tips/std", - "profile-validation-runtime-api/std", - "positive-externality-runtime-api/std", - "department-funding-runtime-api/std", - "project-tips-runtime-api/std", + "codec/std", + "scale-info/std", + + "frame-executive/std", + "frame-support/std", + "frame-system-benchmarking?/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + + "frame-benchmarking?/std", + "frame-try-runtime?/std", + + "pallet-aura/std", + "pallet-balances/std", + "pallet-grandpa/std", + "pallet-sudo/std", + "pallet-template/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/std", + "sp-consensus-grandpa/std", + "sp-core/std", + "sp-genesis-builder/std", + "sp-inherents/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-storage/std", + "sp-transaction-pool/std", + "sp-version/std", + + "substrate-wasm-builder", + "pallet-insecure-randomness-collective-flip/std", + "pallet-sortition-sum-game/std", + "pallet-schelling-game-shared/std", + "pallet-profile-validation/std", + "pallet-shared-storage/std", + "pallet-positive-externality/std", + "pallet-department-funding/std", + "pallet-project-tips/std", + "profile-validation-runtime-api/std", + "positive-externality-runtime-api/std", + "department-funding-runtime-api/std", + "project-tips-runtime-api/std", ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-grandpa/runtime-benchmarks", - "pallet-sudo/runtime-benchmarks", - "pallet-template/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "pallet-sortition-sum-game/runtime-benchmarks", - "pallet-schelling-game-shared/runtime-benchmarks", - "pallet-profile-validation/runtime-benchmarks", - "pallet-shared-storage/runtime-benchmarks", - "pallet-positive-externality/runtime-benchmarks", - "pallet-department-funding/runtime-benchmarks", - "pallet-project-tips/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-grandpa/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-template/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "pallet-sortition-sum-game/runtime-benchmarks", + "pallet-schelling-game-shared/runtime-benchmarks", + "pallet-profile-validation/runtime-benchmarks", + "pallet-shared-storage/runtime-benchmarks", + "pallet-positive-externality/runtime-benchmarks", + "pallet-department-funding/runtime-benchmarks", + "pallet-project-tips/runtime-benchmarks", ] try-runtime = [ - "frame-executive/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "frame-try-runtime/try-runtime", - "pallet-aura/try-runtime", - "pallet-balances/try-runtime", - "pallet-grandpa/try-runtime", - "pallet-sudo/try-runtime", - "pallet-template/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-transaction-payment/try-runtime", - "sp-runtime/try-runtime", - "pallet-sortition-sum-game/try-runtime", - "pallet-schelling-game-shared/try-runtime", - "pallet-profile-validation/try-runtime", - "pallet-shared-storage/try-runtime", - "pallet-positive-externality/try-runtime", - "pallet-department-funding/try-runtime", - "pallet-project-tips/try-runtime", + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-aura/try-runtime", + "pallet-balances/try-runtime", + "pallet-grandpa/try-runtime", + "pallet-sudo/try-runtime", + "pallet-template/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", + "sp-runtime/try-runtime", + "pallet-sortition-sum-game/try-runtime", + "pallet-schelling-game-shared/try-runtime", + "pallet-profile-validation/try-runtime", + "pallet-shared-storage/try-runtime", + "pallet-positive-externality/try-runtime", + "pallet-department-funding/try-runtime", + "pallet-project-tips/try-runtime", ] experimental = ["pallet-aura/experimental"] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 89e45a2..cb50db3 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -299,6 +299,11 @@ impl pallet_departments::Config for Runtime { type WeightInfo = pallet_departments::weights::SubstrateWeight; } +impl pallet_anonymous_account::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_anonymous_account::weights::SubstrateWeight; +} + impl pallet_department_funding::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_department_funding::weights::SubstrateWeight; @@ -386,6 +391,9 @@ mod runtime { #[runtime::pallet_index(16)] pub type Departments = pallet_departments; + + #[runtime::pallet_index(17)] + pub type AnonymousAccount = pallet_anonymous_account; } /// The address format for describing accounts.