From a849024897349ba3be77239951083e4052990630 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 22 Oct 2021 08:28:38 +0200 Subject: [PATCH 01/37] comment out println --- pallets/mining/rewards-allowance/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 931a3ee27..5adbae859 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -1016,7 +1016,7 @@ pub mod pallet { match _mpower_current_u128 { None => { log::error!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); - println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); + // println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); }, Some(x) => { mpower_current_u128 = x; From a58164fe8e69a7f0c04ac0e90400d222bf03f5dc Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 22 Oct 2021 08:34:02 +0200 Subject: [PATCH 02/37] refactor dependencies --- pallets/mining/rewards-allowance/src/lib.rs | 103 ++++++++++---------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 5adbae859..2b288b9e6 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -1,8 +1,55 @@ #![cfg_attr(not(feature = "std"), no_std)] -/// Edit this file to define custom logic or remove it if it is not needed. -/// Learn more about FRAME and the core library of Substrate FRAME pallets: -/// +use log::{warn, info}; +use chrono::{ + NaiveDateTime, +}; +use rand::{seq::SliceRandom, Rng}; +use substrate_fixed::{ + types::{ + extra::U3, + U16F16, + U32F32, + U64F64, + }, + FixedU128, +}; +use codec::{ + Decode, + Encode, + // MaxEncodedLen, +}; +use frame_support::{ + dispatch::DispatchResult, + traits::{ + Currency, + ExistenceRequirement, + }, +}; +use sp_std::{ + convert::{ + TryFrom, + TryInto, + }, + prelude::*, // Imports Vec +}; +use sp_core::{ + sr25519, +}; +use sp_runtime::traits::{ + IdentifyAccount, + One, + Verify, +}; +use pallet_balances::{BalanceLock}; +use module_primitives::{ + types::{ + AccountId, + Balance, + Signature, + }, +}; + pub use pallet::*; #[cfg(test)] @@ -16,55 +63,9 @@ mod tests; #[frame_support::pallet] pub mod pallet { - use log::{warn, info}; - use chrono::{ - NaiveDateTime, - }; - use rand::{seq::SliceRandom, Rng}; - use substrate_fixed::{ - types::{ - extra::U3, - U16F16, - U32F32, - U64F64, - }, - FixedU128, - }; - use codec::{ - Decode, - Encode, - // MaxEncodedLen, - }; - use frame_support::{dispatch::DispatchResult, pallet_prelude::*, - traits::{ - Currency, - ExistenceRequirement, - }, - }; + use super::*; + use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - use sp_std::{ - convert::{ - TryFrom, - TryInto, - }, - prelude::*, // Imports Vec - }; - use sp_core::{ - sr25519, - }; - use sp_runtime::traits::{ - IdentifyAccount, - One, - Verify, - }; - use pallet_balances::{BalanceLock}; - use module_primitives::{ - types::{ - AccountId, - Balance, - Signature, - }, - }; // this is only a default for test purposes and fallback. // set this to 0u128 in production From 2ce1c149237c0f34dc6e6f9d2b816a38d1e7ea28 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 26 Oct 2021 10:03:38 +0200 Subject: [PATCH 03/37] wip --- Cargo.lock | 49 +- pallets/mining/rewards-allowance/Cargo.toml | 4 + pallets/mining/rewards-allowance/src/lib.rs | 736 +++++++++++++++++++- runtime/src/lib.rs | 30 +- 4 files changed, 786 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1f1acee77..3c609d413 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1668,7 +1668,7 @@ dependencies = [ "linregress", "log", "parity-scale-codec", - "paste", + "paste 1.0.5", "sp-api", "sp-io", "sp-runtime", @@ -1754,7 +1754,7 @@ dependencies = [ "log", "once_cell", "parity-scale-codec", - "paste", + "paste 1.0.5", "serde", "smallvec", "sp-arithmetic", @@ -3313,6 +3313,24 @@ dependencies = [ "statrs", ] +[[package]] +name = "lite-json" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0460d985423a026b4d9b828a7c6eed1bcf606f476322f3f9b507529686a61715" +dependencies = [ + "lite-parser", +] + +[[package]] +name = "lite-parser" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c50092e40e0ccd1bf2015a10333fde0502ff95b832b0895dc1ca0d7ac6c52f6" +dependencies = [ + "paste 0.1.18", +] + [[package]] name = "lock_api" version = "0.3.4" @@ -3701,6 +3719,7 @@ dependencies = [ "chrono", "frame-support", "frame-system", + "lite-json", "log", "module-primitives", "pallet-aura", @@ -3722,6 +3741,7 @@ dependencies = [ "sp-consensus-aura", "sp-core", "sp-io", + "sp-keystore", "sp-runtime", "sp-std", "static_assertions", @@ -4831,12 +4851,31 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "paste" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" +dependencies = [ + "paste-impl", + "proc-macro-hack", +] + [[package]] name = "paste" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" +[[package]] +name = "paste-impl" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" +dependencies = [ + "proc-macro-hack", +] + [[package]] name = "pbkdf2" version = "0.4.0" @@ -7212,7 +7251,7 @@ dependencies = [ "approx", "num-complex", "num-traits", - "paste", + "paste 1.0.5", ] [[package]] @@ -7682,7 +7721,7 @@ dependencies = [ "log", "parity-scale-codec", "parity-util-mem", - "paste", + "paste 1.0.5", "rand 0.7.3", "serde", "sp-application-crypto", @@ -8846,7 +8885,7 @@ dependencies = [ "lazy_static", "libc", "log", - "paste", + "paste 1.0.5", "psm", "region", "rustc-demangle", diff --git a/pallets/mining/rewards-allowance/Cargo.toml b/pallets/mining/rewards-allowance/Cargo.toml index 025ba24b7..31a09dbd9 100644 --- a/pallets/mining/rewards-allowance/Cargo.toml +++ b/pallets/mining/rewards-allowance/Cargo.toml @@ -18,6 +18,7 @@ std = [ 'codec/std', 'frame-support/std', 'frame-system/std', + 'lite-json/std', 'pallet-aura/std', 'pallet-balances/std', 'pallet-bounties/std', @@ -34,6 +35,7 @@ std = [ 'sp-consensus-aura/std', 'sp-core/std', 'sp-io/std', + 'sp-keystore/std', 'sp-runtime/std', 'sp-std/std', 'module-primitives/std', @@ -42,6 +44,7 @@ std = [ [dependencies] static_assertions = '1.1.0' chrono = { version = '0.4.19', default_features = false } +lite-json = { version = "0.1", default-features = false } log = { version = '0.4.14', default-features = false } serde = { version = '1.0.126', features = ['derive'] } rand = { version = '0.8.4', default-features = false } @@ -65,6 +68,7 @@ pallet-treasury = { git = 'https://github.com/DataHighway-DHX/substrate', rev = sp-consensus-aura = { git = 'https://github.com/DataHighway-DHX/substrate', rev = 'f5dc02a8a491c149fba05a2a5a51c80ce1b3cead', default-features = false } sp-core = { git = 'https://github.com/DataHighway-DHX/substrate', rev = 'f5dc02a8a491c149fba05a2a5a51c80ce1b3cead', default-features = false } sp-io = { git = 'https://github.com/DataHighway-DHX/substrate', rev = 'f5dc02a8a491c149fba05a2a5a51c80ce1b3cead', default-features = false } +sp-keystore = { git = 'https://github.com/DataHighway-DHX/substrate', rev = 'f5dc02a8a491c149fba05a2a5a51c80ce1b3cead', default-features = false, optional = true } sp-runtime = { git = 'https://github.com/DataHighway-DHX/substrate', rev = 'f5dc02a8a491c149fba05a2a5a51c80ce1b3cead', default-features = false } sp-std = { git = 'https://github.com/DataHighway-DHX/substrate', rev = 'f5dc02a8a491c149fba05a2a5a51c80ce1b3cead', default-features = false } module-primitives = { version = '3.0.6', default-features = false, path = '../../primitives' } diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 2b288b9e6..430b3a9ed 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -1,53 +1,101 @@ +//! +//! # Rewards Allowance with Offchain Worker Pallet +//! +//! TODO - add description +//! +//! Run `cargo doc --package rewards-allowance --open` to view this module's +//! documentation. +//! +//! - [`Config`] +//! - [`Call`] +//! - [`Pallet`] +//! +//! +//! ## Overview +//! +//! Offchain Worker (OCW) will be triggered after every block, fetch the mPower of current +//! of registered DHX users and prepare either signed or unsigned transaction to feed the +//! result back on chain. +//! +//! Additional logic in OCW is put in place to prevent spamming the network with both signed +//! and unsigned transactions, and custom `UnsignedValidator` makes sure that there is only +//! one unsigned transaction floating in the network. +//! +//! The on-chain logic will integrate their mPower values in the calculation of their +//! accumulated and aggregated rewards allowance each day. +//! +//! TODO - add further overview +//! #![cfg_attr(not(feature = "std"), no_std)] -use log::{warn, info}; use chrono::{ NaiveDateTime, }; -use rand::{seq::SliceRandom, Rng}; -use substrate_fixed::{ - types::{ - extra::U3, - U16F16, - U32F32, - U64F64, - }, - FixedU128, -}; use codec::{ Decode, Encode, - // MaxEncodedLen, }; use frame_support::{ dispatch::DispatchResult, traits::{ Currency, ExistenceRequirement, + Get, }, }; -use sp_std::{ - convert::{ - TryFrom, - TryInto, +use frame_system::{ + self as system, + offchain::{ + AppCrypto, CreateSignedTransaction, SendSignedTransaction, SendUnsignedTransaction, + SignedPayload, Signer, SigningTypes, SubmitTransaction, + }, +}; +use lite_json::json::JsonValue; +use log::{warn, info}; +use module_primitives::{ + types::{ + AccountId, + Balance, + Signature, }, - prelude::*, // Imports Vec }; +use pallet_balances::{BalanceLock}; +use rand::{seq::SliceRandom, Rng}; use sp_core::{ + crypto::KeyTypeId, sr25519, }; -use sp_runtime::traits::{ - IdentifyAccount, - One, - Verify, +use sp_runtime::{ + offchain::{ + http, + storage::{MutateStorageError, StorageRetrievalError, StorageValueRef}, + Duration, + }, + transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + traits::{ + IdentifyAccount, + One, + Verify, + Zero, + }, + RuntimeDebug, }; -use pallet_balances::{BalanceLock}; -use module_primitives::{ +use sp_std::{ + convert::{ + TryFrom, + TryInto, + }, + vec::Vec, + // prelude::*, // Imports Vec +}; +use substrate_fixed::{ types::{ - AccountId, - Balance, - Signature, + extra::U3, + U16F16, + U32F32, + U64F64, }, + FixedU128, }; pub use pallet::*; @@ -61,6 +109,48 @@ mod tests; // #[cfg(feature = "runtime-benchmarks")] // mod benchmarking; +/// Defines application identifier for crypto keys of this module. +/// +/// Every module that deals with signatures needs to declare its unique identifier for +/// its crypto keys. +/// When offchain worker is signing transactions it's going to request keys of type +/// `KeyTypeId` from the keystore and use the ones it finds to sign the transaction. +/// The keys can be inserted manually via RPC (see `author_insertKey`). +pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"mpow"); + +/// Based on the above `KeyTypeId` we need to generate a pallet-specific crypto type wrappers. +/// We can use from supported crypto kinds (`sr25519`, `ed25519` and `ecdsa`) and augment +/// the types with this pallet-specific identifier. +pub mod crypto { + use super::KEY_TYPE; + use sp_core::sr25519::Signature as Sr25519Signature; + use sp_runtime::{ + app_crypto::{app_crypto, sr25519}, + traits::Verify, + MultiSigner, + MultiSignature, + }; + app_crypto!(sr25519, KEY_TYPE); + + pub struct TestAuthId; + + // implemented for off-chain workers in runtime + impl frame_system::offchain::AppCrypto for TestAuthId { + type RuntimeAppPublic = Public; + type GenericSignature = sp_core::sr25519::Signature; + type GenericPublic = sp_core::sr25519::Public; + } + + // implemented for mock runtime in test + impl frame_system::offchain::AppCrypto<::Signer, Sr25519Signature> + for TestAuthId + { + type RuntimeAppPublic = Public; + type GenericSignature = sp_core::sr25519::Signature; + type GenericPublic = sp_core::sr25519::Public; + } +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -80,14 +170,68 @@ pub mod pallet { /// Configure the pallet by specifying the parameters and types on which it depends. #[pallet::config] - pub trait Config: frame_system::Config + pub trait Config: CreateSignedTransaction> + + frame_system::Config + pallet_democracy::Config + pallet_balances::Config + pallet_timestamp::Config + pallet_treasury::Config { + /// The identifier type for an offchain worker. + type AuthorityId: AppCrypto; + /// Because this pallet emits events, it depends on the runtime's definition of an event. type Event: From> + IsType<::Event>; + + /// The overarching dispatch call type. + type Call: From>; + type Currency: Currency; + + // Configuration parameters + + /// A grace period after we send transaction. + /// + /// To avoid sending too many transactions, we only attempt to send one + /// every `GRACE_PERIOD` blocks. We use Local Storage to coordinate + /// sending between distinct runs of this offchain worker. + #[pallet::constant] + type GracePeriod: Get; + + /// Number of blocks of cooldown after unsigned transaction is included. + /// + /// This ensures that we only accept unsigned transactions once, every `UnsignedInterval` + /// blocks. + #[pallet::constant] + type UnsignedInterval: Get; + + /// A configuration for base priority of unsigned transactions. + /// + /// This is exposed so that it can be tuned for particular runtime, when + /// multiple pallets send unsigned transactions. + #[pallet::constant] + type UnsignedPriority: Get; + } + + /// Payload used to hold mPower data required to submit a transaction. + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] + pub struct MPowerPayload { + block_number: BlockNumber, + mpower: u32, + public: Public, + } + + impl SignedPayload for MPowerPayload { + fn public(&self) -> T::Public { + self.public.clone() + } + } + + enum TransactionType { + Signed, + UnsignedForAny, + UnsignedForAll, + Raw, + None, } #[pallet::pallet] @@ -256,6 +400,22 @@ pub mod pallet { ), >; + // Offchain workers + + /// Recently submitted mPower data. + #[pallet::storage] + #[pallet::getter(fn mpower)] + pub(super) type MPowerData = StorageValue<_, Vec, ValueQuery>; + + /// Defines the block when next unsigned transaction will be accepted. + /// + /// To prevent spam of unsigned (and unpayed!) transactions on the network, + /// we only allow one transaction every `T::UnsignedInterval` blocks. + /// This storage entry defines when new transaction is going to be accepted. + #[pallet::storage] + #[pallet::getter(fn next_unsigned_at)] + pub(super) type NextUnsignedAt = StorageValue<_, T::BlockNumber, ValueQuery>; + // The genesis config type. #[pallet::genesis_config] pub struct GenesisConfig { @@ -452,6 +612,12 @@ pub mod pallet { /// Storage of new rewards multiplier reset status /// \[new_status] ChangeRewardsMultiplierResetStatusStored(bool), + + // Off-chain workers + + /// Event generated when new mPower data is accepted to contribute to the rewards allowance. + /// \[mpower, who\] + NewMPower(u32, T::AccountId), } // Errors inform users that something went wrong should be descriptive and have helpful documentation @@ -469,6 +635,51 @@ pub mod pallet { // Pallet implements [`Hooks`] trait to define some logic to execute in some context. #[pallet::hooks] impl Hooks> for Pallet { + /// Offchain Worker entry point. + /// + /// By implementing `fn offchain_worker` you declare a new offchain worker. + /// This function will be called when the node is fully synced and a new best block is + /// succesfuly imported. + /// Note that it's not guaranteed for offchain workers to run on EVERY block, there might + /// be cases where some blocks are skipped, or for some the worker runs twice (re-orgs), + /// so the code should be able to handle that. + /// You can use `Local Storage` API to coordinate runs of the worker. + fn offchain_worker(block_number: T::BlockNumber) { + // Note that having logs compiled to WASM may cause the size of the blob to increase + // significantly. You can use `RuntimeDebug` custom derive to hide details of the types + // in WASM. The `sp-api` crate also provides a feature `disable-logging` to disable + // all logging and thus, remove any logging from the WASM. + + // Since off-chain workers are just part of the runtime code, they have direct access + // to the storage and other included pallets. + // + // We can easily import `frame_system` and retrieve a block hash of the parent block. + let parent_hash = >::block_hash(block_number - 1u32.into()); + log::debug!("offchain_workers current block: {:?} (parent hash: {:?})", block_number, parent_hash); + + // Call a helper function that reads storage entries of the current state average_mpower + // and performs a calculation. + let average_mpower: Option = Self::average_mpower(); + log::debug!("offchain_workers average_mpower: {:?}", average_mpower); + + // For this example we are going to send both signed and unsigned transactions + // depending on the block number. + // Usually it's enough to choose one or the other. + let should_send = Self::choose_transaction_type(block_number); + let res = match should_send { + TransactionType::Signed => Self::fetch_mpower_and_send_signed(), + TransactionType::UnsignedForAny => + Self::fetch_mpower_and_send_unsigned_for_any_account(block_number), + TransactionType::UnsignedForAll => + Self::fetch_mpower_and_send_unsigned_for_all_accounts(block_number), + TransactionType::Raw => Self::fetch_mpower_and_send_raw_unsigned(block_number), + TransactionType::None => Ok(()), + }; + if let Err(e) = res { + log::error!("offchain_workers error: {}", e); + } + } + // `on_initialize` is executed at the beginning of the block before any extrinsic are // dispatched. // @@ -2015,8 +2226,108 @@ pub mod pallet { // Return a successful DispatchResultWithPostInfo Ok(()) } + + // Off-chain workers + + /// Submit new mPower data. + /// + /// This method is a public function of the module and can be called from within + /// a transaction. It stores fetched mPower data associated with registered DHX miners + /// under a key that represents the associated date that it relates to. + /// In our example the `offchain worker` will create, sign & submit a transaction that + /// calls this function passing the mPower data. + /// + /// The transaction needs to be signed (see `ensure_signed`) check, so that the caller + /// pays a fee to execute it. + /// This makes sure that it's not easy (or rather cheap) to attack the chain by submitting + /// excessive transactions, but note that it doesn't ensure the mPower oracle is actually + /// working and receives (and provides) meaningful data. + /// + /// TODO - verify the provided mPower to check that it is meaningful data + /// TODO - replace u32 with data structured that contains the account id of each + /// registered DHX miner and their mPower data for a date + /// TODO - specify `weight` for unsigned calls as well, because even though + /// they don't charge fees, we still don't want a single block to contain unlimited + /// number of such transactions. + #[pallet::weight(0)] + pub fn submit_mpower(origin: OriginFor, mpower: u32) -> DispatchResultWithPostInfo { + // Retrieve sender of the transaction. + let who = ensure_signed(origin)?; + // Add mpower on-chain. + Self::add_mpower(who, mpower); + Ok(().into()) + } + + /// Submit new mPower data on-chain via unsigned transaction. + /// + /// Works exactly like the `submit_mpower` function, but since we allow sending the + /// transaction without a signature, and hence without paying any fees, + /// we need a way to make sure that only some transactions are accepted. + /// This function can be called only once every `T::UnsignedInterval` blocks. + /// Transactions that call that function are de-duplicated on the pool level + /// via `validate_unsigned` implementation and also are rendered invalid if + /// the function has already been called in current "session". + #[pallet::weight(0)] + pub fn submit_mpower_unsigned( + origin: OriginFor, + _block_number: T::BlockNumber, + mpower: u32, + ) -> DispatchResultWithPostInfo { + // This ensures that the function can only be called via unsigned transaction. + ensure_none(origin)?; + // Add the mpower on-chain, but mark it as coming from an empty address. + Self::add_mpower(Default::default(), mpower); + // now increment the block number at which we expect next unsigned transaction. + let current_block = >::block_number(); + >::put(current_block + T::UnsignedInterval::get()); + Ok(().into()) + } + + #[pallet::weight(0)] + pub fn submit_mpower_unsigned_with_signed_payload( + origin: OriginFor, + mpower_payload: MPowerPayload, + _signature: T::Signature, + ) -> DispatchResultWithPostInfo { + // This ensures that the function can only be called via unsigned transaction. + ensure_none(origin)?; + // Add the mPower on-chain, but mark it as coming from an empty address. + Self::add_mpower(Default::default(), mpower_payload.mpower); + // now increment the block number at which we expect next unsigned transaction. + let current_block = >::block_number(); + >::put(current_block + T::UnsignedInterval::get()); + Ok(().into()) + } } + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + + /// Validate unsigned call to this module. + /// + /// By default unsigned transactions are disallowed, but implementing the validator + /// here we make sure that some particular calls (the ones produced by offchain worker) + /// are being whitelisted and marked as valid. + fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { + // Firstly let's check that we call the right function. + if let Call::submit_mpower_unsigned_with_signed_payload(ref payload, ref signature) = + call + { + let signature_valid = + SignedPayload::::verify::(payload, signature.clone()); + if !signature_valid { + return InvalidTransaction::BadProof.into() + } + Self::validate_transaction_parameters(&payload.block_number, &payload.mpower) + } else if let Call::submit_mpower_unsigned(block_number, new_mpower) = call { + Self::validate_transaction_parameters(block_number, new_mpower) + } else { + InvalidTransaction::Call.into() + } + } + } + // Private functions impl Pallet { @@ -2279,5 +2590,376 @@ pub mod pallet { // Return a successful DispatchResultWithPostInfo Ok(new_status.clone()) } + + // Offchain workers + + /// Chooses which transaction type to send. + /// + /// This function serves mostly to showcase `StorageValue` helper + /// and local storage usage. + /// + /// Returns a type of transaction that should be produced in current run. + /// + /// TODO - figure out how to effectively use Local Storage and whether to use + /// signed or unsigned transactions + fn choose_transaction_type(block_number: T::BlockNumber) -> TransactionType { + /// A friendlier name for the error that is going to be returned in case we are in the grace + /// period. + const RECENTLY_SENT: () = (); + + // Start off by creating a reference to Local Storage value. + // Since the local storage is common for all offchain workers, it's a good practice + // to prepend your entry with the module name. + let val = StorageValueRef::persistent(b"mpow_ocw::last_send"); + // The Local Storage is persisted and shared between runs of the offchain workers, + // and offchain workers may run concurrently. We can use the `mutate` function, to + // write a storage entry in an atomic fashion. Under the hood it uses `compare_and_set` + // low-level method of local storage API, which means that only one worker + // will be able to "acquire a lock" and send a transaction if multiple workers + // happen to be executed concurrently. + let res = val.mutate(|last_send: Result, StorageRetrievalError>| { + match last_send { + // If we already have a value in storage and the block number is recent enough + // we avoid sending another transaction at this time. + Ok(Some(block)) if block_number < block + T::GracePeriod::get() => + Err(RECENTLY_SENT), + // In every other case we attempt to acquire the lock and send a transaction. + _ => Ok(block_number), + } + }); + + // The result of `mutate` call will give us a nested `Result` type. + // The first one matches the return of the closure passed to `mutate`, i.e. + // if we return `Err` from the closure, we get an `Err` here. + // In case we return `Ok`, here we will have another (inner) `Result` that indicates + // if the value has been set to the storage correctly - i.e. if it wasn't + // written to in the meantime. + match res { + // The value has been set correctly, which means we can safely send a transaction now. + Ok(block_number) => { + // Depending if the block is even or odd we will send a `Signed` or `Unsigned` + // transaction. + // Note that this logic doesn't really guarantee that the transactions will be sent + // in an alternating fashion (i.e. fairly distributed). Depending on the execution + // order and lock acquisition, we may end up for instance sending two `Signed` + // transactions in a row. If a strict order is desired, it's better to use + // the storage entry for that. (for instance store both block number and a flag + // indicating the type of next transaction to send). + let transaction_type = block_number % 3u32.into(); + if transaction_type == Zero::zero() { + TransactionType::Signed + } else if transaction_type == T::BlockNumber::from(1u32) { + TransactionType::UnsignedForAny + } else if transaction_type == T::BlockNumber::from(2u32) { + TransactionType::UnsignedForAll + } else { + TransactionType::Raw + } + }, + // We are in the grace period, we should not send a transaction this time. + Err(MutateStorageError::ValueFunctionFailed(RECENTLY_SENT)) => TransactionType::None, + // We wanted to send a transaction, but failed to write the block number (acquire a + // lock). This indicates that another offchain worker that was running concurrently + // most likely executed the same logic and succeeded at writing to storage. + // Thus we don't really want to send the transaction, knowing that the other run + // already did. + Err(MutateStorageError::ConcurrentModification(_)) => TransactionType::None, + } + } + + /// A helper function to fetch the mpower and send signed transaction. + fn fetch_mpower_and_send_signed() -> Result<(), &'static str> { + let signer = Signer::::all_accounts(); + if !signer.can_sign() { + return Err( + "No local accounts available. Consider adding one via `author_insertKey` RPC.", + )? + } + // Make an external HTTP request to fetch the current mpower data. + // Note this call will block until response is received. + let mpower = Self::fetch_mpower().map_err(|_| "Failed to fetch mpower")?; + + // Using `send_signed_transaction` associated type we create and submit a transaction + // representing the call, we've just created. + // Submit signed will return a vector of results for all accounts that were found in the + // local keystore with expected `KEY_TYPE`. + let results = signer.send_signed_transaction(|_account| { + // Received mpower is wrapped into a call to `submit_mpower` public function of this + // pallet. This means that the transaction, when executed, will simply call that + // function passing `mpower` as an argument. + Call::submit_mpower(mpower) + }); + + for (acc, res) in &results { + match res { + Ok(()) => log::info!("[{:?}] Submitted mpower of {} cents", acc.id, mpower), + Err(e) => log::error!("[{:?}] Failed to submit transaction: {:?}", acc.id, e), + } + } + + Ok(()) + } + + /// A helper function to fetch the mpower and send a raw unsigned transaction. + fn fetch_mpower_and_send_raw_unsigned(block_number: T::BlockNumber) -> Result<(), &'static str> { + // Make sure we don't fetch the mpower if unsigned transaction is going to be rejected + // anyway. + let next_unsigned_at = >::get(); + if next_unsigned_at > block_number { + return Err("Too early to send unsigned transaction") + } + + // Make an external HTTP request to fetch the current mpower. + // Note this call will block until response is received. + let mpower = Self::fetch_mpower().map_err(|_| "Failed to fetch mpower data")?; + + // Received mpower data is wrapped into a call to `submit_mpower_unsigned` public function of this + // pallet. This means that the transaction, when executed, will simply call that function + // passing `mpower` as an argument. + let call = Call::submit_mpower_unsigned(block_number, mpower); + + // Now let's create a transaction out of this call and submit it to the pool. + // Here we showcase two ways to send an unsigned transaction / unsigned payload (raw) + // + // TODO - By default unsigned transactions are disallowed, so we need to whitelist this case + // by writing `UnsignedValidator`. Note that it's EXTREMELY important to carefuly + // implement unsigned validation logic, as any mistakes can lead to opening DoS or spam + // attack vectors. See validation logic docs for more details. + // + SubmitTransaction::>::submit_unsigned_transaction(call.into()) + .map_err(|()| "Unable to submit unsigned transaction.")?; + + Ok(()) + } + + /// A helper function to fetch the mpower, sign payload and send an unsigned transaction + fn fetch_mpower_and_send_unsigned_for_any_account( + block_number: T::BlockNumber, + ) -> Result<(), &'static str> { + // Make sure we don't fetch the mpower if unsigned transaction is going to be rejected anyway. + let next_unsigned_at = >::get(); + if next_unsigned_at > block_number { + return Err("Too early to send unsigned transaction") + } + + // Make an external HTTP request to fetch the current mpower data. + // Note this call will block until response is received. + let mpower = Self::fetch_mpower().map_err(|_| "Failed to fetch mpower data")?; + + // -- Sign using any account + let (_, result) = Signer::::any_account() + .send_unsigned_transaction( + |account| MPowerPayload { mpower, block_number, public: account.public.clone() }, + |payload, signature| { + Call::submit_mpower_unsigned_with_signed_payload(payload, signature) + }, + ) + .ok_or("No local accounts accounts available.")?; + result.map_err(|()| "Unable to submit transaction")?; + + Ok(()) + } + + /// A helper function to fetch the mpower, sign payload and send an unsigned transaction + fn fetch_mpower_and_send_unsigned_for_all_accounts( + block_number: T::BlockNumber, + ) -> Result<(), &'static str> { + // Make sure we don't fetch the mpower if unsigned transaction is going to be rejected anyway. + let next_unsigned_at = >::get(); + if next_unsigned_at > block_number { + return Err("Too early to send unsigned transaction") + } + + // Make an external HTTP request to fetch the current mpower data. + // Note this call will block until response is received. + let mpower = Self::fetch_mpower().map_err(|_| "Failed to fetch mpower")?; + + // Sign using all accounts + // TODO - why would we need to sign using all accounts? + let transaction_results = Signer::::all_accounts() + .send_unsigned_transaction( + |account| MPowerPayload { mpower, block_number, public: account.public.clone() }, + |payload, signature| { + Call::submit_mpower_unsigned_with_signed_payload(payload, signature) + }, + ); + for (_account_id, result) in transaction_results.into_iter() { + if result.is_err() { + return Err("Unable to submit transaction") + } + } + + Ok(()) + } + + /// Fetch current mPower and return the result. + fn fetch_mpower() -> Result { + // We want to keep the offchain worker execution time reasonable, so we set a hard-coded + // deadline to 2s to complete the external call. + // You can also wait idefinitely for the response, however you may still get a timeout + // coming from the host machine. + let deadline = sp_io::offchain::timestamp().add(Duration::from_millis(2_000)); + // Initiate an external HTTP GET request. + // This is using high-level wrappers from `sp_runtime`, for the low-level calls that + // you can find in `sp_io`. The API is trying to be similar to `reqwest`, but + // since we are running in a custom WASM execution environment we can't simply + // import the library here. + let request = + http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); + // We set the deadline for sending of the request, note that awaiting response can + // have a separate deadline. Next we send the request, before that it's also possible + // to alter request headers or stream body content in case of non-GET requests. + let pending = request.deadline(deadline).send().map_err(|_| http::Error::IoError)?; + + // The request is already being processed by the host, we are free to do anything + // else in the worker (we can send multiple concurrent requests too). + // At some point however we probably want to check the response though, + // so we can block current thread and wait for it to finish. + // Note that since the request is being driven by the host, we don't have to wait + // for the request to have it complete, we will just not read the response. + let response = pending.try_wait(deadline).map_err(|_| http::Error::DeadlineReached)??; + // Let's check the status code before we proceed to reading the response. + if response.code != 200 { + log::warn!("Unexpected status code: {}", response.code); + return Err(http::Error::Unknown) + } + + // Next we want to fully read the response body and collect it to a vector of bytes. + // Note that the return object allows you to read the body in chunks as well + // with a way to control the deadline. + let body = response.body().collect::>(); + + // Create a str slice from the body. + let body_str = sp_std::str::from_utf8(&body).map_err(|_| { + log::warn!("No UTF8 body"); + http::Error::Unknown + })?; + + let mpower = match Self::parse_mpower(body_str) { + Some(mpower) => Ok(mpower), + None => { + log::warn!("Unable to extract mpower from the response: {:?}", body_str); + Err(http::Error::Unknown) + }, + }?; + + log::warn!("Got mpower: {:?}", mpower); + + Ok(mpower) + } + + /// Parse the mPower from the given JSON string using `lite-json`. + /// + /// Returns `None` when parsing failed or `Some(mPower)` when parsing is successful. + fn parse_mpower(mpower_str: &str) -> Option { + let val = lite_json::parse_json(mpower_str); + + // TODO - parse for mPower data and replace hard-coded response with output + + // let mpower = match val.ok()? { + // JsonValue::Object(obj) => { + // let (_, v) = obj.into_iter().find(|(k, _)| k.iter().copied().eq("USD".chars()))?; + // match v { + // JsonValue::Number(number) => number, + // _ => return None, + // } + // }, + // _ => return None, + // }; + + // let exp = mpower.fraction_length.checked_sub(2).unwrap_or(0); + // Some(mpower.integer as u32 * 100 + (mpower.fraction / 10_u64.pow(exp)) as u32) + Some(0u32) + } + + /// Add new mPower on-chain. + fn add_mpower(who: T::AccountId, mpower: u32) { + log::info!("Adding mPower to storage: {}", mpower); + + // TODO - add mPower data to storage + + // >::mutate(|mpowers| { + // const MAX_LEN: usize = 64; + + // if mpowers.len() < MAX_LEN { + // mpowers.push(mpower); + // } else { + // mpowers[mpower as usize % MAX_LEN] = mpower; + // } + // }); + + // let average = Self::average_mpower() + // .expect("The average is not empty, because it was just mutated; qed"); + // log::info!("Current average mpower is: {}", average); + // here we are raising the NewPrice event + + Self::deposit_event(Event::NewMPower(mpower, who)); + } + + /// Calculation based on mPower. + fn average_mpower() -> Option { + let mpowers = >::get(); + + // TODO - implement what we need and replace hard-coded response with output + + // if mpowers.is_empty() { + // None + // } else { + // Some(mpowers.iter().fold(0_u32, |a, b| a.saturating_add(*b)) / mpowers.len() as u32) + // } + None + } + + fn validate_transaction_parameters( + block_number: &T::BlockNumber, + new_mpower: &u32, + ) -> TransactionValidity { + // Now let's check if the transaction has any chance to succeed. + let next_unsigned_at = >::get(); + if &next_unsigned_at > block_number { + return InvalidTransaction::Stale.into() + } + // Let's make sure to reject transactions from the future. + let current_block = >::block_number(); + if ¤t_block < block_number { + return InvalidTransaction::Future.into() + } + + // We prioritize transactions that are more far away from current average. + // + // Note this doesn't make much sense when building an actual oracle, but this example + // is here mostly to show off offchain workers capabilities, not about building an + // oracle. + let avg_mpower = Self::average_mpower() + .map(|mpower| if &mpower > new_mpower { mpower - new_mpower } else { new_mpower - mpower }) + .unwrap_or(0); + + ValidTransaction::with_tag_prefix("MPowerOffchainWorker") + // We set base priority to 2**20 and hope it's included before any other + // transactions in the pool. Next we tweak the priority depending on how much + // it differs from the current average. (the more it differs the more priority it + // has). + .priority(T::UnsignedPriority::get().saturating_add(avg_mpower as _)) + // This transaction does not require anything else to go before into the pool. + // In theory we could require `previous_unsigned_at` transaction to go first, + // but it's not necessary in our case. + //.and_requires() + // We set the `provides` tag to be the same as `next_unsigned_at`. This makes + // sure only one transaction produced after `next_unsigned_at` will ever + // get to the transaction pool and will end up in the block. + // We can still have multiple transactions compete for the same "spot", + // and the one with higher priority will replace other one in the pool. + .and_provides(next_unsigned_at) + // The transaction is only valid for next 5 blocks. After that it's + // going to be revalidated by the pool. + .longevity(5) + // It's fine to propagate that transaction to other peers, which means it can be + // created even by nodes that don't produce blocks. + // Note that sometimes it's better to keep it for yourself (if you are the block + // producer), since for instance in some schemes others may copy your solution and + // claim a reward. + .propagate(true) + .build() + } } } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 92063b768..4e6232b8a 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -7,6 +7,11 @@ use codec::{ Decode, Encode, }; +use mining_rewards_allowance::{ + crypto::{ + TestAuthId, + }, +}; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use pallet_grandpa::{ fg_primitives, @@ -1146,9 +1151,32 @@ impl mining_execution_token::Config for Runtime { type MiningExecutionTokenIndex = u64; } +// pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test"); + +// pub mod sr25519 { +// mod app_sr25519 { +// use super::super::TEST_KEY_TYPE_ID; +// use app_crypto::{app_crypto, sr25519}; +// app_crypto!(sr25519, TEST_KEY_TYPE_ID); +// } + +// pub type AuthorityId = app_sr25519::Public; +// } + +parameter_types! { + pub const GracePeriod: BlockNumber = 1 * MINUTES; + pub const UnsignedInterval: BlockNumber = 1 * MINUTES; + pub const UnsignedPriority: BlockNumber = 1 * MINUTES; +} + impl mining_rewards_allowance::Config for Runtime { - type Event = Event; + type AuthorityId = TestAuthId; + type Call = Call; type Currency = Balances; + type Event = Event; + type GracePeriod = GracePeriod; + type UnsignedInterval = UnsignedInterval; + type UnsignedPriority = UnsignedPriority; } impl exchange_rate::Config for Runtime { From a7bb57cbab657e7b1a46900c9e31b9358bf35de8 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 5 Nov 2021 03:37:03 +0100 Subject: [PATCH 04/37] wip --- pallets/mining/rewards-allowance/src/lib.rs | 512 ++++++++------------ runtime/src/lib.rs | 3 +- 2 files changed, 205 insertions(+), 310 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 430b3a9ed..410201265 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -46,8 +46,7 @@ use frame_support::{ use frame_system::{ self as system, offchain::{ - AppCrypto, CreateSignedTransaction, SendSignedTransaction, SendUnsignedTransaction, - SignedPayload, Signer, SigningTypes, SubmitTransaction, + AppCrypto, CreateSignedTransaction, SendUnsignedTransaction, Signer, SubmitTransaction, }, }; use lite_json::json::JsonValue; @@ -176,8 +175,6 @@ pub mod pallet { + pallet_balances::Config + pallet_timestamp::Config + pallet_treasury::Config { - /// The identifier type for an offchain worker. - type AuthorityId: AppCrypto; /// Because this pallet emits events, it depends on the runtime's definition of an event. type Event: From> + IsType<::Event>; @@ -213,23 +210,23 @@ pub mod pallet { } /// Payload used to hold mPower data required to submit a transaction. - #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] - pub struct MPowerPayload { - block_number: BlockNumber, - mpower: u32, - public: Public, + #[cfg_attr(feature = "std", derive(Debug))] + #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)] + pub struct MPowerPayload { + pub account_id_registered_dhx_miner: U, + pub mpower_registered_dhx_miner: V, + pub received_at_date: W, + pub received_at_block_number: X, } - impl SignedPayload for MPowerPayload { - fn public(&self) -> T::Public { - self.public.clone() - } - } + type MPowerPayloadData = MPowerPayload< + ::AccountId, + u128, + Date, + ::BlockNumber, + >; enum TransactionType { - Signed, - UnsignedForAny, - UnsignedForAll, Raw, None, } @@ -254,16 +251,6 @@ pub mod pallet { BalanceOf, >; - #[pallet::storage] - #[pallet::getter(fn mpower_of_account_for_date)] - pub(super) type MPowerForAccountForDate = StorageMap<_, Blake2_128Concat, - ( - Date, - T::AccountId, - ), - u128, - >; - #[pallet::storage] #[pallet::getter(fn rewards_allowance_dhx_for_date_remaining)] pub(super) type RewardsAllowanceDHXForDateRemaining = StorageMap<_, Blake2_128Concat, @@ -402,10 +389,20 @@ pub mod pallet { // Offchain workers - /// Recently submitted mPower data. - #[pallet::storage] - #[pallet::getter(fn mpower)] - pub(super) type MPowerData = StorageValue<_, Vec, ValueQuery>; + /// Recently submitted mPower data. + #[pallet::storage] + #[pallet::getter(fn mpower_of_account_for_date)] + pub(super) type MPowerForAccountForDate = StorageMap<_, Blake2_128Concat, + ( + Date, // converted to start of date + T::AccountId, + ), + ( + u128, // mPower + Date, // date received using off-chain workers + T::BlockNumber, // block receive dusing off-chain workers + ), + >; /// Defines the block when next unsigned transaction will be accepted. /// @@ -540,7 +537,8 @@ pub mod pallet { T::AccountId = "AccountId", BondedData = "BondedData", BalanceOf = "BalanceOf", - T::AccountId = "Date" + T::AccountId = "Date", + T::BlockNumber = "BlockNumber", )] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -568,7 +566,7 @@ pub mod pallet { /// Storage of the mPower of an account on a specific date. /// \[date, amount_mpower, account\] - SetMPowerOfAccountForDateStored(Date, u128, T::AccountId), + SetMPowerOfAccountForDateStored(Date, T::AccountId, u128, Date, T::BlockNumber), /// Storage of the default daily reward allowance in DHX by an origin account. /// \[amount_dhx, sender\] @@ -616,8 +614,8 @@ pub mod pallet { // Off-chain workers /// Event generated when new mPower data is accepted to contribute to the rewards allowance. - /// \[mpower, who\] - NewMPower(u32, T::AccountId), + /// \[start_date_received, registered_dhx_miner_account_id, mpower, date_received_offchain, block_received_offchain\] + NewMPowerForAccountForDate(Date, T::AccountId, u128, Date, T::BlockNumber), } // Errors inform users that something went wrong should be descriptive and have helpful documentation @@ -659,19 +657,12 @@ pub mod pallet { // Call a helper function that reads storage entries of the current state average_mpower // and performs a calculation. - let average_mpower: Option = Self::average_mpower(); + let average_mpower: Option = Self::average_mpower(); log::debug!("offchain_workers average_mpower: {:?}", average_mpower); - // For this example we are going to send both signed and unsigned transactions - // depending on the block number. - // Usually it's enough to choose one or the other. + // We are going to send unsigned transactions let should_send = Self::choose_transaction_type(block_number); let res = match should_send { - TransactionType::Signed => Self::fetch_mpower_and_send_signed(), - TransactionType::UnsignedForAny => - Self::fetch_mpower_and_send_unsigned_for_any_account(block_number), - TransactionType::UnsignedForAll => - Self::fetch_mpower_and_send_unsigned_for_all_accounts(block_number), TransactionType::Raw => Self::fetch_mpower_and_send_raw_unsigned(block_number), TransactionType::None => Ok(()), }; @@ -1224,8 +1215,14 @@ pub mod pallet { // TODO - fetch the mPower of the miner currently being iterated to check if it's greater than the min. // mPower that is required let mut mpower_current_u128: u128 = 0u128; - let _mpower_current_u128 = >::get((start_of_requested_date_millis.clone(), miner.clone())); - match _mpower_current_u128 { + // let _mpower_current_u128 = >::get((start_of_requested_date_millis.clone(), miner.clone())); + // FIXME - this is temporary + let _mpower_data = ( + Some(0u128), + start_of_requested_date_millis.clone(), + 1u64, + ); + match _mpower_data.0 { None => { log::error!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); // println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); @@ -2229,75 +2226,37 @@ pub mod pallet { // Off-chain workers - /// Submit new mPower data. - /// - /// This method is a public function of the module and can be called from within - /// a transaction. It stores fetched mPower data associated with registered DHX miners - /// under a key that represents the associated date that it relates to. - /// In our example the `offchain worker` will create, sign & submit a transaction that - /// calls this function passing the mPower data. - /// - /// The transaction needs to be signed (see `ensure_signed`) check, so that the caller - /// pays a fee to execute it. - /// This makes sure that it's not easy (or rather cheap) to attack the chain by submitting - /// excessive transactions, but note that it doesn't ensure the mPower oracle is actually - /// working and receives (and provides) meaningful data. + /// Submit new mPower data on-chain via unsigned transaction. + /// + /// Works exactly like the `submit_mpower` function, but since we allow sending the + /// transaction without a signature, and hence without paying any fees, + /// we need a way to make sure that only some transactions are accepted. + /// This function can be called only once every `T::UnsignedInterval` blocks. + /// Transactions that call that function are de-duplicated on the pool level + /// via `validate_unsigned` implementation and also are rendered invalid if + /// the function has already been called in current "session". /// /// TODO - verify the provided mPower to check that it is meaningful data /// TODO - replace u32 with data structured that contains the account id of each /// registered DHX miner and their mPower data for a date - /// TODO - specify `weight` for unsigned calls as well, because even though - /// they don't charge fees, we still don't want a single block to contain unlimited - /// number of such transactions. - #[pallet::weight(0)] - pub fn submit_mpower(origin: OriginFor, mpower: u32) -> DispatchResultWithPostInfo { - // Retrieve sender of the transaction. - let who = ensure_signed(origin)?; - // Add mpower on-chain. - Self::add_mpower(who, mpower); - Ok(().into()) - } - - /// Submit new mPower data on-chain via unsigned transaction. - /// - /// Works exactly like the `submit_mpower` function, but since we allow sending the - /// transaction without a signature, and hence without paying any fees, - /// we need a way to make sure that only some transactions are accepted. - /// This function can be called only once every `T::UnsignedInterval` blocks. - /// Transactions that call that function are de-duplicated on the pool level - /// via `validate_unsigned` implementation and also are rendered invalid if - /// the function has already been called in current "session". - #[pallet::weight(0)] - pub fn submit_mpower_unsigned( - origin: OriginFor, - _block_number: T::BlockNumber, - mpower: u32, - ) -> DispatchResultWithPostInfo { - // This ensures that the function can only be called via unsigned transaction. - ensure_none(origin)?; - // Add the mpower on-chain, but mark it as coming from an empty address. - Self::add_mpower(Default::default(), mpower); - // now increment the block number at which we expect next unsigned transaction. - let current_block = >::block_number(); - >::put(current_block + T::UnsignedInterval::get()); - Ok(().into()) - } - - #[pallet::weight(0)] - pub fn submit_mpower_unsigned_with_signed_payload( - origin: OriginFor, - mpower_payload: MPowerPayload, - _signature: T::Signature, - ) -> DispatchResultWithPostInfo { - // This ensures that the function can only be called via unsigned transaction. - ensure_none(origin)?; - // Add the mPower on-chain, but mark it as coming from an empty address. - Self::add_mpower(Default::default(), mpower_payload.mpower); - // now increment the block number at which we expect next unsigned transaction. - let current_block = >::block_number(); - >::put(current_block + T::UnsignedInterval::get()); - Ok(().into()) - } + /// TODO - specify `weight` for unsigned calls as well, because even though + /// they don't charge fees, we still don't want a single block to contain unlimited + /// number of such transactions. + #[pallet::weight(0)] + pub fn submit_mpower_unsigned( + origin: OriginFor, + _block_number: T::BlockNumber, + mpower_payload: MPowerPayloadData, + ) -> DispatchResultWithPostInfo { + // This ensures that the function can only be called via unsigned transaction. + ensure_none(origin)?; + // Add the mpower on-chain, but mark it as coming from an empty address. + Self::add_mpower(Default::default(), mpower_payload.clone()); + // now increment the block number at which we expect next unsigned transaction. + let current_block = >::block_number(); + >::put(current_block + T::UnsignedInterval::get()); + Ok(().into()) + } } #[pallet::validate_unsigned] @@ -2310,18 +2269,8 @@ pub mod pallet { /// here we make sure that some particular calls (the ones produced by offchain worker) /// are being whitelisted and marked as valid. fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { - // Firstly let's check that we call the right function. - if let Call::submit_mpower_unsigned_with_signed_payload(ref payload, ref signature) = - call - { - let signature_valid = - SignedPayload::::verify::(payload, signature.clone()); - if !signature_valid { - return InvalidTransaction::BadProof.into() - } - Self::validate_transaction_parameters(&payload.block_number, &payload.mpower) - } else if let Call::submit_mpower_unsigned(block_number, new_mpower) = call { - Self::validate_transaction_parameters(block_number, new_mpower) + if let Call::submit_mpower_unsigned(block_number, new_mpower_data) = call { + Self::validate_transaction_parameters(block_number, new_mpower_data) } else { InvalidTransaction::Call.into() } @@ -2462,7 +2411,7 @@ pub mod pallet { } // we need to set the mPower for the next start date so it's available from off-chain in time - pub fn set_mpower_of_account_for_date(account_id: T::AccountId, mpower: u128, next_start_date: Date) -> Result { + pub fn set_mpower_of_account_for_date(account_id: T::AccountId, mpower: u128, next_start_date: Date, received_at_date: Date, received_at_block_number: T::BlockNumber) -> Result { // // Note: we DO need the following as we're using the current timestamp, rather than a function parameter. // let timestamp: ::Moment = >::get(); // let requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone())?; @@ -2480,8 +2429,13 @@ pub mod pallet { start_of_next_start_date_millis.clone(), account_id.clone(), ), - mpower_current_u128.clone(), + ( + mpower_current_u128.clone(), + received_at_date.clone(), + received_at_block_number.clone(), + ), ); + log::info!("set_mpower_of_account_for_date - start_of_next_start_date_millis: {:?}", &start_of_next_start_date_millis); log::info!("set_mpower_of_account_for_date - account_id: {:?}", &account_id); log::info!("set_mpower_of_account_for_date - mpower_current: {:?}", &mpower_current_u128); @@ -2489,8 +2443,10 @@ pub mod pallet { // Emit an event. Self::deposit_event(Event::SetMPowerOfAccountForDateStored( start_of_next_start_date_millis.clone(), - mpower_current_u128.clone(), account_id.clone(), + mpower_current_u128.clone(), + received_at_date.clone(), + received_at_block_number.clone(), )); // Return a successful DispatchResultWithPostInfo @@ -2637,24 +2593,7 @@ pub mod pallet { match res { // The value has been set correctly, which means we can safely send a transaction now. Ok(block_number) => { - // Depending if the block is even or odd we will send a `Signed` or `Unsigned` - // transaction. - // Note that this logic doesn't really guarantee that the transactions will be sent - // in an alternating fashion (i.e. fairly distributed). Depending on the execution - // order and lock acquisition, we may end up for instance sending two `Signed` - // transactions in a row. If a strict order is desired, it's better to use - // the storage entry for that. (for instance store both block number and a flag - // indicating the type of next transaction to send). - let transaction_type = block_number % 3u32.into(); - if transaction_type == Zero::zero() { - TransactionType::Signed - } else if transaction_type == T::BlockNumber::from(1u32) { - TransactionType::UnsignedForAny - } else if transaction_type == T::BlockNumber::from(2u32) { - TransactionType::UnsignedForAll - } else { - TransactionType::Raw - } + TransactionType::Raw }, // We are in the grace period, we should not send a transaction this time. Err(MutateStorageError::ValueFunctionFailed(RECENTLY_SENT)) => TransactionType::None, @@ -2667,39 +2606,6 @@ pub mod pallet { } } - /// A helper function to fetch the mpower and send signed transaction. - fn fetch_mpower_and_send_signed() -> Result<(), &'static str> { - let signer = Signer::::all_accounts(); - if !signer.can_sign() { - return Err( - "No local accounts available. Consider adding one via `author_insertKey` RPC.", - )? - } - // Make an external HTTP request to fetch the current mpower data. - // Note this call will block until response is received. - let mpower = Self::fetch_mpower().map_err(|_| "Failed to fetch mpower")?; - - // Using `send_signed_transaction` associated type we create and submit a transaction - // representing the call, we've just created. - // Submit signed will return a vector of results for all accounts that were found in the - // local keystore with expected `KEY_TYPE`. - let results = signer.send_signed_transaction(|_account| { - // Received mpower is wrapped into a call to `submit_mpower` public function of this - // pallet. This means that the transaction, when executed, will simply call that - // function passing `mpower` as an argument. - Call::submit_mpower(mpower) - }); - - for (acc, res) in &results { - match res { - Ok(()) => log::info!("[{:?}] Submitted mpower of {} cents", acc.id, mpower), - Err(e) => log::error!("[{:?}] Failed to submit transaction: {:?}", acc.id, e), - } - } - - Ok(()) - } - /// A helper function to fetch the mpower and send a raw unsigned transaction. fn fetch_mpower_and_send_raw_unsigned(block_number: T::BlockNumber) -> Result<(), &'static str> { // Make sure we don't fetch the mpower if unsigned transaction is going to be rejected @@ -2711,12 +2617,12 @@ pub mod pallet { // Make an external HTTP request to fetch the current mpower. // Note this call will block until response is received. - let mpower = Self::fetch_mpower().map_err(|_| "Failed to fetch mpower data")?; + let mpower_data: MPowerPayloadData = Self::fetch_mpower(block_number.clone()).map_err(|_| "Failed to fetch mpower data")?; // Received mpower data is wrapped into a call to `submit_mpower_unsigned` public function of this // pallet. This means that the transaction, when executed, will simply call that function - // passing `mpower` as an argument. - let call = Call::submit_mpower_unsigned(block_number, mpower); + // passing `mpower_data` as an argument. + let call = Call::submit_mpower_unsigned(block_number, mpower_data); // Now let's create a transaction out of this call and submit it to the pool. // Here we showcase two ways to send an unsigned transaction / unsigned payload (raw) @@ -2732,68 +2638,8 @@ pub mod pallet { Ok(()) } - /// A helper function to fetch the mpower, sign payload and send an unsigned transaction - fn fetch_mpower_and_send_unsigned_for_any_account( - block_number: T::BlockNumber, - ) -> Result<(), &'static str> { - // Make sure we don't fetch the mpower if unsigned transaction is going to be rejected anyway. - let next_unsigned_at = >::get(); - if next_unsigned_at > block_number { - return Err("Too early to send unsigned transaction") - } - - // Make an external HTTP request to fetch the current mpower data. - // Note this call will block until response is received. - let mpower = Self::fetch_mpower().map_err(|_| "Failed to fetch mpower data")?; - - // -- Sign using any account - let (_, result) = Signer::::any_account() - .send_unsigned_transaction( - |account| MPowerPayload { mpower, block_number, public: account.public.clone() }, - |payload, signature| { - Call::submit_mpower_unsigned_with_signed_payload(payload, signature) - }, - ) - .ok_or("No local accounts accounts available.")?; - result.map_err(|()| "Unable to submit transaction")?; - - Ok(()) - } - - /// A helper function to fetch the mpower, sign payload and send an unsigned transaction - fn fetch_mpower_and_send_unsigned_for_all_accounts( - block_number: T::BlockNumber, - ) -> Result<(), &'static str> { - // Make sure we don't fetch the mpower if unsigned transaction is going to be rejected anyway. - let next_unsigned_at = >::get(); - if next_unsigned_at > block_number { - return Err("Too early to send unsigned transaction") - } - - // Make an external HTTP request to fetch the current mpower data. - // Note this call will block until response is received. - let mpower = Self::fetch_mpower().map_err(|_| "Failed to fetch mpower")?; - - // Sign using all accounts - // TODO - why would we need to sign using all accounts? - let transaction_results = Signer::::all_accounts() - .send_unsigned_transaction( - |account| MPowerPayload { mpower, block_number, public: account.public.clone() }, - |payload, signature| { - Call::submit_mpower_unsigned_with_signed_payload(payload, signature) - }, - ); - for (_account_id, result) in transaction_results.into_iter() { - if result.is_err() { - return Err("Unable to submit transaction") - } - } - - Ok(()) - } - /// Fetch current mPower and return the result. - fn fetch_mpower() -> Result { + fn fetch_mpower(block_number: T::BlockNumber) -> Result, http::Error> { // We want to keep the offchain worker execution time reasonable, so we set a hard-coded // deadline to 2s to complete the external call. // You can also wait idefinitely for the response, however you may still get a timeout @@ -2835,84 +2681,124 @@ pub mod pallet { http::Error::Unknown })?; - let mpower = match Self::parse_mpower(body_str) { - Some(mpower) => Ok(mpower), + log::info!("Received HTTP Body: {}", body_str.clone()); + + // FIXME - do we need this? + let mpower_data = match Self::parse_mpower_data(body_str, block_number.clone()) { + Some(mpower_data) => Ok(mpower_data), None => { log::warn!("Unable to extract mpower from the response: {:?}", body_str); Err(http::Error::Unknown) }, }?; - log::warn!("Got mpower: {:?}", mpower); + log::info!("Parsed mpower_data: {:?}", body_str); - Ok(mpower) + Ok(mpower_data) } /// Parse the mPower from the given JSON string using `lite-json`. /// - /// Returns `None` when parsing failed or `Some(mPower)` when parsing is successful. - fn parse_mpower(mpower_str: &str) -> Option { - let val = lite_json::parse_json(mpower_str); + /// Returns `None` when parsing failed or `Some(mpower_data)` when parsing is successful. + fn parse_mpower_data(mpower_data_str: &str, block_number: T::BlockNumber) -> Option> { + let val = lite_json::parse_json(mpower_data_str); + let timestamp = >::get(); + let received_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()).ok()?; + log::info!("received_date_as_u64: {:?}", received_date_as_u64.clone()); // TODO - parse for mPower data and replace hard-coded response with output + let received_date_as_millis = Self::convert_u64_in_milliseconds_to_start_of_date(received_date_as_u64.clone()).ok()?; + + let mpower_parsed = match val.ok()? { + JsonValue::Object(obj) => { + // let (_, v) = obj.into_iter().find(|(k, _)| k.iter().copied().eq("USD".chars()))?; + // match v { + // JsonValue::Number(number) => number, + // _ => return None, + // }; + + // FIXME - this is all hard-coded temporary + let mpower_data: MPowerPayloadData = MPowerPayload { + // account_id_registered_dhx_miner: mpower_data_str.account_id.clone(), // FIXME + // mpower_registered_dhx_miner: mpower_data_str.mpower.clone(), // FIXME + // it's not supposed to be from the treasury, but just using treasury account for demo + account_id_registered_dhx_miner: >::account_id(), // FIXME + mpower_registered_dhx_miner: 0u128, // FIXME + received_at_date: received_date_as_millis.clone(), + received_at_block_number: block_number.clone(), + }; + return Some(mpower_data); + }, + _ => return None, + }; - // let mpower = match val.ok()? { - // JsonValue::Object(obj) => { - // let (_, v) = obj.into_iter().find(|(k, _)| k.iter().copied().eq("USD".chars()))?; - // match v { - // JsonValue::Number(number) => number, - // _ => return None, - // } - // }, - // _ => return None, - // }; - - // let exp = mpower.fraction_length.checked_sub(2).unwrap_or(0); - // Some(mpower.integer as u32 * 100 + (mpower.fraction / 10_u64.pow(exp)) as u32) - Some(0u32) + Some(mpower_parsed) } /// Add new mPower on-chain. - fn add_mpower(who: T::AccountId, mpower: u32) { - log::info!("Adding mPower to storage: {}", mpower); + fn add_mpower(who: T::AccountId, mpower_data: MPowerPayloadData) -> Option> { + log::info!("Adding mPower to storage"); - // TODO - add mPower data to storage - - // >::mutate(|mpowers| { - // const MAX_LEN: usize = 64; + let timestamp = >::get(); + let received_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()).ok()?; + log::info!("received_date_as_u64: {:?}", received_date_as_u64.clone()); + // convert the received date/time to the start of that day date/time to signify that date for lookup + // i.e. 21 Apr @ 1420 -> 21 Apr @ 0000 + let start_of_received_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(received_date_as_u64.clone()).ok()?; + log::info!("start_of_received_date_millis: {:?}", start_of_received_date_millis.clone()); - // if mpowers.len() < MAX_LEN { - // mpowers.push(mpower); - // } else { - // mpowers[mpower as usize % MAX_LEN] = mpower; - // } - // }); + >::insert( + ( + start_of_received_date_millis.clone(), + mpower_data.account_id_registered_dhx_miner.clone(), + ), + ( + mpower_data.mpower_registered_dhx_miner.clone(), + mpower_data.received_at_date.clone(), + mpower_data.received_at_block_number.clone(), + ), + ); + log::info!("Added MPowerForAccountForDate {:?} {:?} {:?} {:?} {:?}", + start_of_received_date_millis.clone(), + mpower_data.account_id_registered_dhx_miner.clone(), + mpower_data.mpower_registered_dhx_miner.clone(), + mpower_data.received_at_date.clone(), + mpower_data.received_at_block_number.clone(), + ); // let average = Self::average_mpower() // .expect("The average is not empty, because it was just mutated; qed"); // log::info!("Current average mpower is: {}", average); // here we are raising the NewPrice event - Self::deposit_event(Event::NewMPower(mpower, who)); + Self::deposit_event(Event::NewMPowerForAccountForDate( + start_of_received_date_millis.clone(), + mpower_data.account_id_registered_dhx_miner.clone(), + mpower_data.mpower_registered_dhx_miner.clone(), + mpower_data.received_at_date.clone(), + mpower_data.received_at_block_number.clone(), + )); + + Some(mpower_data.clone()) } /// Calculation based on mPower. - fn average_mpower() -> Option { - let mpowers = >::get(); + fn average_mpower() -> Option { + // let mpowers = >::get(); // TODO - implement what we need and replace hard-coded response with output // if mpowers.is_empty() { // None // } else { - // Some(mpowers.iter().fold(0_u32, |a, b| a.saturating_add(*b)) / mpowers.len() as u32) + // Some(mpowers.iter().fold(0_u128, |a, b| a.saturating_add(*b)) / mpowers.len() as u128) // } None } fn validate_transaction_parameters( block_number: &T::BlockNumber, - new_mpower: &u32, + new_mpower_data: &MPowerPayloadData, ) -> TransactionValidity { // Now let's check if the transaction has any chance to succeed. let next_unsigned_at = >::get(); @@ -2925,41 +2811,51 @@ pub mod pallet { return InvalidTransaction::Future.into() } - // We prioritize transactions that are more far away from current average. - // - // Note this doesn't make much sense when building an actual oracle, but this example - // is here mostly to show off offchain workers capabilities, not about building an - // oracle. - let avg_mpower = Self::average_mpower() - .map(|mpower| if &mpower > new_mpower { mpower - new_mpower } else { new_mpower - mpower }) - .unwrap_or(0); + + // // We prioritize transactions that are more far away from current average. + // // + // // Note this doesn't make much sense when building an actual oracle, but this example + // // is here mostly to show off offchain workers capabilities, not about building an + // // oracle. + // let avg_mpower = Self::average_mpower() + // .map(|mpower| if &mpower > new_mpower { mpower - new_mpower } else { new_mpower - mpower }) + // .unwrap_or(0); + + // FIXME ValidTransaction::with_tag_prefix("MPowerOffchainWorker") - // We set base priority to 2**20 and hope it's included before any other - // transactions in the pool. Next we tweak the priority depending on how much - // it differs from the current average. (the more it differs the more priority it - // has). - .priority(T::UnsignedPriority::get().saturating_add(avg_mpower as _)) - // This transaction does not require anything else to go before into the pool. - // In theory we could require `previous_unsigned_at` transaction to go first, - // but it's not necessary in our case. - //.and_requires() - // We set the `provides` tag to be the same as `next_unsigned_at`. This makes - // sure only one transaction produced after `next_unsigned_at` will ever - // get to the transaction pool and will end up in the block. - // We can still have multiple transactions compete for the same "spot", - // and the one with higher priority will replace other one in the pool. + .priority(1) .and_provides(next_unsigned_at) - // The transaction is only valid for next 5 blocks. After that it's - // going to be revalidated by the pool. .longevity(5) - // It's fine to propagate that transaction to other peers, which means it can be - // created even by nodes that don't produce blocks. - // Note that sometimes it's better to keep it for yourself (if you are the block - // producer), since for instance in some schemes others may copy your solution and - // claim a reward. .propagate(true) .build() + + // ValidTransaction::with_tag_prefix("MPowerOffchainWorker") + // // We set base priority to 2**20 and hope it's included before any other + // // transactions in the pool. Next we tweak the priority depending on how much + // // it differs from the current average. (the more it differs the more priority it + // // has). + // .priority(T::UnsignedPriority::get().saturating_add(avg_mpower as _)) + // // This transaction does not require anything else to go before into the pool. + // // In theory we could require `previous_unsigned_at` transaction to go first, + // // but it's not necessary in our case. + // //.and_requires() + // // We set the `provides` tag to be the same as `next_unsigned_at`. This makes + // // sure only one transaction produced after `next_unsigned_at` will ever + // // get to the transaction pool and will end up in the block. + // // We can still have multiple transactions compete for the same "spot", + // // and the one with higher priority will replace other one in the pool. + // .and_provides(next_unsigned_at) + // // The transaction is only valid for next 5 blocks. After that it's + // // going to be revalidated by the pool. + // .longevity(5) + // // It's fine to propagate that transaction to other peers, which means it can be + // // created even by nodes that don't produce blocks. + // // Note that sometimes it's better to keep it for yourself (if you are the block + // // producer), since for instance in some schemes others may copy your solution and + // // claim a reward. + // .propagate(true) + // .build() } } } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4e6232b8a..e228c58b9 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1170,7 +1170,6 @@ parameter_types! { } impl mining_rewards_allowance::Config for Runtime { - type AuthorityId = TestAuthId; type Call = Call; type Currency = Balances; type Event = Event; @@ -1250,7 +1249,7 @@ construct_runtime!( MiningSettingHardware: mining_setting_hardware::{Pallet, Call, Storage, Event}, MiningRatesToken: mining_rates_token::{Pallet, Call, Storage, Event}, MiningRatesHardware: mining_rates_hardware::{Pallet, Call, Storage, Event}, - MiningRewardsAllowance: mining_rewards_allowance::{Pallet, Call, Storage, Config, Event}, + MiningRewardsAllowance: mining_rewards_allowance::{Pallet, Call, Storage, Config, Event, ValidateUnsigned}, MiningSamplingToken: mining_sampling_token::{Pallet, Call, Storage, Event}, MiningSamplingHardware: mining_sampling_hardware::{Pallet, Call, Storage, Event}, MiningEligibilityToken: mining_eligibility_token::{Pallet, Call, Storage, Event}, From f3c2e3379414b3424901fcc39c953c1ed7b0efd0 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 5 Nov 2021 12:43:13 +0100 Subject: [PATCH 05/37] wip - unable to use serde_json --- Cargo.lock | 1 + pallets/mining/rewards-allowance/Cargo.toml | 2 + pallets/mining/rewards-allowance/src/lib.rs | 198 +++++++++++++------- 3 files changed, 129 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c609d413..a60160765 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3738,6 +3738,7 @@ dependencies = [ "parity-scale-codec", "rand 0.8.4", "serde", + "serde_json", "sp-consensus-aura", "sp-core", "sp-io", diff --git a/pallets/mining/rewards-allowance/Cargo.toml b/pallets/mining/rewards-allowance/Cargo.toml index 31a09dbd9..7bc544009 100644 --- a/pallets/mining/rewards-allowance/Cargo.toml +++ b/pallets/mining/rewards-allowance/Cargo.toml @@ -12,6 +12,7 @@ default = ['std'] std = [ 'chrono/std', 'log/std', + 'serde_json/std', 'serde/std', 'rand/std', 'substrate-fixed/std', @@ -46,6 +47,7 @@ static_assertions = '1.1.0' chrono = { version = '0.4.19', default_features = false } lite-json = { version = "0.1", default-features = false } log = { version = '0.4.14', default-features = false } +serde_json = '1.0.41' serde = { version = '1.0.126', features = ['derive'] } rand = { version = '0.8.4', default-features = false } substrate-fixed = { git = "https://github.com/encointer/substrate-fixed", version = '0.5.6' } diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 410201265..88aa58f4a 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -49,7 +49,8 @@ use frame_system::{ AppCrypto, CreateSignedTransaction, SendUnsignedTransaction, Signer, SubmitTransaction, }, }; -use lite_json::json::JsonValue; +// use lite_json::json::JsonValue; +use serde::{Deserialize, Serialize}; use log::{warn, info}; use module_primitives::{ types::{ @@ -209,6 +210,17 @@ pub mod pallet { type UnsignedPriority: Get; } + #[derive(Debug, Serialize, Deserialize)] + struct MPowerAccountData { + acct_id: U, + mpower: V, + } + + #[derive(Debug, Serialize, Deserialize)] + struct MPowerJSONResponseData { + data: Vec>, + } + /// Payload used to hold mPower data required to submit a transaction. #[cfg_attr(feature = "std", derive(Debug))] #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)] @@ -226,6 +238,12 @@ pub mod pallet { ::BlockNumber, >; + // FIXME - change these to the types we really want + type MPowerAccountDataType = MPowerAccountData< + ::AccountId, + u128, + >; + enum TransactionType { Raw, None, @@ -2246,12 +2264,12 @@ pub mod pallet { pub fn submit_mpower_unsigned( origin: OriginFor, _block_number: T::BlockNumber, - mpower_payload: MPowerPayloadData, + mpower_payload_vec: Vec>, ) -> DispatchResultWithPostInfo { // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; - // Add the mpower on-chain, but mark it as coming from an empty address. - Self::add_mpower(Default::default(), mpower_payload.clone()); + // Add the mpower vec on-chain, but mark it as coming from an empty address. + Self::add_mpower(Default::default(), mpower_payload_vec.clone()); // now increment the block number at which we expect next unsigned transaction. let current_block = >::block_number(); >::put(current_block + T::UnsignedInterval::get()); @@ -2269,8 +2287,8 @@ pub mod pallet { /// here we make sure that some particular calls (the ones produced by offchain worker) /// are being whitelisted and marked as valid. fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { - if let Call::submit_mpower_unsigned(block_number, new_mpower_data) = call { - Self::validate_transaction_parameters(block_number, new_mpower_data) + if let Call::submit_mpower_unsigned(block_number, new_mpower_data_vec) = call { + Self::validate_transaction_parameters(block_number, new_mpower_data_vec) } else { InvalidTransaction::Call.into() } @@ -2410,6 +2428,7 @@ pub mod pallet { Ok(bonded_dhx_current_u128.clone()) } + // FIXME - we're using `next_start_date`, but in off-chain workers we'll try doing it all on the same date we received it // we need to set the mPower for the next start date so it's available from off-chain in time pub fn set_mpower_of_account_for_date(account_id: T::AccountId, mpower: u128, next_start_date: Date, received_at_date: Date, received_at_block_number: T::BlockNumber) -> Result { // // Note: we DO need the following as we're using the current timestamp, rather than a function parameter. @@ -2617,12 +2636,12 @@ pub mod pallet { // Make an external HTTP request to fetch the current mpower. // Note this call will block until response is received. - let mpower_data: MPowerPayloadData = Self::fetch_mpower(block_number.clone()).map_err(|_| "Failed to fetch mpower data")?; + let mpower_data_vec: Vec> = Self::fetch_mpower(block_number.clone()).map_err(|_| "Failed to fetch mpower data vec")?; // Received mpower data is wrapped into a call to `submit_mpower_unsigned` public function of this // pallet. This means that the transaction, when executed, will simply call that function - // passing `mpower_data` as an argument. - let call = Call::submit_mpower_unsigned(block_number, mpower_data); + // passing `mpower_data_vec` as an argument. + let call = Call::submit_mpower_unsigned(block_number, mpower_data_vec); // Now let's create a transaction out of this call and submit it to the pool. // Here we showcase two ways to send an unsigned transaction / unsigned payload (raw) @@ -2639,7 +2658,7 @@ pub mod pallet { } /// Fetch current mPower and return the result. - fn fetch_mpower(block_number: T::BlockNumber) -> Result, http::Error> { + fn fetch_mpower(block_number: T::BlockNumber) -> Result>, http::Error> { // We want to keep the offchain worker execution time reasonable, so we set a hard-coded // deadline to 2s to complete the external call. // You can also wait idefinitely for the response, however you may still get a timeout @@ -2683,25 +2702,34 @@ pub mod pallet { log::info!("Received HTTP Body: {}", body_str.clone()); - // FIXME - do we need this? - let mpower_data = match Self::parse_mpower_data(body_str, block_number.clone()) { - Some(mpower_data) => Ok(mpower_data), + let mpower_data = r#"{ + "data": [ + { "acct_id": "50000000000000001", "mpower": "1" }, + { "acct_id": "50000000000000001", "mpower": "1" } + ] + }"#; + + let mpower_data_vec = match Self::parse_mpower_data(mpower_data, block_number.clone()) { + Some(data) => Ok(data), None => { - log::warn!("Unable to extract mpower from the response: {:?}", body_str); + log::warn!("Unable to extract mpower data from the response: {:?}", body_str); Err(http::Error::Unknown) }, }?; - log::info!("Parsed mpower_data: {:?}", body_str); + // log::info!("Parsed mpower_data_vec: {:?}", mpower_data_vec); - Ok(mpower_data) + Ok(mpower_data_vec) } /// Parse the mPower from the given JSON string using `lite-json`. /// /// Returns `None` when parsing failed or `Some(mpower_data)` when parsing is successful. - fn parse_mpower_data(mpower_data_str: &str, block_number: T::BlockNumber) -> Option> { - let val = lite_json::parse_json(mpower_data_str); + fn parse_mpower_data(mpower_data_str: &str, block_number: T::BlockNumber) -> Option>> { + // checking it works: + // https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=09eee43b3354f2a798ca4394838fdef7 + + // let val = lite_json::parse_json(mpower_data_str); let timestamp = >::get(); let received_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()).ok()?; @@ -2709,34 +2737,59 @@ pub mod pallet { // TODO - parse for mPower data and replace hard-coded response with output let received_date_as_millis = Self::convert_u64_in_milliseconds_to_start_of_date(received_date_as_u64.clone()).ok()?; - let mpower_parsed = match val.ok()? { - JsonValue::Object(obj) => { - // let (_, v) = obj.into_iter().find(|(k, _)| k.iter().copied().eq("USD".chars()))?; - // match v { - // JsonValue::Number(number) => number, - // _ => return None, - // }; - - // FIXME - this is all hard-coded temporary - let mpower_data: MPowerPayloadData = MPowerPayload { - // account_id_registered_dhx_miner: mpower_data_str.account_id.clone(), // FIXME - // mpower_registered_dhx_miner: mpower_data_str.mpower.clone(), // FIXME - // it's not supposed to be from the treasury, but just using treasury account for demo - account_id_registered_dhx_miner: >::account_id(), // FIXME - mpower_registered_dhx_miner: 0u128, // FIXME - received_at_date: received_date_as_millis.clone(), - received_at_block_number: block_number.clone(), - }; - return Some(mpower_data); + let mpower_json_data: MPowerJSONResponseData = match serde_json::from_str(mpower_data_str) { + Err(e) => { + println!("Couldn't parse JSON :( {:?}", e); + return None; }, - _ => return None, + Ok(data) => data, }; - Some(mpower_parsed) + log::info!("mpower_json_data{:?}", mpower_json_data); + + let mut mpower_data_vec: Vec> = vec![]; + for (i, v) in mpower_json_data.data.into_iter().enumerate() { + println!("i v {:?} {:?}", i, v); + let mpower_data_elem: MPowerPayloadData = MPowerPayload { + account_id_registered_dhx_miner: v.acct_id.clone(), + mpower_registered_dhx_miner: v.mpower.clone(), + received_at_date: received_date_as_millis.clone(), + received_at_block_number: block_number.clone(), + }; + + mpower_data_vec.push(mpower_data_elem); + } + + // log::info!("mpower_data_vec{:?}", mpower_data_vec); + + // let mpower_parsed = match val.ok()? { + // JsonValue::Object(obj) => { + // // let (_, v) = obj.into_iter().find(|(k, _)| k.iter().copied().eq("USD".chars()))?; + // // match v { + // // JsonValue::Number(number) => number, + // // _ => return None, + // // }; + + // // FIXME - this is all hard-coded temporary + // let mpower_data: MPowerPayloadData = MPowerPayload { + // // account_id_registered_dhx_miner: mpower_data_str.account_id.clone(), // FIXME + // // mpower_registered_dhx_miner: mpower_data_str.mpower.clone(), // FIXME + // // it's not supposed to be from the treasury, but just using treasury account for demo + // account_id_registered_dhx_miner: >::account_id(), // FIXME + // mpower_registered_dhx_miner: 0u128, // FIXME + // received_at_date: received_date_as_millis.clone(), + // received_at_block_number: block_number.clone(), + // }; + // return Some(mpower_data); + // }, + // _ => return None, + // }; + + Some(mpower_data_vec) } /// Add new mPower on-chain. - fn add_mpower(who: T::AccountId, mpower_data: MPowerPayloadData) -> Option> { + fn add_mpower(who: T::AccountId, mpower_data_vec: Vec>) -> Option>> { log::info!("Adding mPower to storage"); let timestamp = >::get(); @@ -2747,39 +2800,41 @@ pub mod pallet { let start_of_received_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(received_date_as_u64.clone()).ok()?; log::info!("start_of_received_date_millis: {:?}", start_of_received_date_millis.clone()); - >::insert( - ( + for (index, mpower_data_item) in mpower_data_vec.iter().enumerate() { + >::insert( + ( + start_of_received_date_millis.clone(), + mpower_data_item.account_id_registered_dhx_miner.clone(), + ), + ( + mpower_data_item.mpower_registered_dhx_miner.clone(), + mpower_data_item.received_at_date.clone(), + mpower_data_item.received_at_block_number.clone(), + ), + ); + log::info!("Added MPowerForAccountForDate {:?} {:?} {:?} {:?} {:?}", start_of_received_date_millis.clone(), - mpower_data.account_id_registered_dhx_miner.clone(), - ), - ( - mpower_data.mpower_registered_dhx_miner.clone(), - mpower_data.received_at_date.clone(), - mpower_data.received_at_block_number.clone(), - ), - ); - log::info!("Added MPowerForAccountForDate {:?} {:?} {:?} {:?} {:?}", - start_of_received_date_millis.clone(), - mpower_data.account_id_registered_dhx_miner.clone(), - mpower_data.mpower_registered_dhx_miner.clone(), - mpower_data.received_at_date.clone(), - mpower_data.received_at_block_number.clone(), - ); + mpower_data_item.account_id_registered_dhx_miner.clone(), + mpower_data_item.mpower_registered_dhx_miner.clone(), + mpower_data_item.received_at_date.clone(), + mpower_data_item.received_at_block_number.clone(), + ); - // let average = Self::average_mpower() - // .expect("The average is not empty, because it was just mutated; qed"); - // log::info!("Current average mpower is: {}", average); - // here we are raising the NewPrice event - - Self::deposit_event(Event::NewMPowerForAccountForDate( - start_of_received_date_millis.clone(), - mpower_data.account_id_registered_dhx_miner.clone(), - mpower_data.mpower_registered_dhx_miner.clone(), - mpower_data.received_at_date.clone(), - mpower_data.received_at_block_number.clone(), - )); + // let average = Self::average_mpower() + // .expect("The average is not empty, because it was just mutated; qed"); + // log::info!("Current average mpower is: {}", average); + // here we are raising the NewPrice event - Some(mpower_data.clone()) + Self::deposit_event(Event::NewMPowerForAccountForDate( + start_of_received_date_millis.clone(), + mpower_data_item.account_id_registered_dhx_miner.clone(), + mpower_data_item.mpower_registered_dhx_miner.clone(), + mpower_data_item.received_at_date.clone(), + mpower_data_item.received_at_block_number.clone(), + )); + } + + Some(mpower_data_vec.clone()) } /// Calculation based on mPower. @@ -2798,7 +2853,7 @@ pub mod pallet { fn validate_transaction_parameters( block_number: &T::BlockNumber, - new_mpower_data: &MPowerPayloadData, + new_mpower_data: &Vec>, ) -> TransactionValidity { // Now let's check if the transaction has any chance to succeed. let next_unsigned_at = >::get(); @@ -2811,7 +2866,6 @@ pub mod pallet { return InvalidTransaction::Future.into() } - // // We prioritize transactions that are more far away from current average. // // // // Note this doesn't make much sense when building an actual oracle, but this example From dba8e712e6c729532d46e7349e8fa33a0ca72aa1 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sat, 6 Nov 2021 22:28:58 +0100 Subject: [PATCH 06/37] wip --- Cargo.lock | 2 - pallets/mining/rewards-allowance/Cargo.toml | 6 +- pallets/mining/rewards-allowance/src/lib.rs | 76 +++++++++------------ 3 files changed, 34 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a60160765..fc512999e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3737,8 +3737,6 @@ dependencies = [ "pallet-treasury", "parity-scale-codec", "rand 0.8.4", - "serde", - "serde_json", "sp-consensus-aura", "sp-core", "sp-io", diff --git a/pallets/mining/rewards-allowance/Cargo.toml b/pallets/mining/rewards-allowance/Cargo.toml index 7bc544009..11b30a60d 100644 --- a/pallets/mining/rewards-allowance/Cargo.toml +++ b/pallets/mining/rewards-allowance/Cargo.toml @@ -12,8 +12,7 @@ default = ['std'] std = [ 'chrono/std', 'log/std', - 'serde_json/std', - 'serde/std', + # 'serde/std', 'rand/std', 'substrate-fixed/std', 'codec/std', @@ -47,8 +46,7 @@ static_assertions = '1.1.0' chrono = { version = '0.4.19', default_features = false } lite-json = { version = "0.1", default-features = false } log = { version = '0.4.14', default-features = false } -serde_json = '1.0.41' -serde = { version = '1.0.126', features = ['derive'] } +# serde = { version = '1.0.126', default-features = false, features = ['derive'] } rand = { version = '0.8.4', default-features = false } substrate-fixed = { git = "https://github.com/encointer/substrate-fixed", version = '0.5.6' } codec = { version = '2.2.0', package = 'parity-scale-codec', default-features = false, features = ['derive', 'max-encoded-len'] } diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 88aa58f4a..dee3dd5fc 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -49,8 +49,8 @@ use frame_system::{ AppCrypto, CreateSignedTransaction, SendUnsignedTransaction, Signer, SubmitTransaction, }, }; -// use lite_json::json::JsonValue; -use serde::{Deserialize, Serialize}; +// use serde::{Deserialize, Serialize}; +use lite_json::json::JsonValue; use log::{warn, info}; use module_primitives::{ types::{ @@ -85,8 +85,8 @@ use sp_std::{ TryFrom, TryInto, }, - vec::Vec, - // prelude::*, // Imports Vec + // vec::Vec, + prelude::*, // Imports Vec }; use substrate_fixed::{ types::{ @@ -210,13 +210,13 @@ pub mod pallet { type UnsignedPriority: Get; } - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug)] struct MPowerAccountData { acct_id: U, mpower: V, } - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug)] struct MPowerJSONResponseData { data: Vec>, } @@ -2705,7 +2705,7 @@ pub mod pallet { let mpower_data = r#"{ "data": [ { "acct_id": "50000000000000001", "mpower": "1" }, - { "acct_id": "50000000000000001", "mpower": "1" } + { "acct_id": "50000000000000002", "mpower": "1" } ] }"#; @@ -2726,33 +2726,44 @@ pub mod pallet { /// /// Returns `None` when parsing failed or `Some(mpower_data)` when parsing is successful. fn parse_mpower_data(mpower_data_str: &str, block_number: T::BlockNumber) -> Option>> { - // checking it works: + // checking it works using serde_json, but cannot use in substrate as it uses std: // https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=09eee43b3354f2a798ca4394838fdef7 - // let val = lite_json::parse_json(mpower_data_str); - let timestamp = >::get(); let received_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()).ok()?; log::info!("received_date_as_u64: {:?}", received_date_as_u64.clone()); // TODO - parse for mPower data and replace hard-coded response with output let received_date_as_millis = Self::convert_u64_in_milliseconds_to_start_of_date(received_date_as_u64.clone()).ok()?; - let mpower_json_data: MPowerJSONResponseData = match serde_json::from_str(mpower_data_str) { - Err(e) => { - println!("Couldn't parse JSON :( {:?}", e); - return None; + let mpower_json_data = lite_json::parse_json(mpower_data_str); + + // let mpower_json_data: MPowerJSONResponseData = match serde_json::from_str(mpower_data_str) { + // Err(e) => { + // println!("Couldn't parse JSON :( {:?}", e); + // return None; + // }, + // Ok(data) => data, + // }; + // log::info!("mpower_json_data{:?}", mpower_json_data); + + let mut mpower_data_vec: Vec> = vec![]; + let mpower_array = match mpower_json_data.ok()? { + JsonValue::Object(obj) => { + let (_, v) = obj.into_iter().find(|(k, _)| k.iter().copied().eq("data".chars()))?; + match v { + JsonValue::Array(vec) => vec, + _ => return None, + }; }, - Ok(data) => data, + _ => return None, }; - log::info!("mpower_json_data{:?}", mpower_json_data); + for (i, obj) in mpower_array.into_iter().enumerate() { + println!("mpower_array obj {:?} {:?}", i, obj); - let mut mpower_data_vec: Vec> = vec![]; - for (i, v) in mpower_json_data.data.into_iter().enumerate() { - println!("i v {:?} {:?}", i, v); let mpower_data_elem: MPowerPayloadData = MPowerPayload { - account_id_registered_dhx_miner: v.acct_id.clone(), - mpower_registered_dhx_miner: v.mpower.clone(), + account_id_registered_dhx_miner: obj.acct_id.clone(), + mpower_registered_dhx_miner: obj.mpower.clone(), received_at_date: received_date_as_millis.clone(), received_at_block_number: block_number.clone(), }; @@ -2762,29 +2773,6 @@ pub mod pallet { // log::info!("mpower_data_vec{:?}", mpower_data_vec); - // let mpower_parsed = match val.ok()? { - // JsonValue::Object(obj) => { - // // let (_, v) = obj.into_iter().find(|(k, _)| k.iter().copied().eq("USD".chars()))?; - // // match v { - // // JsonValue::Number(number) => number, - // // _ => return None, - // // }; - - // // FIXME - this is all hard-coded temporary - // let mpower_data: MPowerPayloadData = MPowerPayload { - // // account_id_registered_dhx_miner: mpower_data_str.account_id.clone(), // FIXME - // // mpower_registered_dhx_miner: mpower_data_str.mpower.clone(), // FIXME - // // it's not supposed to be from the treasury, but just using treasury account for demo - // account_id_registered_dhx_miner: >::account_id(), // FIXME - // mpower_registered_dhx_miner: 0u128, // FIXME - // received_at_date: received_date_as_millis.clone(), - // received_at_block_number: block_number.clone(), - // }; - // return Some(mpower_data); - // }, - // _ => return None, - // }; - Some(mpower_data_vec) } From edd9734daff8f9c2f94dc48b748e3e1581e90076 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 8 Nov 2021 12:00:47 +1100 Subject: [PATCH 07/37] Update pallets/mining/rewards-allowance/src/lib.rs Co-authored-by: Xiliang Chen --- pallets/mining/rewards-allowance/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index dee3dd5fc..610f9a743 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -2753,7 +2753,7 @@ pub mod pallet { match v { JsonValue::Array(vec) => vec, _ => return None, - }; + } }, _ => return None, }; From 88500f3baaad19da09e18bbc6f0cf4f9267baa22 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 8 Nov 2021 12:28:30 +0100 Subject: [PATCH 08/37] wip --- Cargo.lock | 1 + pallets/mining/rewards-allowance/Cargo.toml | 1 + pallets/mining/rewards-allowance/src/lib.rs | 56 ++++++++++++++++++--- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc512999e..115ba7d80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3719,6 +3719,7 @@ dependencies = [ "chrono", "frame-support", "frame-system", + "hex-literal", "lite-json", "log", "module-primitives", diff --git a/pallets/mining/rewards-allowance/Cargo.toml b/pallets/mining/rewards-allowance/Cargo.toml index 11b30a60d..cb6dfa8ff 100644 --- a/pallets/mining/rewards-allowance/Cargo.toml +++ b/pallets/mining/rewards-allowance/Cargo.toml @@ -44,6 +44,7 @@ std = [ [dependencies] static_assertions = '1.1.0' chrono = { version = '0.4.19', default_features = false } +hex-literal = { version = '0.3.1', default_features = false } lite-json = { version = "0.1", default-features = false } log = { version = '0.4.14', default-features = false } # serde = { version = '1.0.126', default-features = false, features = ['derive'] } diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 610f9a743..74fbb17da 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -49,6 +49,7 @@ use frame_system::{ AppCrypto, CreateSignedTransaction, SendUnsignedTransaction, Signer, SubmitTransaction, }, }; +use hex_literal::hex; // use serde::{Deserialize, Serialize}; use lite_json::json::JsonValue; use log::{warn, info}; @@ -62,7 +63,7 @@ use module_primitives::{ use pallet_balances::{BalanceLock}; use rand::{seq::SliceRandom, Rng}; use sp_core::{ - crypto::KeyTypeId, + crypto::{KeyTypeId, Public}, sr25519, }; use sp_runtime::{ @@ -95,6 +96,7 @@ use substrate_fixed::{ U32F32, U64F64, }, + FixedU32, FixedU128, }; @@ -2702,10 +2704,11 @@ pub mod pallet { log::info!("Received HTTP Body: {}", body_str.clone()); + // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d let mpower_data = r#"{ "data": [ - { "acct_id": "50000000000000001", "mpower": "1" }, - { "acct_id": "50000000000000002", "mpower": "1" } + { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": 1 }, + { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": 2 } ] }"#; @@ -2759,19 +2762,58 @@ pub mod pallet { }; for (i, obj) in mpower_array.into_iter().enumerate() { - println!("mpower_array obj {:?} {:?}", i, obj); + let obj_acct_id = match obj.clone() { + JsonValue::Object(obj_data) => { + let (_, v) = obj_data.into_iter().find(|(k, _)| k.iter().copied().eq("acct_id".chars()))?; + match v { + JsonValue::String(val) => val, + _ => return None, + } + }, + _ => return None, + }; + + // let obj_mpower: u32 = match obj.clone() { + // JsonValue::Object(obj_data) => { + // let (_, v) = obj_data.into_iter().find(|(k, _)| k.iter().copied().eq("mpower".chars()))?; + // match v { + // JsonValue::Number(val) => val.into(), + // _ => return None, + // } + // }, + // _ => return None, + // }; + + // Convert from `Vec` to `Vec` since we do not use String in the runtime + // e.g. converts from `['1', '2', '3']` to `123` + let obj_acct_id_str: Vec = obj_acct_id.iter().map(|c| *c as u8).collect::>(); + // let obj_mpower_str: u32 = obj_mpower.iter().map(|c| *c as u32).collect::(); + + // FIXME - this outputs the following but needs to be in correct format to insert into storage + // Vec: ['5', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1'] ['1'] + // Vec: [ 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49] [49] + + log::info!("mpower_array obj acct_id {:?} {:?}", i, obj_acct_id_str.clone()); + // log::info!("mpower_array obj mpower {:?} {:?}", i, obj_mpower_str.clone()); + + // // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d + // let alice_public_key_hex: T::AccountId = hex!["d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"].into_account(); + // // where ::AccountId: From<[u8; 32]> + // let mpower_as_u128: u128 = obj_mpower.clone().parse().unwrap(); // convert from string to number let mpower_data_elem: MPowerPayloadData = MPowerPayload { - account_id_registered_dhx_miner: obj.acct_id.clone(), - mpower_registered_dhx_miner: obj.mpower.clone(), + account_id_registered_dhx_miner: obj_acct_id_str.clone(), // alice_public_key_hex.clone(), //acct_id_as_acct_id.clone(), + // FIXME - do not hardcode + mpower_registered_dhx_miner: 0u128, // mpower_as_u128.clone(), received_at_date: received_date_as_millis.clone(), received_at_block_number: block_number.clone(), }; mpower_data_vec.push(mpower_data_elem); + } - // log::info!("mpower_data_vec{:?}", mpower_data_vec); + // log::info!("mpower_data_vec {:?}", mpower_data_vec); Some(mpower_data_vec) } From df24da120be2a4436bd2d72b1c12829c29494fba Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 9 Nov 2021 07:52:11 +0100 Subject: [PATCH 09/37] wip - api response acct_id stored as Vec string to represent public key hex --- Cargo.lock | 1 + pallets/mining/rewards-allowance/Cargo.toml | 5 +- pallets/mining/rewards-allowance/src/lib.rs | 56 ++++++++++++++------- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 115ba7d80..11ba9981d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3719,6 +3719,7 @@ dependencies = [ "chrono", "frame-support", "frame-system", + "hex", "hex-literal", "lite-json", "log", diff --git a/pallets/mining/rewards-allowance/Cargo.toml b/pallets/mining/rewards-allowance/Cargo.toml index cb6dfa8ff..2a1124ff0 100644 --- a/pallets/mining/rewards-allowance/Cargo.toml +++ b/pallets/mining/rewards-allowance/Cargo.toml @@ -11,6 +11,9 @@ targets = ['x86_64-unknown-linux-gnu'] default = ['std'] std = [ 'chrono/std', + 'hex/std', + # 'hex-literal/std', + 'lite-json/std', 'log/std', # 'serde/std', 'rand/std', @@ -18,7 +21,6 @@ std = [ 'codec/std', 'frame-support/std', 'frame-system/std', - 'lite-json/std', 'pallet-aura/std', 'pallet-balances/std', 'pallet-bounties/std', @@ -44,6 +46,7 @@ std = [ [dependencies] static_assertions = '1.1.0' chrono = { version = '0.4.19', default_features = false } +hex = { version = '0.4.3', default_features = false, features = ['alloc'] } hex-literal = { version = '0.3.1', default_features = false } lite-json = { version = "0.1", default-features = false } log = { version = '0.4.14', default-features = false } diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 74fbb17da..8d233d1f3 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -49,7 +49,10 @@ use frame_system::{ AppCrypto, CreateSignedTransaction, SendUnsignedTransaction, Signer, SubmitTransaction, }, }; -use hex_literal::hex; +use hex; // to use hex::encode("..."); +use hex_literal::{ // to use hex!("..."); + hex as write_hex, +}; // use serde::{Deserialize, Serialize}; use lite_json::json::JsonValue; use log::{warn, info}; @@ -234,7 +237,7 @@ pub mod pallet { } type MPowerPayloadData = MPowerPayload< - ::AccountId, + Vec, // ::AccountId, u128, Date, ::BlockNumber, @@ -415,7 +418,7 @@ pub mod pallet { pub(super) type MPowerForAccountForDate = StorageMap<_, Blake2_128Concat, ( Date, // converted to start of date - T::AccountId, + Vec, // T::AccountId, ), ( u128, // mPower @@ -586,7 +589,8 @@ pub mod pallet { /// Storage of the mPower of an account on a specific date. /// \[date, amount_mpower, account\] - SetMPowerOfAccountForDateStored(Date, T::AccountId, u128, Date, T::BlockNumber), + SetMPowerOfAccountForDateStored(Date, Vec, u128, Date, T::BlockNumber), + // SetMPowerOfAccountForDateStored(Date, T::AccountId, u128, Date, T::BlockNumber), /// Storage of the default daily reward allowance in DHX by an origin account. /// \[amount_dhx, sender\] @@ -635,7 +639,8 @@ pub mod pallet { /// Event generated when new mPower data is accepted to contribute to the rewards allowance. /// \[start_date_received, registered_dhx_miner_account_id, mpower, date_received_offchain, block_received_offchain\] - NewMPowerForAccountForDate(Date, T::AccountId, u128, Date, T::BlockNumber), + NewMPowerForAccountForDate(Date, Vec, u128, Date, T::BlockNumber), + // NewMPowerForAccountForDate(Date, T::AccountId, u128, Date, T::BlockNumber), } // Errors inform users that something went wrong should be descriptive and have helpful documentation @@ -2432,7 +2437,8 @@ pub mod pallet { // FIXME - we're using `next_start_date`, but in off-chain workers we'll try doing it all on the same date we received it // we need to set the mPower for the next start date so it's available from off-chain in time - pub fn set_mpower_of_account_for_date(account_id: T::AccountId, mpower: u128, next_start_date: Date, received_at_date: Date, received_at_block_number: T::BlockNumber) -> Result { + pub fn set_mpower_of_account_for_date(account_id: Vec, mpower: u128, next_start_date: Date, received_at_date: Date, received_at_block_number: T::BlockNumber) -> Result { + // pub fn set_mpower_of_account_for_date(account_id: T::AccountId, mpower: u128, next_start_date: Date, received_at_date: Date, received_at_block_number: T::BlockNumber) -> Result { // // Note: we DO need the following as we're using the current timestamp, rather than a function parameter. // let timestamp: ::Moment = >::get(); // let requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone())?; @@ -2704,11 +2710,12 @@ pub mod pallet { log::info!("Received HTTP Body: {}", body_str.clone()); + // FIXME - replace the below hard-coded example in future with use of the response body // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d let mpower_data = r#"{ "data": [ - { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": 1 }, - { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": 2 } + { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "1" }, + { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "2" } ] }"#; @@ -2786,23 +2793,38 @@ pub mod pallet { // Convert from `Vec` to `Vec` since we do not use String in the runtime // e.g. converts from `['1', '2', '3']` to `123` - let obj_acct_id_str: Vec = obj_acct_id.iter().map(|c| *c as u8).collect::>(); + let obj_acct_id_str_hex: Vec = obj_acct_id.iter().map(|c| *c as u8).collect::>(); // let obj_mpower_str: u32 = obj_mpower.iter().map(|c| *c as u32).collect::(); - // FIXME - this outputs the following but needs to be in correct format to insert into storage - // Vec: ['5', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1'] ['1'] - // Vec: [ 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49] [49] + // Decode from hex ascii format + let obj_acct_id_str = hex::decode(obj_acct_id_str_hex.clone()).ok()?; + log::info!("Decoded acct_id i public key hex as Vec {:?} {:?}", i, obj_acct_id_str.clone()); - log::info!("mpower_array obj acct_id {:?} {:?}", i, obj_acct_id_str.clone()); // log::info!("mpower_array obj mpower {:?} {:?}", i, obj_mpower_str.clone()); - // // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d - // let alice_public_key_hex: T::AccountId = hex!["d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"].into_account(); - // // where ::AccountId: From<[u8; 32]> + // Example only: + // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d + // + // Note: do not do `hex!["..."].encode(), since that will just encoding a vec, + // which will include a length prefix, but we don't want that. + // let example_acct_id_str: Vec = write_hex!["d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"].into(); + // log::info!("example_acct_id_str {:?}", example_acct_id_str); + // let mpower_as_u128: u128 = obj_mpower.clone().parse().unwrap(); // convert from string to number + // Example of how to access the Vec string representation of the account's public key hex + // let reg_dhx_miners; + // if let Some(_reg_dhx_miners) = >::get() { + // reg_dhx_miners = _reg_dhx_miners; + // } else { + // log::error!("Unable to retrieve any registered DHX Miners"); + // return None; + // } + // let first_reg_dhx_miner = ®_dhx_miners[0]; + // log::info!("first_reg_dhx_miner {:?}", first_reg_dhx_miner.encode()); + let mpower_data_elem: MPowerPayloadData = MPowerPayload { - account_id_registered_dhx_miner: obj_acct_id_str.clone(), // alice_public_key_hex.clone(), //acct_id_as_acct_id.clone(), + account_id_registered_dhx_miner: obj_acct_id_str.clone(), // FIXME - do not hardcode mpower_registered_dhx_miner: 0u128, // mpower_as_u128.clone(), received_at_date: received_date_as_millis.clone(), From f7c362eadb9cc103c5048f701bf4021ddd8e21ba Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 9 Nov 2021 14:32:21 +0100 Subject: [PATCH 10/37] wip - adding mpower from API works. fixing tests --- pallets/mining/rewards-allowance/src/lib.rs | 115 +++++++++++++++--- pallets/mining/rewards-allowance/src/mock.rs | 48 +++++++- pallets/mining/rewards-allowance/src/tests.rs | 9 ++ 3 files changed, 154 insertions(+), 18 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 8d233d1f3..740d098c1 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -28,6 +28,7 @@ //! #![cfg_attr(not(feature = "std"), no_std)] +use core::str; use chrono::{ NaiveDateTime, }; @@ -2389,6 +2390,76 @@ pub mod pallet { return Ok(blocknumber_u64); } + // fn convert_vec_u8_to_u128(data: &[u8]) -> Result { + // Ok(core::str::from_utf8(data)?.parse()?) + // } + + // Convert a Vec that we received from an API endpoint that represents the mPower + // associated with an account id into a u128 value. + // ascii table: https://aws1.discourse-cdn.com/business5/uploads/rust_lang/original/3X/9/0/909baa7e3d9569489b07c791ca76f2223bd7bac2.webp + fn convert_vec_u8_to_u128(data: &[u8]) -> Result { + let mut out = 0u128; + let mut multiplier = 1; + + for &val in data.iter().rev() { + // log::info!("{:?}", val); + + let mut digit = 0u128; + match val { + 48u8 => { + digit = 0u128; + }, + 49u8 => { + digit = 1u128; + }, + 50u8 => { + digit = 2u128; + }, + 51u8 => { + digit = 3u128; + }, + 52u8 => { + digit = 4u128; + }, + 53u8 => { + digit = 5u128; + }, + 54u8 => { + digit = 6u128; + }, + 55u8 => { + digit = 7u128; + }, + 56u8 => { + digit = 8u128; + }, + 57u8 => { + digit = 9u128; + }, + _ => { + log::error!("Non-digit ASCII char in input"); + return Err(DispatchError::Other("Non-digit ASCII char in input")); + }, + } + log::info!("digit {:?}", digit); + if digit != 0u128 && out != 0u128 { + multiplier *= 10; + } else if digit != 0u128 && out == 0u128 { + multiplier *= 1; + } else if digit == 0u128 && out != 0u128 { + multiplier *= 10; + } else if digit == 0u128 && out == 0u128 { + multiplier *= 10; + } + + log::info!("multiplier {:?}", multiplier); + out += multiplier * digit; + log::info!("out {:?}", out); + } + + Ok(out) + } + fn set_bonded_dhx_of_account_for_date(account_id: T::AccountId, bonded_dhx: u128) -> Result { // Note: we DO need the following as we're using the current timestamp, rather than a function parameter. let timestamp: ::Moment = >::get(); @@ -2714,8 +2785,8 @@ pub mod pallet { // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d let mpower_data = r#"{ "data": [ - { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "1" }, - { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "2" } + { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "11" }, + { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "12" } ] }"#; @@ -2780,27 +2851,40 @@ pub mod pallet { _ => return None, }; - // let obj_mpower: u32 = match obj.clone() { - // JsonValue::Object(obj_data) => { - // let (_, v) = obj_data.into_iter().find(|(k, _)| k.iter().copied().eq("mpower".chars()))?; - // match v { - // JsonValue::Number(val) => val.into(), - // _ => return None, - // } - // }, - // _ => return None, - // }; + let obj_mpower = match obj.clone() { + JsonValue::Object(obj_data) => { + let (_, v) = obj_data.into_iter().find(|(k, _)| k.iter().copied().eq("mpower".chars()))?; + match v { + JsonValue::String(val) => val, + _ => return None, + } + }, + _ => return None, + }; + + log::info!("obj_mpower char {:?} {:?}", i, obj_mpower.clone()); // Convert from `Vec` to `Vec` since we do not use String in the runtime // e.g. converts from `['1', '2', '3']` to `123` let obj_acct_id_str_hex: Vec = obj_acct_id.iter().map(|c| *c as u8).collect::>(); - // let obj_mpower_str: u32 = obj_mpower.iter().map(|c| *c as u32).collect::(); + let obj_mpower_str_hex: Vec = obj_mpower.iter().map(|c| *c as u8).collect::>(); + log::info!("obj_mpower_str_hex {:?} {:?}", i, obj_mpower_str_hex.clone()); // Decode from hex ascii format let obj_acct_id_str = hex::decode(obj_acct_id_str_hex.clone()).ok()?; log::info!("Decoded acct_id i public key hex as Vec {:?} {:?}", i, obj_acct_id_str.clone()); - // log::info!("mpower_array obj mpower {:?} {:?}", i, obj_mpower_str.clone()); + let mpower_u128 = Self::convert_vec_u8_to_u128(&obj_mpower_str_hex).ok()?; + log::info!("mpower_u128 {:?} {:?}", i, mpower_u128.clone()); + + // let mut obj_mpower_as_u128 = 0u128; // initialize + // if let Some(_obj_mpower_as_u128) = TryInto::::try_into(obj_mpower_str.clone()).ok() { + // obj_mpower_as_u128 = _obj_mpower_as_u128; + // } else { + // log::error!("Unable to convert Vec into u128"); + // return None; + // } + // log::info!("obj_mpower_as_u128 {:?} {:?}", i, obj_mpower_as_u128.clone()); // Example only: // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d @@ -2825,8 +2909,7 @@ pub mod pallet { let mpower_data_elem: MPowerPayloadData = MPowerPayload { account_id_registered_dhx_miner: obj_acct_id_str.clone(), - // FIXME - do not hardcode - mpower_registered_dhx_miner: 0u128, // mpower_as_u128.clone(), + mpower_registered_dhx_miner: mpower_u128.clone(), received_at_date: received_date_as_millis.clone(), received_at_block_number: block_number.clone(), }; diff --git a/pallets/mining/rewards-allowance/src/mock.rs b/pallets/mining/rewards-allowance/src/mock.rs index b9a2ec4b4..e6fb92c14 100644 --- a/pallets/mining/rewards-allowance/src/mock.rs +++ b/pallets/mining/rewards-allowance/src/mock.rs @@ -24,6 +24,7 @@ use frame_system::{ use pallet_democracy::{self, Conviction, Vote}; use sp_core::{ H256, + sr25519::Signature, u32_trait::{ _1, _2, @@ -37,10 +38,13 @@ use codec::{ }; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_runtime::{ - testing::Header, + testing::{Header, TestXt}, traits::{ BlakeTwo256, + Extrinsic as ExtrinsicT, + IdentifyAccount, IdentityLookup, + Verify, }, Perbill, Percent, @@ -438,9 +442,49 @@ impl pallet_democracy::Config for Test { type MaxProposals = MaxProposals; } +type Extrinsic = TestXt; +// type AccountId = <::Signer as IdentifyAccount>::AccountId; + +impl frame_system::offchain::SigningTypes for Test { + type Public = ::Signer; + type Signature = Signature; +} + +impl frame_system::offchain::SendTransactionTypes for Test +where + Call: From, +{ + type OverarchingCall = Call; + type Extrinsic = Extrinsic; +} + +impl frame_system::offchain::CreateSignedTransaction for Test +where + Call: From, +{ + fn create_transaction>( + call: Call, + _public: ::Signer, + _account: AccountId, + nonce: u64, + ) -> Option<(Call, ::SignaturePayload)> { + Some((call, (nonce, ()))) + } +} + +parameter_types! { + pub const GracePeriod: BlockNumber = 1 * MINUTES; + pub const UnsignedInterval: BlockNumber = 1 * MINUTES; + pub const UnsignedPriority: BlockNumber = 1 * MINUTES; +} + impl MiningRewardsAllowanceConfig for Test { - type Event = (); + type Call = Call; type Currency = Balances; + type Event = (); + type GracePeriod = GracePeriod; + type UnsignedInterval = UnsignedInterval; + type UnsignedPriority = UnsignedPriority; } pub type SysEvent = frame_system::Event; diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 70f0f0e4a..4eb2dd669 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -292,6 +292,15 @@ fn it_allows_us_to_retrieve_genesis_value_for_min_mpower_daily() { }); } +#[test] +fn it_converts_vec_u8_to_u128() { + new_test_ext().execute_with(|| { + // my snippet: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=69915086c8faa9de69301ee86e914bed + let hex_literal = vec![48, 51, 48, 48, 49, 50, 48, 51, 57, 48, 48]; + assert_eq!(MiningRewardsAllowanceTestModule::convert_vec_u8_to_u128(&hex_literal), 3001203900u128); + }); +} + fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(1))); assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(2))); From e52f252389688f32cb68030f835f29c07a8cc08b Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 10 Nov 2021 08:33:45 +0100 Subject: [PATCH 11/37] try to fix tests. remove block number and date received from SetMPower storage --- pallets/mining/rewards-allowance/src/lib.rs | 41 +++++-------------- pallets/mining/rewards-allowance/src/mock.rs | 6 ++- pallets/mining/rewards-allowance/src/tests.rs | 18 ++++---- 3 files changed, 26 insertions(+), 39 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 740d098c1..9c1a9b85e 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -421,11 +421,7 @@ pub mod pallet { Date, // converted to start of date Vec, // T::AccountId, ), - ( - u128, // mPower - Date, // date received using off-chain workers - T::BlockNumber, // block receive dusing off-chain workers - ), + u128, // mPower >; /// Defines the block when next unsigned transaction will be accepted. @@ -590,8 +586,7 @@ pub mod pallet { /// Storage of the mPower of an account on a specific date. /// \[date, amount_mpower, account\] - SetMPowerOfAccountForDateStored(Date, Vec, u128, Date, T::BlockNumber), - // SetMPowerOfAccountForDateStored(Date, T::AccountId, u128, Date, T::BlockNumber), + SetMPowerOfAccountForDateStored(Date, Vec, u128), /// Storage of the default daily reward allowance in DHX by an origin account. /// \[amount_dhx, sender\] @@ -639,9 +634,9 @@ pub mod pallet { // Off-chain workers /// Event generated when new mPower data is accepted to contribute to the rewards allowance. - /// \[start_date_received, registered_dhx_miner_account_id, mpower, date_received_offchain, block_received_offchain\] - NewMPowerForAccountForDate(Date, Vec, u128, Date, T::BlockNumber), - // NewMPowerForAccountForDate(Date, T::AccountId, u128, Date, T::BlockNumber), + /// \[start_date_received, registered_dhx_miner_account_id, mpower\] + NewMPowerForAccountForDate(Date, Vec, u128), + // NewMPowerForAccountForDate(Date, T::AccountId, u128), } // Errors inform users that something went wrong should be descriptive and have helpful documentation @@ -2397,7 +2392,7 @@ pub mod pallet { // Convert a Vec that we received from an API endpoint that represents the mPower // associated with an account id into a u128 value. // ascii table: https://aws1.discourse-cdn.com/business5/uploads/rust_lang/original/3X/9/0/909baa7e3d9569489b07c791ca76f2223bd7bac2.webp - fn convert_vec_u8_to_u128(data: &[u8]) -> Result { + pub fn convert_vec_u8_to_u128(data: &[u8]) -> Result { let mut out = 0u128; let mut multiplier = 1; @@ -2508,8 +2503,8 @@ pub mod pallet { // FIXME - we're using `next_start_date`, but in off-chain workers we'll try doing it all on the same date we received it // we need to set the mPower for the next start date so it's available from off-chain in time - pub fn set_mpower_of_account_for_date(account_id: Vec, mpower: u128, next_start_date: Date, received_at_date: Date, received_at_block_number: T::BlockNumber) -> Result { - // pub fn set_mpower_of_account_for_date(account_id: T::AccountId, mpower: u128, next_start_date: Date, received_at_date: Date, received_at_block_number: T::BlockNumber) -> Result { + pub fn set_mpower_of_account_for_date(account_id: Vec, mpower: u128, next_start_date: Date) -> Result { + // pub fn set_mpower_of_account_for_date(account_id: T::AccountId, mpower: u128, next_start_date: Date) -> Result { // // Note: we DO need the following as we're using the current timestamp, rather than a function parameter. // let timestamp: ::Moment = >::get(); // let requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone())?; @@ -2527,11 +2522,7 @@ pub mod pallet { start_of_next_start_date_millis.clone(), account_id.clone(), ), - ( - mpower_current_u128.clone(), - received_at_date.clone(), - received_at_block_number.clone(), - ), + mpower_current_u128.clone(), ); log::info!("set_mpower_of_account_for_date - start_of_next_start_date_millis: {:?}", &start_of_next_start_date_millis); @@ -2543,8 +2534,6 @@ pub mod pallet { start_of_next_start_date_millis.clone(), account_id.clone(), mpower_current_u128.clone(), - received_at_date.clone(), - received_at_block_number.clone(), )); // Return a successful DispatchResultWithPostInfo @@ -2941,18 +2930,12 @@ pub mod pallet { start_of_received_date_millis.clone(), mpower_data_item.account_id_registered_dhx_miner.clone(), ), - ( - mpower_data_item.mpower_registered_dhx_miner.clone(), - mpower_data_item.received_at_date.clone(), - mpower_data_item.received_at_block_number.clone(), - ), + mpower_data_item.mpower_registered_dhx_miner.clone(), ); - log::info!("Added MPowerForAccountForDate {:?} {:?} {:?} {:?} {:?}", + log::info!("Added MPowerForAccountForDate {:?} {:?} {:?}", start_of_received_date_millis.clone(), mpower_data_item.account_id_registered_dhx_miner.clone(), mpower_data_item.mpower_registered_dhx_miner.clone(), - mpower_data_item.received_at_date.clone(), - mpower_data_item.received_at_block_number.clone(), ); // let average = Self::average_mpower() @@ -2964,8 +2947,6 @@ pub mod pallet { start_of_received_date_millis.clone(), mpower_data_item.account_id_registered_dhx_miner.clone(), mpower_data_item.mpower_registered_dhx_miner.clone(), - mpower_data_item.received_at_date.clone(), - mpower_data_item.received_at_block_number.clone(), )); } diff --git a/pallets/mining/rewards-allowance/src/mock.rs b/pallets/mining/rewards-allowance/src/mock.rs index e6fb92c14..d538fe1d8 100644 --- a/pallets/mining/rewards-allowance/src/mock.rs +++ b/pallets/mining/rewards-allowance/src/mock.rs @@ -447,6 +447,7 @@ type Extrinsic = TestXt; impl frame_system::offchain::SigningTypes for Test { type Public = ::Signer; + // type Public = u128; type Signature = Signature; } @@ -465,10 +466,11 @@ where fn create_transaction>( call: Call, _public: ::Signer, + // _public: u128, _account: AccountId, - nonce: u64, + nonce: Index, ) -> Option<(Call, ::SignaturePayload)> { - Some((call, (nonce, ()))) + Some((call, (nonce.into(), ()))) } } diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 4eb2dd669..5744853ed 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -297,7 +297,7 @@ fn it_converts_vec_u8_to_u128() { new_test_ext().execute_with(|| { // my snippet: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=69915086c8faa9de69301ee86e914bed let hex_literal = vec![48, 51, 48, 48, 49, 50, 48, 51, 57, 48, 48]; - assert_eq!(MiningRewardsAllowanceTestModule::convert_vec_u8_to_u128(&hex_literal), 3001203900u128); + assert_eq!(MiningRewardsAllowanceTestModule::convert_vec_u8_to_u128(&hex_literal), Ok(3001203900u128)); }); } @@ -340,19 +340,23 @@ fn setup_min_mpower_daily(min_mpower_daily: u128) { // we have to get their mpower the day before we check if they are eligible incase there are delays in getting the off-chain data fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, next_start_date: i64) { - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(1, amount_mpower_each_miner.clone(), next_start_date)); - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(2, amount_mpower_each_miner.clone(), next_start_date)); - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(3, amount_mpower_each_miner.clone(), next_start_date)); + let account_1_public_key = vec![1]; + let account_2_public_key = vec![2]; + let account_3_public_key = vec![3]; + // https://aws1.discourse-cdn.com/business5/uploads/rust_lang/original/3X/9/0/909baa7e3d9569489b07c791ca76f2223bd7bac2.webp + assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_1_public_key, amount_mpower_each_miner.clone(), next_start_date)); + assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_2_public_key, amount_mpower_each_miner.clone(), next_start_date)); + assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_3_public_key, amount_mpower_each_miner.clone(), next_start_date)); assert_eq!( - MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, 1)), + MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_1_public_key)), Some(amount_mpower_each_miner.clone()) ); assert_eq!( - MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, 2)), + MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_2_public_key)), Some(amount_mpower_each_miner.clone()) ); assert_eq!( - MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, 3)), + MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_3_public_key)), Some(amount_mpower_each_miner.clone()) ); } From 9ad33cdf615e54699613d608134cae5c89dcc3ab Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 11 Nov 2021 19:32:27 +0100 Subject: [PATCH 12/37] fix mock using offchain_workers --- pallets/mining/rewards-allowance/src/lib.rs | 10 +++--- pallets/mining/rewards-allowance/src/mock.rs | 35 ++++++++++--------- pallets/mining/rewards-allowance/src/tests.rs | 12 +++---- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 9c1a9b85e..c4e80a3f0 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -2395,10 +2395,10 @@ pub mod pallet { pub fn convert_vec_u8_to_u128(data: &[u8]) -> Result { let mut out = 0u128; let mut multiplier = 1; - + for &val in data.iter().rev() { // log::info!("{:?}", val); - + let mut digit = 0u128; match val { 48u8 => { @@ -2446,12 +2446,12 @@ pub mod pallet { } else if digit == 0u128 && out == 0u128 { multiplier *= 10; } - + log::info!("multiplier {:?}", multiplier); out += multiplier * digit; log::info!("out {:?}", out); } - + Ok(out) } @@ -2859,7 +2859,7 @@ pub mod pallet { let obj_mpower_str_hex: Vec = obj_mpower.iter().map(|c| *c as u8).collect::>(); log::info!("obj_mpower_str_hex {:?} {:?}", i, obj_mpower_str_hex.clone()); - // Decode from hex ascii format + // Decode from hex ascii format let obj_acct_id_str = hex::decode(obj_acct_id_str_hex.clone()).ok()?; log::info!("Decoded acct_id i public key hex as Vec {:?} {:?}", i, obj_acct_id_str.clone()); diff --git a/pallets/mining/rewards-allowance/src/mock.rs b/pallets/mining/rewards-allowance/src/mock.rs index d538fe1d8..dfa3fe0c7 100644 --- a/pallets/mining/rewards-allowance/src/mock.rs +++ b/pallets/mining/rewards-allowance/src/mock.rs @@ -10,6 +10,7 @@ use frame_support::{ GenesisBuild, LockIdentifier, SortedMembers, + StorageMapShim, }, weights::{ IdentityFee, @@ -38,7 +39,7 @@ use codec::{ }; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_runtime::{ - testing::{Header, TestXt}, + testing::{Header, TestSignature, TestXt, UintAuthorityId}, traits::{ BlakeTwo256, Extrinsic as ExtrinsicT, @@ -103,7 +104,7 @@ frame_support::construct_runtime!( ); // Override primitives -pub type AccountId = u128; +pub type AccountId = u64; // pub type SysEvent = frame_system::Event; pub const MILLISECS_PER_BLOCK: Moment = 4320; @@ -141,7 +142,7 @@ impl frame_system::Config for Test { type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; + type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); @@ -161,7 +162,7 @@ impl pallet_scheduler::Config for Test { type PalletsOrigin = OriginCaller; type Call = Call; type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureRoot; + type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = (); } @@ -192,7 +193,8 @@ impl pallet_balances::Config for Test { type DustRemoval = (); type Event = (); type ExistentialDeposit = ExistentialDeposit; - type AccountStore = frame_system::Pallet; + type AccountStore = StorageMapShim, frame_system::Provider, u64, pallet_balances::AccountData>; + // type AccountStore = frame_system::Pallet; type WeightInfo = (); } parameter_types! { @@ -297,16 +299,16 @@ impl pallet_membership::Config for Test { } thread_local! { - static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); + static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); } pub struct TenToFourteen; -impl SortedMembers for TenToFourteen { - fn sorted_members() -> Vec { +impl SortedMembers for TenToFourteen { + fn sorted_members() -> Vec { TEN_TO_FOURTEEN.with(|v| v.borrow().clone()) } #[cfg(feature = "runtime-benchmarks")] - fn add(new: &u128) { + fn add(new: &u64) { TEN_TO_FOURTEEN.with(|v| { let mut members = v.borrow_mut(); members.push(*new); @@ -346,8 +348,8 @@ parameter_types! { impl pallet_treasury::Config for Test { type PalletId = TreasuryPalletId; type Currency = Balances; - type ApproveOrigin = EnsureRoot; - type RejectOrigin = EnsureRoot; + type ApproveOrigin = EnsureRoot; + type RejectOrigin = EnsureRoot; type Event = (); type OnSlash = (); type ProposalBond = ProposalBond; @@ -446,9 +448,9 @@ type Extrinsic = TestXt; // type AccountId = <::Signer as IdentifyAccount>::AccountId; impl frame_system::offchain::SigningTypes for Test { - type Public = ::Signer; - // type Public = u128; - type Signature = Signature; + type Public = UintAuthorityId; // ::Signer; + // type Public = u64; + type Signature = TestSignature; // Signature; } impl frame_system::offchain::SendTransactionTypes for Test @@ -465,8 +467,9 @@ where { fn create_transaction>( call: Call, - _public: ::Signer, - // _public: u128, + _public: UintAuthorityId, + // _public: ::Signer, + // _public: u64, _account: AccountId, nonce: Index, ) -> Option<(Call, ::SignaturePayload)> { diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 5744853ed..3d90ece37 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -344,19 +344,19 @@ fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, next_start_date: let account_2_public_key = vec![2]; let account_3_public_key = vec![3]; // https://aws1.discourse-cdn.com/business5/uploads/rust_lang/original/3X/9/0/909baa7e3d9569489b07c791ca76f2223bd7bac2.webp - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_1_public_key, amount_mpower_each_miner.clone(), next_start_date)); - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_2_public_key, amount_mpower_each_miner.clone(), next_start_date)); - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_3_public_key, amount_mpower_each_miner.clone(), next_start_date)); + assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_1_public_key.clone(), amount_mpower_each_miner.clone(), next_start_date)); + assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_2_public_key.clone(), amount_mpower_each_miner.clone(), next_start_date)); + assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_3_public_key.clone(), amount_mpower_each_miner.clone(), next_start_date)); assert_eq!( - MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_1_public_key)), + MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_1_public_key.clone())), Some(amount_mpower_each_miner.clone()) ); assert_eq!( - MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_2_public_key)), + MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_2_public_key.clone())), Some(amount_mpower_each_miner.clone()) ); assert_eq!( - MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_3_public_key)), + MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_3_public_key.clone())), Some(amount_mpower_each_miner.clone()) ); } From 75631cc06999ca68abc06ef98316b6c0e15a9bd5 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 15 Nov 2021 06:46:45 +0100 Subject: [PATCH 13/37] wip - move from on_initialize into offchain_worker and refactor --- pallets/mining/rewards-allowance/src/lib.rs | 935 ++++++++++---------- 1 file changed, 482 insertions(+), 453 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index c4e80a3f0..51d2a2738 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -673,55 +673,29 @@ pub mod pallet { // to the storage and other included pallets. // // We can easily import `frame_system` and retrieve a block hash of the parent block. - let parent_hash = >::block_hash(block_number - 1u32.into()); - log::debug!("offchain_workers current block: {:?} (parent hash: {:?})", block_number, parent_hash); + // let parent_hash = >::block_hash(block_number - 1u32.into()); + // log::debug!("offchain_workers current block: {:?} (parent hash: {:?})", block_number, parent_hash); // Call a helper function that reads storage entries of the current state average_mpower // and performs a calculation. - let average_mpower: Option = Self::average_mpower(); - log::debug!("offchain_workers average_mpower: {:?}", average_mpower); + // let average_mpower: Option = Self::average_mpower(); + // log::debug!("offchain_workers average_mpower: {:?}", average_mpower); - // We are going to send unsigned transactions - let should_send = Self::choose_transaction_type(block_number); - let res = match should_send { - TransactionType::Raw => Self::fetch_mpower_and_send_raw_unsigned(block_number), - TransactionType::None => Ok(()), - }; - if let Err(e) = res { - log::error!("offchain_workers error: {}", e); - } - } - - // `on_initialize` is executed at the beginning of the block before any extrinsic are - // dispatched. - // - // This function must return the weight consumed by `on_initialize` and `on_finalize`. - // TODO - update with the weight consumed - fn on_initialize(_n: T::BlockNumber) -> Weight { - let block_one = 1u32; - let block_one_as_block; - if let Some(_block_one) = TryInto::::try_into(block_one).ok() { - block_one_as_block = _block_one; - } else { - log::error!("Unable to convert u32 to BlockNumber"); - return 0; - } - - // skip block #1 since timestamp is 0 in blocks before block #2 - if _n == block_one_as_block.clone() { - return 0; + let should_process_block = Self::should_process_block(block_number.clone()); + if should_process_block == false { + return; } // Anything that needs to be done at the start of the block. let timestamp: ::Moment = >::get(); - log::info!("_n: {:?}", _n.clone()); + log::info!("block_number: {:?}", block_number.clone()); log::info!("timestamp: {:?}", timestamp.clone()); let requested_date_as_u64; let _requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()); match _requested_date_as_u64 { Err(_e) => { log::error!("Unable to convert Moment to u64 in millis for timestamp"); - return 0; + return; }, Ok(ref x) => { requested_date_as_u64 = x; @@ -733,14 +707,15 @@ pub mod pallet { // do not run when block number is 1, which is when timestamp is 0 because this // timestamp corresponds to 1970-01-01 if requested_date_as_u64.clone() == 0u64 { - return 0; + return; } + let start_of_requested_date_millis; let _start_of_requested_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(requested_date_as_u64.clone()); match _start_of_requested_date_millis { Err(_e) => { log::error!("Unable to convert u64 in milliseconds to start_of_requested_date_millis"); - return 0; + return; }, Ok(ref x) => { start_of_requested_date_millis = x; @@ -761,7 +736,7 @@ pub mod pallet { rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; } else { log::error!("Unable to get rewards_allowance_dhx_daily"); - return 0; + return; } // Update storage. Use RewardsAllowanceDHXDaily as fallback incase not previously set prior to block @@ -826,7 +801,7 @@ pub mod pallet { match _min_bonded_dhx_daily_default { Err(_e) => { log::error!("Unable to retrieve any min. bonded DHX daily default as BalanceOf and u128"); - return 0; + return; }, Ok(ref x) => { min_bonded_dhx_daily_default = x.0; @@ -885,17 +860,10 @@ pub mod pallet { >::put(min_mpower_daily_default.clone()); } - let block_two = 2u32; - let block_two_as_block; - if let Some(_block_two) = TryInto::::try_into(block_two).ok() { - block_two_as_block = _block_two; - } else { - log::error!("Unable to convert u32 to BlockNumber"); - return 0; - } + let is_block_two = Self::is_block_two(block_number.clone()); // start on block #2 since timestamp is 0 in blocks before that - if _n == block_two_as_block.clone() { + if is_block_two.clone() == true { // initialise values in storage that cannot be set in genesis and apply to local variables // incase its just after genesis when values are not yet set in storage >::put( @@ -920,7 +888,7 @@ pub mod pallet { if rm_current_period_days_remaining.1 != start_of_requested_date_millis.clone() { // if there are still days remaining in the countdown if rm_current_period_days_remaining.3 > 0u32 { - // println!("[reducing_multiplier_days] block: {:#?}, date_start: {:#?} remain_days: {:#?}", _n, rm_current_period_days_remaining.0, rm_current_period_days_remaining.3); + // println!("[reducing_multiplier_days] block: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, rm_current_period_days_remaining.0, rm_current_period_days_remaining.3); let old_rm_current_period_days_remaining = rm_current_period_days_remaining.3.clone(); // Subtract, handling overflow @@ -930,7 +898,7 @@ pub mod pallet { match _new_rm_current_period_days_remaining { None => { log::error!("Unable to subtract one from rm_current_period_days_remaining due to StorageOverflow"); - return 0; + return; }, Some(x) => { new_rm_current_period_days_remaining = x; @@ -960,7 +928,7 @@ pub mod pallet { match _min_bonded_dhx_daily { Err(_e) => { log::error!("Unable to retrieve any min. bonded DHX daily as BalanceOf and u128"); - return 0; + return; }, Ok(ref x) => { min_bonded_dhx_daily = x.0; @@ -974,7 +942,7 @@ pub mod pallet { rewards_multipler_operation = _rewards_multipler_operation; } else { log::error!("Unable to retrieve rewards_multipler_operation"); - return 0; + return; } let mut new_min_bonded_dhx_daily_u128 = 0u128; // initialize @@ -988,7 +956,7 @@ pub mod pallet { rm_next_change_u128_short = _rm_next_change_u128_short; } else { log::error!("Unable to convert u32 to u128"); - return 0; + return; } let ONE = 1000000000000000000u128; @@ -998,7 +966,7 @@ pub mod pallet { match _rm_next_change_as_fixedu128 { None => { log::error!("Unable to mult rm_next_change by ONE due to StorageOverflow"); - return 0; + return; }, Some(x) => { rm_next_change_as_fixedu128 = x; @@ -1021,7 +989,7 @@ pub mod pallet { match _new_min_bonded_dhx_daily_u128 { None => { log::error!("Unable to add min_bonded_dhx_daily_u128 with rm_next_change_u128 due to StorageOverflow"); - return 0; + return; }, Some(x) => { new_min_bonded_dhx_daily_u128 = x; @@ -1029,7 +997,7 @@ pub mod pallet { } } else { log::error!("Unsupported rewards_multipler_operation value"); - return 0; + return; } // println!("new_min_bonded_dhx_daily_u128 {:?}", new_min_bonded_dhx_daily_u128); @@ -1039,7 +1007,7 @@ pub mod pallet { match _new_min_bonded_dhx_daily { Err(_e) => { log::error!("Unable to convert u128 to balance for new_min_bonded_dhx_daily"); - return 0; + return; }, Ok(ref x) => { new_min_bonded_dhx_daily = x; @@ -1091,7 +1059,7 @@ pub mod pallet { match _new_min_bonded_dhx_daily { Err(_e) => { log::error!("Unable to convert u128 to balance for new_min_bonded_dhx_daily"); - return 0; + return; }, Ok(ref x) => { new_min_bonded_dhx_daily = x; @@ -1110,12 +1078,13 @@ pub mod pallet { reg_dhx_miners = _reg_dhx_miners; } else { log::error!("Unable to retrieve any registered DHX Miners"); - return 0; + return; } if reg_dhx_miners.len() == 0 { log::error!("Registered DHX Miners has no elements"); - return 0; + return; }; + let mut miner_count = 0; for (index, miner) in reg_dhx_miners.iter().enumerate() { @@ -1157,7 +1126,7 @@ pub mod pallet { match _locks_first_amount_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128"); - return 0; + return; }, Ok(x) => { locks_first_amount_as_u128 = x; @@ -1193,7 +1162,7 @@ pub mod pallet { match _bonded_dhx_current_u128 { Err(_e) => { log::error!("Unable to set_bonded_dhx_of_account_for_date"); - return 0; + return; }, Ok(ref x) => { bonded_dhx_current_u128 = x; @@ -1206,7 +1175,7 @@ pub mod pallet { match _min_bonded_dhx_daily { Err(_e) => { log::error!("Unable to retrieve any min. bonded DHX daily as BalanceOf and u128"); - return 0; + return; }, Ok(ref x) => { min_bonded_dhx_daily = x.0; @@ -1274,7 +1243,7 @@ pub mod pallet { cooling_off_period_days = _cooling_off_period_days; } else { log::error!("Unable to retrieve cooling off period days"); - return 0; + return; } let mut cooling_off_period_days_remaining = ( @@ -1324,7 +1293,7 @@ pub mod pallet { is_bonding_min_dhx == true && has_min_mpower_daily == true { - // println!("[reducing_days] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", _n, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); + // println!("[reducing_days] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); let old_cooling_off_period_days_remaining = cooling_off_period_days_remaining.1.clone(); // we cannot do this because of error: cannot use the `?` operator in a method that returns `()` @@ -1338,7 +1307,7 @@ pub mod pallet { match _new_cooling_off_period_days_remaining { None => { log::error!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); - return 0; + return; }, Some(x) => { new_cooling_off_period_days_remaining = x; @@ -1369,7 +1338,7 @@ pub mod pallet { is_bonding_min_dhx == true && has_min_mpower_daily == true { - // println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", _n, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); + // println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); // we need to add that they are eligible for rewards on the current date too >::insert( @@ -1412,14 +1381,14 @@ pub mod pallet { match _daily_reward_for_miner_as_u128 { None => { log::error!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); - return 0; + return; }, Some(x) => { daily_reward_for_miner_as_u128 = x; } } log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); - // println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} daily_reward_for_miner_as_u128: {:#?}", _n, miner_count, start_of_requested_date_millis, daily_reward_for_miner_as_u128); + // println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} daily_reward_for_miner_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, daily_reward_for_miner_as_u128); // if we have a rewards_aggregated_dhx_daily of 25.133 k DHX, then after the above manipulation // since we're dealing with a mixture of u128 and BalanceOf so the values are more readable in the UI. @@ -1438,7 +1407,7 @@ pub mod pallet { match _daily_reward_for_miner { Err(_e) => { log::error!("Unable to convert u128 to balance for daily_reward_for_miner"); - return 0; + return; }, Ok(ref x) => { daily_reward_for_miner = x; @@ -1458,7 +1427,7 @@ pub mod pallet { match _rewards_aggregated_dhx_daily_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); - return 0; + return; }, Ok(x) => { rewards_aggregated_dhx_daily_as_u128 = x; @@ -1472,7 +1441,7 @@ pub mod pallet { match _new_rewards_aggregated_dhx_daily_as_u128 { None => { log::error!("Unable to add daily_reward_for_miner to rewards_aggregated_dhx_daily due to StorageOverflow"); - return 0; + return; }, Some(x) => { new_rewards_aggregated_dhx_daily_as_u128 = x; @@ -1480,14 +1449,14 @@ pub mod pallet { } log::info!("new_rewards_aggregated_dhx_daily_as_u128: {:?}", new_rewards_aggregated_dhx_daily_as_u128.clone()); - // println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} new_rewards_aggregated_dhx_daily_as_u128: {:#?}", _n, miner_count, start_of_requested_date_millis, new_rewards_aggregated_dhx_daily_as_u128); + // println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} new_rewards_aggregated_dhx_daily_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_aggregated_dhx_daily_as_u128); let new_rewards_aggregated_dhx_daily; let _new_rewards_aggregated_dhx_daily = Self::convert_u128_to_balance(new_rewards_aggregated_dhx_daily_as_u128.clone()); match _new_rewards_aggregated_dhx_daily { Err(_e) => { log::error!("Unable to convert u128 to balance for new_rewards_aggregated_dhx_daily"); - return 0; + return; }, Ok(ref x) => { new_rewards_aggregated_dhx_daily = x; @@ -1571,7 +1540,7 @@ pub mod pallet { match _new_cooling_off_period_days_remaining { None => { log::error!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); - return 0; + return; }, Some(x) => { new_cooling_off_period_days_remaining = x; @@ -1588,7 +1557,7 @@ pub mod pallet { ), ); - // println!("[reduce] block: {:#?}, miner: {:#?}, date_start: {:#?} new_cooling_off_period_days_remaining: {:#?}", _n, miner_count, start_of_requested_date_millis, new_cooling_off_period_days_remaining); + // println!("[reduce] block: {:#?}, miner: {:#?}, date_start: {:#?} new_cooling_off_period_days_remaining: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_cooling_off_period_days_remaining); log::info!("Unbonded miner. Reducing cooling down period dates remaining {:?} {:?}", miner.clone(), new_cooling_off_period_days_remaining.clone()); // if cooling_off_period_days_remaining.0 is not the start of the current date @@ -1618,405 +1587,431 @@ pub mod pallet { } log::info!("Finished initial loop of registered miners"); - // println!("Finished initial loop of registered miners"); - - // TODO - consider the miner's mPower that we have fetched. it should have been added earlier above - // to the aggregated (all miners for that day) and accumulated (specific miner for a day) rewards - - // fetch accumulated total rewards for all registered miners for the day - // TODO - we've done this twice, create a function to fetch it - let mut rewards_aggregated_dhx_daily: BalanceOf = 0u32.into(); // initialize - if let Some(_rewards_aggregated_dhx_daily) = >::get(&start_of_requested_date_millis) { - rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; - } else { - log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period may not be finished yet"); - // Note: it would be an issue if we got past the first loop of looping through the registered miners - // and still hadn't added to the aggregated rewards for the day - return 0; - } - // println!("[multiplier] block: {:#?}, miner: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", _n, miner_count, start_of_requested_date_millis, rewards_aggregated_dhx_daily); - - if rewards_aggregated_dhx_daily == 0u32.into() { - log::error!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); - return 0; - } + println!("Finished initial loop of registered miners"); - let rewards_aggregated_dhx_daily_as_u128; - let _rewards_aggregated_dhx_daily_as_u128 = Self::convert_balance_to_u128(rewards_aggregated_dhx_daily.clone()); - match _rewards_aggregated_dhx_daily_as_u128.clone() { - Err(_e) => { - log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); - return 0; - }, - Ok(x) => { - rewards_aggregated_dhx_daily_as_u128 = x; - } - } - log::info!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); - - // TODO - we've done this twice, create a function to fetch it - let rewards_allowance_dhx_daily; - if let Some(_rewards_allowance_dhx_daily) = >::get() { - rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; - } else { - log::error!("Unable to get rewards_allowance_dhx_daily"); - return 0; - } - - let rewards_allowance_dhx_daily_u128; - let _rewards_allowance_dhx_daily_u128 = Self::convert_balance_to_u128(rewards_allowance_dhx_daily.clone()); - match _rewards_allowance_dhx_daily_u128.clone() { - Err(_e) => { - log::error!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); - return 0; - }, - Ok(x) => { - rewards_allowance_dhx_daily_u128 = x; - } - } + // We are going to send unsigned transactions + let should_send = Self::choose_transaction_type(block_number); + let res = match should_send { + TransactionType::Raw => Self::fetch_mpower_and_send_raw_unsigned(block_number), + TransactionType::None => Ok(()), + }; + if let Err(e) = res { + log::error!("offchain_workers error: {}", e); + } + } - if rewards_allowance_dhx_daily_u128 == 0u128 { - log::error!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); + // `on_initialize` is executed at the beginning of the block before any extrinsic are + // dispatched. + // + // This function must return the weight consumed by `on_initialize` and `on_finalize`. + // TODO - update with the weight consumed + fn on_initialize(block_number: T::BlockNumber) -> Weight { + let should_process_block = Self::should_process_block(block_number.clone()); + if should_process_block == true { return 0; } - // previously when we looped through all the registered dhx miners we calculated the - // reward for each registered miner based on the 10:1 ratio, and stored that along with - // the corresponding day in storage. since that loop we've fetched the total - // aggregated rewards that all reg miners are eligible for on that day as `rewards_aggregated_dhx_daily`, - // lets say it adds up to 8000 DHX, but say we only have 5000 DHX availabe to distribute - // from `rewards_allowance_dhx_daily`, so we'll constrain the rewards they'll receive further by - // applying a `distribution_multiplier_for_day_u128` of (5000/8000)*reg_miner_reward on each of - // the rewards that are distributed to them. - - // if the aggregated rewards isn't more than the daily rewards allowance available - // then just set the multiplier to 1, so they actually get the previously calculated reward rather - // than a scaled down proportion. - // - // e.g. 1: if miner rewards are 2000 & 4000 DHX respectively, this is greater than 5000 DHX daily allowance - // so we'd have a multiplier of 5000/6000 = 5/6, so they'd receive ~1666 & 3333 DHX respectively. - // e.g. 2: if miner rewards are 2000 & 2000 DHX respectively, this is less than 5000 DHX daily allowance - // so we'd just use a multiplier of 1, so they'd receive 2000 & 2000 DHX respectively. - // https://docs.rs/fixed/0.5.4/fixed/struct.FixedU128.html - let mut distribution_multiplier_for_day_fixed128 = FixedU128::from_num(1); // initialize - - if rewards_aggregated_dhx_daily_as_u128.clone() > rewards_allowance_dhx_daily_u128.clone() { - // Divide, handling overflow - - // Note: If the rewards_allowance_dhx_daily_u128 is 5000 DHX, its 5000000000000000000000, - // but we can't convert to u64 since largest value is 18446744073709551615. - // Since we expect the rewards_aggregated_dhx_daily_as_u128 to be at least 1 DHX (i.e. 1000000000000000000), - // we could just divide both numbers by 1000000000000000000, so we'd have say 5000 and 1 instead, - // since we're just using these values to get a multiplier output. - - let mut manageable_rewards_allowance_dhx_daily_u128 = 0u128; - if let Some(_manageable_rewards_allowance_dhx_daily_u128) = - rewards_allowance_dhx_daily_u128.clone().checked_div(1000000000000000000u128) { - manageable_rewards_allowance_dhx_daily_u128 = _manageable_rewards_allowance_dhx_daily_u128; - } else { - log::error!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); - return 0; - } - - let mut rewards_allowance_dhx_daily_u64 = 0u64; - if let Some(_rewards_allowance_dhx_daily_u64) = - TryInto::::try_into(manageable_rewards_allowance_dhx_daily_u128.clone()).ok() { - rewards_allowance_dhx_daily_u64 = _rewards_allowance_dhx_daily_u64; - } else { - log::error!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); - return 0; - } - - let mut manageable_rewards_aggregated_dhx_daily_as_u128 = 0u128; - if let Some(_manageable_rewards_aggregated_dhx_daily_as_u128) = rewards_aggregated_dhx_daily_as_u128.clone().checked_div(1000000000000000000u128) { - manageable_rewards_aggregated_dhx_daily_as_u128 = _manageable_rewards_aggregated_dhx_daily_as_u128; - } else { - log::error!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); - return 0; - } - - let mut rewards_aggregated_dhx_daily_as_u64 = 0u64; - if let Some(_rewards_aggregated_dhx_daily_as_u64) = - TryInto::::try_into(manageable_rewards_aggregated_dhx_daily_as_u128.clone()).ok() { - rewards_aggregated_dhx_daily_as_u64 = _rewards_aggregated_dhx_daily_as_u64; - } else { - log::error!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); - return 0; - } - - // See https://github.com/ltfschoen/substrate-node-template/pull/6/commits/175ef4805d07093042431c5814dda52da1ebde18 - let _fraction_distribution_multiplier_for_day_fixed128 = - U64F64::from_num(manageable_rewards_allowance_dhx_daily_u128.clone()) - .checked_div(U64F64::from_num(manageable_rewards_aggregated_dhx_daily_as_u128.clone())); - let _distribution_multiplier_for_day_fixed128 = _fraction_distribution_multiplier_for_day_fixed128.clone(); - match _distribution_multiplier_for_day_fixed128 { - None => { - log::error!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); - return 0; - }, - Some(x) => { - distribution_multiplier_for_day_fixed128 = x; - } - } - } - log::info!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); - // println!("[multiplier] block: {:#?}, miner: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", _n, miner_count, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); - - // Initialise outside the loop as we need this value after the loop after we finish iterating through all the miners - let mut rewards_allowance_dhx_remaining_today_as_u128 = 0u128; - - miner_count = 0; - for (index, miner) in reg_dhx_miners.iter().enumerate() { - miner_count += 1; - log::info!("rewards loop - miner_count {:#?}", miner_count); - log::info!("rewards loop - miner {:#?}", miner); - - // only run the following once per day per miner until rewards_allowance_dhx_for_date_remaining is exhausted - // but since we're giving each registered miner a proportion of the daily reward allowance - // (if their aggregated rewards is above daily allowance) each proportion is rounded down, - // it shouldn't become exhausted anyway - let is_already_distributed = >::get(start_of_requested_date_millis.clone()); - if is_already_distributed == Some(true) { - log::error!("Unable to distribute further rewards allowance today"); - return 0; - } - - let daily_reward_for_miner_as_u128; - let daily_reward_for_miner_to_try = >::get( - ( - start_of_requested_date_millis.clone(), - miner.clone(), - ), - ); - if let Some(_daily_reward_for_miner_to_try) = daily_reward_for_miner_to_try.clone() { - let _daily_reward_for_miner_as_u128 = Self::convert_balance_to_u128(_daily_reward_for_miner_to_try.clone()); - match _daily_reward_for_miner_as_u128.clone() { - Err(_e) => { - log::error!("Unable to convert balance to u128 for daily_reward_for_miner_as_u128"); - return 0; - }, - Ok(x) => { - daily_reward_for_miner_as_u128 = x; - } - } - } else { - // If any of the miner's don't have a reward, we won't waste storing that, - // so we want to move to the next miner in the loop - log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner.clone()); - continue; - } - log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); - - let mut manageable_daily_reward_for_miner_as_u128 = 0u128; - if let Some(_manageable_daily_reward_for_miner_as_u128) = - daily_reward_for_miner_as_u128.clone().checked_div(1000000000000000000u128) { - manageable_daily_reward_for_miner_as_u128 = _manageable_daily_reward_for_miner_as_u128; - } else { - log::error!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); - return 0; - } - - // Multiply, handling overflow - // TODO - probably have to initialise below proportion_of_daily_reward_for_miner_fixed128 to 0u128, - // and convert distribution_multiplier_for_day_fixed128 to u64, - // and convert daily_reward_for_miner_as_u128 to u64 too, like i did earlier. - // but it works so this doesn't seem necessary. - let proportion_of_daily_reward_for_miner_fixed128; - let _proportion_of_daily_reward_for_miner_fixed128 = - U64F64::from_num(distribution_multiplier_for_day_fixed128.clone()).checked_mul(U64F64::from_num(manageable_daily_reward_for_miner_as_u128.clone())); - match _proportion_of_daily_reward_for_miner_fixed128 { - None => { - log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); - return 0; - }, - Some(x) => { - proportion_of_daily_reward_for_miner_fixed128 = x; - } - } - log::info!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); - - // round down to nearest integer. we need to round down, because if we round up then if there are - // 3x registered miners with 5000 DHX rewards allowance per day then they would each get 1667 rewards, - // but there would only be 1666 remaining after the first two, so the last one would miss out. - // so if we round down they each get 1666 DHX and there is 2 DHX from the daily allocation that doesn't get distributed at all. - let proportion_of_daily_reward_for_miner_u128: u128 = proportion_of_daily_reward_for_miner_fixed128.floor().to_num::(); - - // we lose some accuracy doing this conversion, but at least we split the bulk of the rewards proportionally and fairly - let mut restored_proportion_of_daily_reward_for_miner_u128 = 0u128; - if let Some(_restored_proportion_of_daily_reward_for_miner_u128) = - proportion_of_daily_reward_for_miner_u128.clone().checked_mul(1000000000000000000u128) { - restored_proportion_of_daily_reward_for_miner_u128 = _restored_proportion_of_daily_reward_for_miner_u128; - } else { - log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); - return 0; - } - - // println!("[rewards] block: {:#?}, miner: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", _n, miner_count, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); - - let treasury_account_id: T::AccountId = >::account_id(); - let max_payout = pallet_balances::Pallet::::usable_balance(treasury_account_id.clone()); - log::info!("Treasury account id: {:?}", treasury_account_id.clone()); - log::info!("Miner to receive reward: {:?}", miner.clone()); - log::info!("Treasury balance max payout: {:?}", max_payout.clone()); - - let proportion_of_daily_reward_for_miner; - let _proportion_of_daily_reward_for_miner = Self::convert_u128_to_balance(restored_proportion_of_daily_reward_for_miner_u128.clone()); - match _proportion_of_daily_reward_for_miner { - Err(_e) => { - log::error!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); - return 0; - }, - Ok(ref x) => { - proportion_of_daily_reward_for_miner = x; - } - } - - let max_payout_as_u128; - if let Some(_max_payout_as_u128) = TryInto::::try_into(max_payout).ok() { - max_payout_as_u128 = _max_payout_as_u128; - } else { - log::error!("Unable to convert Balance to u128 for max_payout"); - return 0; - } - log::info!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); - - // Store output `rewards_allowance_dhx_remaining_today_as_u128` outside the loop - // Validate inputs so the daily_rewards is less or equal to the existing_allowance - if let Some(_rewards_allowance_dhx_remaining_today) = >::get(&start_of_requested_date_millis) { - let _rewards_allowance_dhx_remaining_today_as_u128 = Self::convert_balance_to_u128(_rewards_allowance_dhx_remaining_today.clone()); - match _rewards_allowance_dhx_remaining_today_as_u128.clone() { - Err(_e) => { - log::error!("Unable to convert balance to u128"); - return 0; - }, - Ok(x) => { - rewards_allowance_dhx_remaining_today_as_u128 = x; - } - } - log::info!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); - } else { - log::error!("Unable to retrieve balance from value provided."); - return 0; - } - - // println!("[prepared-for-payment] block: {:#?}, miner: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", _n, miner_count, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); - - // check if miner's reward is less than or equal to: rewards_allowance_dhx_daily_remaining - if restored_proportion_of_daily_reward_for_miner_u128.clone() > 0u128 && - rewards_allowance_dhx_remaining_today_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() && - max_payout_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() - { - // pay the miner their daily reward - info!("Paying the miner a proportion of the remaining daily reward allowance"); - - let tx_result; - let _tx_result = ::Currency::transfer( - &treasury_account_id, - &miner.clone(), - proportion_of_daily_reward_for_miner.clone(), - ExistenceRequirement::KeepAlive - ); - match _tx_result { - Err(_e) => { - log::error!("Unable to transfer from treasury to miner {:?}", miner.clone()); - return 0; - }, - Ok(ref x) => { - tx_result = x; - } - } - info!("Transfer to the miner tx_result: {:?}", tx_result.clone()); + return 0; - info!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); + // TODO - move the below into an extrinsic function - // TODO - move into function `reduce_rewards_allowance_dhx_for_date_remaining`? + // // TODO - consider the miner's mPower that we have fetched. it should have been added earlier above + // // to the aggregated (all miners for that day) and accumulated (specific miner for a day) rewards - // Subtract, handling overflow - let new_rewards_allowance_dhx_remaining_today_as_u128; - let _new_rewards_allowance_dhx_remaining_today_as_u128 = - rewards_allowance_dhx_remaining_today_as_u128.clone().checked_sub(restored_proportion_of_daily_reward_for_miner_u128.clone()); - match _new_rewards_allowance_dhx_remaining_today_as_u128 { - None => { - log::error!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); - return 0; - }, - Some(x) => { - new_rewards_allowance_dhx_remaining_today_as_u128 = x; - } - } - - let new_rewards_allowance_dhx_remaining_today; - let _new_rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(new_rewards_allowance_dhx_remaining_today_as_u128.clone()); - match _new_rewards_allowance_dhx_remaining_today { - Err(_e) => { - log::error!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); - return 0; - }, - Ok(ref x) => { - new_rewards_allowance_dhx_remaining_today = x; - } - } + // // fetch accumulated total rewards for all registered miners for the day + // // TODO - we've done this twice, create a function to fetch it + // let mut rewards_aggregated_dhx_daily: BalanceOf = 0u32.into(); // initialize + // if let Some(_rewards_aggregated_dhx_daily) = >::get(&start_of_requested_date_millis) { + // rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; + // } else { + // log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period may not be finished yet"); + // // Note: it would be an issue if we got past the first loop of looping through the registered miners + // // and still hadn't added to the aggregated rewards for the day + // return 0; + // } + // // println!("[multiplier] block: {:#?}, miner: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, miner_count, start_of_requested_date_millis, rewards_aggregated_dhx_daily); - // Write the new value to storage - >::insert( - start_of_requested_date_millis.clone(), - new_rewards_allowance_dhx_remaining_today.clone(), - ); + // if rewards_aggregated_dhx_daily == 0u32.into() { + // log::error!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); + // return 0; + // } - // println!("[paid] block: {:#?}, miner: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", _n, miner_count, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); + // let rewards_aggregated_dhx_daily_as_u128; + // let _rewards_aggregated_dhx_daily_as_u128 = Self::convert_balance_to_u128(rewards_aggregated_dhx_daily.clone()); + // match _rewards_aggregated_dhx_daily_as_u128.clone() { + // Err(_e) => { + // log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); + // return 0; + // }, + // Ok(x) => { + // rewards_aggregated_dhx_daily_as_u128 = x; + // } + // } + // log::info!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); - // emit event with reward payment history rather than bloating storage - Self::deposit_event(Event::TransferredRewardsAllowanceDHXToMinerForDate( - start_of_requested_date_millis.clone(), - proportion_of_daily_reward_for_miner.clone(), - new_rewards_allowance_dhx_remaining_today.clone(), - miner.clone(), - )); + // // TODO - we've done this twice, create a function to fetch it + // let rewards_allowance_dhx_daily; + // if let Some(_rewards_allowance_dhx_daily) = >::get() { + // rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; + // } else { + // log::error!("Unable to get rewards_allowance_dhx_daily"); + // return 0; + // } - log::info!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", - start_of_requested_date_millis.clone(), - proportion_of_daily_reward_for_miner.clone(), - new_rewards_allowance_dhx_remaining_today.clone(), - miner.clone(), - ); + // let rewards_allowance_dhx_daily_u128; + // let _rewards_allowance_dhx_daily_u128 = Self::convert_balance_to_u128(rewards_allowance_dhx_daily.clone()); + // match _rewards_allowance_dhx_daily_u128.clone() { + // Err(_e) => { + // log::error!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); + // return 0; + // }, + // Ok(x) => { + // rewards_allowance_dhx_daily_u128 = x; + // } + // } - continue; - } else { - log::error!("Insufficient remaining rewards allowance to pay daily reward to miner"); + // if rewards_allowance_dhx_daily_u128 == 0u128 { + // log::error!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); + // return 0; + // } - break; - } - } + // // previously when we looped through all the registered dhx miners we calculated the + // // reward for each registered miner based on the 10:1 ratio, and stored that along with + // // the corresponding day in storage. since that loop we've fetched the total + // // aggregated rewards that all reg miners are eligible for on that day as `rewards_aggregated_dhx_daily`, + // // lets say it adds up to 8000 DHX, but say we only have 5000 DHX availabe to distribute + // // from `rewards_allowance_dhx_daily`, so we'll constrain the rewards they'll receive further by + // // applying a `distribution_multiplier_for_day_u128` of (5000/8000)*reg_miner_reward on each of + // // the rewards that are distributed to them. + + // // if the aggregated rewards isn't more than the daily rewards allowance available + // // then just set the multiplier to 1, so they actually get the previously calculated reward rather + // // than a scaled down proportion. + // // + // // e.g. 1: if miner rewards are 2000 & 4000 DHX respectively, this is greater than 5000 DHX daily allowance + // // so we'd have a multiplier of 5000/6000 = 5/6, so they'd receive ~1666 & 3333 DHX respectively. + // // e.g. 2: if miner rewards are 2000 & 2000 DHX respectively, this is less than 5000 DHX daily allowance + // // so we'd just use a multiplier of 1, so they'd receive 2000 & 2000 DHX respectively. + // // https://docs.rs/fixed/0.5.4/fixed/struct.FixedU128.html + // let mut distribution_multiplier_for_day_fixed128 = FixedU128::from_num(1); // initialize + + // if rewards_aggregated_dhx_daily_as_u128.clone() > rewards_allowance_dhx_daily_u128.clone() { + // // Divide, handling overflow + + // // Note: If the rewards_allowance_dhx_daily_u128 is 5000 DHX, its 5000000000000000000000, + // // but we can't convert to u64 since largest value is 18446744073709551615. + // // Since we expect the rewards_aggregated_dhx_daily_as_u128 to be at least 1 DHX (i.e. 1000000000000000000), + // // we could just divide both numbers by 1000000000000000000, so we'd have say 5000 and 1 instead, + // // since we're just using these values to get a multiplier output. + + // let mut manageable_rewards_allowance_dhx_daily_u128 = 0u128; + // if let Some(_manageable_rewards_allowance_dhx_daily_u128) = + // rewards_allowance_dhx_daily_u128.clone().checked_div(1000000000000000000u128) { + // manageable_rewards_allowance_dhx_daily_u128 = _manageable_rewards_allowance_dhx_daily_u128; + // } else { + // log::error!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); + // return 0; + // } + + // let mut rewards_allowance_dhx_daily_u64 = 0u64; + // if let Some(_rewards_allowance_dhx_daily_u64) = + // TryInto::::try_into(manageable_rewards_allowance_dhx_daily_u128.clone()).ok() { + // rewards_allowance_dhx_daily_u64 = _rewards_allowance_dhx_daily_u64; + // } else { + // log::error!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); + // return 0; + // } + + // let mut manageable_rewards_aggregated_dhx_daily_as_u128 = 0u128; + // if let Some(_manageable_rewards_aggregated_dhx_daily_as_u128) = rewards_aggregated_dhx_daily_as_u128.clone().checked_div(1000000000000000000u128) { + // manageable_rewards_aggregated_dhx_daily_as_u128 = _manageable_rewards_aggregated_dhx_daily_as_u128; + // } else { + // log::error!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); + // return 0; + // } + + // let mut rewards_aggregated_dhx_daily_as_u64 = 0u64; + // if let Some(_rewards_aggregated_dhx_daily_as_u64) = + // TryInto::::try_into(manageable_rewards_aggregated_dhx_daily_as_u128.clone()).ok() { + // rewards_aggregated_dhx_daily_as_u64 = _rewards_aggregated_dhx_daily_as_u64; + // } else { + // log::error!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); + // return 0; + // } + + // // See https://github.com/ltfschoen/substrate-node-template/pull/6/commits/175ef4805d07093042431c5814dda52da1ebde18 + // let _fraction_distribution_multiplier_for_day_fixed128 = + // U64F64::from_num(manageable_rewards_allowance_dhx_daily_u128.clone()) + // .checked_div(U64F64::from_num(manageable_rewards_aggregated_dhx_daily_as_u128.clone())); + // let _distribution_multiplier_for_day_fixed128 = _fraction_distribution_multiplier_for_day_fixed128.clone(); + // match _distribution_multiplier_for_day_fixed128 { + // None => { + // log::error!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); + // return 0; + // }, + // Some(x) => { + // distribution_multiplier_for_day_fixed128 = x; + // } + // } + // } + // log::info!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); + // // println!("[multiplier] block: {:#?}, miner: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, miner_count, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); + + // // Initialise outside the loop as we need this value after the loop after we finish iterating through all the miners + // let mut rewards_allowance_dhx_remaining_today_as_u128 = 0u128; + + // miner_count = 0; + // for (index, miner) in reg_dhx_miners.iter().enumerate() { + // miner_count += 1; + // log::info!("rewards loop - miner_count {:#?}", miner_count); + // log::info!("rewards loop - miner {:#?}", miner); + + // // only run the following once per day per miner until rewards_allowance_dhx_for_date_remaining is exhausted + // // but since we're giving each registered miner a proportion of the daily reward allowance + // // (if their aggregated rewards is above daily allowance) each proportion is rounded down, + // // it shouldn't become exhausted anyway + // let is_already_distributed = >::get(start_of_requested_date_millis.clone()); + // if is_already_distributed == Some(true) { + // log::error!("Unable to distribute further rewards allowance today"); + // return 0; + // } + + // let daily_reward_for_miner_as_u128; + // let daily_reward_for_miner_to_try = >::get( + // ( + // start_of_requested_date_millis.clone(), + // miner.clone(), + // ), + // ); + // if let Some(_daily_reward_for_miner_to_try) = daily_reward_for_miner_to_try.clone() { + // let _daily_reward_for_miner_as_u128 = Self::convert_balance_to_u128(_daily_reward_for_miner_to_try.clone()); + // match _daily_reward_for_miner_as_u128.clone() { + // Err(_e) => { + // log::error!("Unable to convert balance to u128 for daily_reward_for_miner_as_u128"); + // return 0; + // }, + // Ok(x) => { + // daily_reward_for_miner_as_u128 = x; + // } + // } + // } else { + // // If any of the miner's don't have a reward, we won't waste storing that, + // // so we want to move to the next miner in the loop + // log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner.clone()); + // continue; + // } + // log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); + + // let mut manageable_daily_reward_for_miner_as_u128 = 0u128; + // if let Some(_manageable_daily_reward_for_miner_as_u128) = + // daily_reward_for_miner_as_u128.clone().checked_div(1000000000000000000u128) { + // manageable_daily_reward_for_miner_as_u128 = _manageable_daily_reward_for_miner_as_u128; + // } else { + // log::error!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); + // return 0; + // } + + // // Multiply, handling overflow + // // TODO - probably have to initialise below proportion_of_daily_reward_for_miner_fixed128 to 0u128, + // // and convert distribution_multiplier_for_day_fixed128 to u64, + // // and convert daily_reward_for_miner_as_u128 to u64 too, like i did earlier. + // // but it works so this doesn't seem necessary. + // let proportion_of_daily_reward_for_miner_fixed128; + // let _proportion_of_daily_reward_for_miner_fixed128 = + // U64F64::from_num(distribution_multiplier_for_day_fixed128.clone()).checked_mul(U64F64::from_num(manageable_daily_reward_for_miner_as_u128.clone())); + // match _proportion_of_daily_reward_for_miner_fixed128 { + // None => { + // log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); + // return 0; + // }, + // Some(x) => { + // proportion_of_daily_reward_for_miner_fixed128 = x; + // } + // } + // log::info!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); + + // // round down to nearest integer. we need to round down, because if we round up then if there are + // // 3x registered miners with 5000 DHX rewards allowance per day then they would each get 1667 rewards, + // // but there would only be 1666 remaining after the first two, so the last one would miss out. + // // so if we round down they each get 1666 DHX and there is 2 DHX from the daily allocation that doesn't get distributed at all. + // let proportion_of_daily_reward_for_miner_u128: u128 = proportion_of_daily_reward_for_miner_fixed128.floor().to_num::(); + + // // we lose some accuracy doing this conversion, but at least we split the bulk of the rewards proportionally and fairly + // let mut restored_proportion_of_daily_reward_for_miner_u128 = 0u128; + // if let Some(_restored_proportion_of_daily_reward_for_miner_u128) = + // proportion_of_daily_reward_for_miner_u128.clone().checked_mul(1000000000000000000u128) { + // restored_proportion_of_daily_reward_for_miner_u128 = _restored_proportion_of_daily_reward_for_miner_u128; + // } else { + // log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); + // return 0; + // } + + // // println!("[rewards] block: {:#?}, miner: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); + + // let treasury_account_id: T::AccountId = >::account_id(); + // let max_payout = pallet_balances::Pallet::::usable_balance(treasury_account_id.clone()); + // log::info!("Treasury account id: {:?}", treasury_account_id.clone()); + // log::info!("Miner to receive reward: {:?}", miner.clone()); + // log::info!("Treasury balance max payout: {:?}", max_payout.clone()); + + // let proportion_of_daily_reward_for_miner; + // let _proportion_of_daily_reward_for_miner = Self::convert_u128_to_balance(restored_proportion_of_daily_reward_for_miner_u128.clone()); + // match _proportion_of_daily_reward_for_miner { + // Err(_e) => { + // log::error!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); + // return 0; + // }, + // Ok(ref x) => { + // proportion_of_daily_reward_for_miner = x; + // } + // } + + // let max_payout_as_u128; + // if let Some(_max_payout_as_u128) = TryInto::::try_into(max_payout).ok() { + // max_payout_as_u128 = _max_payout_as_u128; + // } else { + // log::error!("Unable to convert Balance to u128 for max_payout"); + // return 0; + // } + // log::info!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); + + // // Store output `rewards_allowance_dhx_remaining_today_as_u128` outside the loop + // // Validate inputs so the daily_rewards is less or equal to the existing_allowance + // if let Some(_rewards_allowance_dhx_remaining_today) = >::get(&start_of_requested_date_millis) { + // let _rewards_allowance_dhx_remaining_today_as_u128 = Self::convert_balance_to_u128(_rewards_allowance_dhx_remaining_today.clone()); + // match _rewards_allowance_dhx_remaining_today_as_u128.clone() { + // Err(_e) => { + // log::error!("Unable to convert balance to u128"); + // return 0; + // }, + // Ok(x) => { + // rewards_allowance_dhx_remaining_today_as_u128 = x; + // } + // } + // log::info!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); + // } else { + // log::error!("Unable to retrieve balance from value provided."); + // return 0; + // } + + // // println!("[prepared-for-payment] block: {:#?}, miner: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, miner_count, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); + + // // check if miner's reward is less than or equal to: rewards_allowance_dhx_daily_remaining + // if restored_proportion_of_daily_reward_for_miner_u128.clone() > 0u128 && + // rewards_allowance_dhx_remaining_today_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() && + // max_payout_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() + // { + // // pay the miner their daily reward + // info!("Paying the miner a proportion of the remaining daily reward allowance"); + + // let tx_result; + // let _tx_result = ::Currency::transfer( + // &treasury_account_id, + // &miner.clone(), + // proportion_of_daily_reward_for_miner.clone(), + // ExistenceRequirement::KeepAlive + // ); + // match _tx_result { + // Err(_e) => { + // log::error!("Unable to transfer from treasury to miner {:?}", miner.clone()); + // return 0; + // }, + // Ok(ref x) => { + // tx_result = x; + // } + // } + // info!("Transfer to the miner tx_result: {:?}", tx_result.clone()); + + // info!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); + + // // TODO - move into function `reduce_rewards_allowance_dhx_for_date_remaining`? + + // // Subtract, handling overflow + // let new_rewards_allowance_dhx_remaining_today_as_u128; + // let _new_rewards_allowance_dhx_remaining_today_as_u128 = + // rewards_allowance_dhx_remaining_today_as_u128.clone().checked_sub(restored_proportion_of_daily_reward_for_miner_u128.clone()); + // match _new_rewards_allowance_dhx_remaining_today_as_u128 { + // None => { + // log::error!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); + // return 0; + // }, + // Some(x) => { + // new_rewards_allowance_dhx_remaining_today_as_u128 = x; + // } + // } + + // let new_rewards_allowance_dhx_remaining_today; + // let _new_rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(new_rewards_allowance_dhx_remaining_today_as_u128.clone()); + // match _new_rewards_allowance_dhx_remaining_today { + // Err(_e) => { + // log::error!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); + // return 0; + // }, + // Ok(ref x) => { + // new_rewards_allowance_dhx_remaining_today = x; + // } + // } + + // // Write the new value to storage + // >::insert( + // start_of_requested_date_millis.clone(), + // new_rewards_allowance_dhx_remaining_today.clone(), + // ); + + // // println!("[paid] block: {:#?}, miner: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); + + // // emit event with reward payment history rather than bloating storage + // Self::deposit_event(Event::TransferredRewardsAllowanceDHXToMinerForDate( + // start_of_requested_date_millis.clone(), + // proportion_of_daily_reward_for_miner.clone(), + // new_rewards_allowance_dhx_remaining_today.clone(), + // miner.clone(), + // )); + + // log::info!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", + // start_of_requested_date_millis.clone(), + // proportion_of_daily_reward_for_miner.clone(), + // new_rewards_allowance_dhx_remaining_today.clone(), + // miner.clone(), + // ); + + // continue; + // } else { + // log::error!("Insufficient remaining rewards allowance to pay daily reward to miner"); + + // break; + // } + // } - let rewards_allowance_dhx_remaining_today; - let _rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(rewards_allowance_dhx_remaining_today_as_u128.clone()); - match _rewards_allowance_dhx_remaining_today { - Err(_e) => { - log::error!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); - return 0; - }, - Ok(ref x) => { - rewards_allowance_dhx_remaining_today = x; - } - } + // let rewards_allowance_dhx_remaining_today; + // let _rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(rewards_allowance_dhx_remaining_today_as_u128.clone()); + // match _rewards_allowance_dhx_remaining_today { + // Err(_e) => { + // log::error!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); + // return 0; + // }, + // Ok(ref x) => { + // rewards_allowance_dhx_remaining_today = x; + // } + // } - >::insert( - start_of_requested_date_millis.clone(), - true - ); + // >::insert( + // start_of_requested_date_millis.clone(), + // true + // ); - // println!("[distributed] block: {:#?}, miner: {:#?}, date_start: {:#?} ", _n, miner_count, start_of_requested_date_millis); + // // println!("[distributed] block: {:#?}, miner: {:#?}, date_start: {:#?} ", block_number, miner_count, start_of_requested_date_millis); - Self::deposit_event(Event::DistributedRewardsAllowanceDHXForDateRemaining( - start_of_requested_date_millis.clone(), - rewards_allowance_dhx_remaining_today.clone(), - )); + // Self::deposit_event(Event::DistributedRewardsAllowanceDHXForDateRemaining( + // start_of_requested_date_millis.clone(), + // rewards_allowance_dhx_remaining_today.clone(), + // )); - return 0; + // return 0; } // `on_finalize` is executed at the end of block after all extrinsic are dispatched. - fn on_finalize(_n: T::BlockNumber) { + fn on_finalize(block_number: T::BlockNumber) { // Perform necessary data/state clean up here. } } @@ -2301,6 +2296,40 @@ pub mod pallet { // Private functions impl Pallet { + fn should_process_block(block_number: T::BlockNumber) -> bool { + let block_one = 1u32; + let block_one_as_block; + if let Some(_block_one) = TryInto::::try_into(block_one).ok() { + block_one_as_block = _block_one; + } else { + log::error!("Unable to convert u32 to BlockNumber"); + return false; + } + + // skip block #1 since timestamp is 0 in blocks before block #2 + if block_number == block_one_as_block.clone() { + return false; + } else { + return true; + } + } + + fn is_block_two(block_number: T::BlockNumber) -> bool { + let block_two = 2u32; + let block_two_as_block; + if let Some(_block_two) = TryInto::::try_into(block_two).ok() { + block_two_as_block = _block_two; + } else { + log::error!("Unable to convert u32 to BlockNumber"); + return false; + } + if block_number.clone() == block_two_as_block.clone() { + return true; + } else { + return false; + } + } + fn convert_moment_to_u64_in_milliseconds(date: T::Moment) -> Result { let date_as_u64_millis; if let Some(_date_as_u64) = TryInto::::try_into(date).ok() { From 3653ab20ea10afefbebd890ab3b706e4154fe366 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 15 Nov 2021 09:12:44 +0100 Subject: [PATCH 14/37] wip --- pallets/mining/rewards-allowance/src/lib.rs | 193 +++++++++--------- pallets/mining/rewards-allowance/src/tests.rs | 14 +- 2 files changed, 108 insertions(+), 99 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 51d2a2738..8d88c8863 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -584,10 +584,6 @@ pub mod pallet { /// \[date, amount_dhx_bonded, account_dhx_bonded\] SetBondedDHXOfAccountForDateStored(Date, BalanceOf, T::AccountId), - /// Storage of the mPower of an account on a specific date. - /// \[date, amount_mpower, account\] - SetMPowerOfAccountForDateStored(Date, Vec, u128), - /// Storage of the default daily reward allowance in DHX by an origin account. /// \[amount_dhx, sender\] SetRewardsAllowanceDHXDailyStored(BalanceOf, T::AccountId), @@ -634,7 +630,7 @@ pub mod pallet { // Off-chain workers /// Event generated when new mPower data is accepted to contribute to the rewards allowance. - /// \[start_date_received, registered_dhx_miner_account_id, mpower\] + /// \[start_date_requested, registered_dhx_miner_account_id, mpower\] NewMPowerForAccountForDate(Date, Vec, u128), // NewMPowerForAccountForDate(Date, T::AccountId, u128), } @@ -1085,6 +1081,48 @@ pub mod pallet { return; }; + // TODO - fetch the mpower from off-chain and store it with `set_mpower_of_account_for_date` + // but only for the reg_dhx_miners + // so we can iterate through the miners and retrieve the mPower of each miner for the current date with + // `MPowerForAccountForDate` + // and check if mPower for current miner being iterated is greather than the min. mPower that is required. + + // after fetching the mpower values store by sending an unsigned transactions + let should_send = Self::choose_transaction_type(block_number.clone()); + let mut res; + let mut mpower_data_vec = vec![]; + match should_send { + TransactionType::Raw => { + let _mpower_res = Self::fetch_mpower_process(block_number.clone(), start_of_requested_date_millis.clone()); + match _mpower_res.clone() { + Err(e) => { + log::error!("offchain_workers error fetching mpower: {}", e); + return; + }, + Ok(x) => { + mpower_data_vec = x; + } + } + }, + TransactionType::None => { + log::error!("offchain_workers error unknown transaction type"); + return; + }, + }; + + // TODO - remove all the fetched accounts from vector that aren't in the list of + // reg_dhx_miners, since we add the list of registered dhx miners from a signed account to + // and use it incase the API endpoint is compromised by hackers and fake accounts and mpower data are provided + + // TODO - change reg_dhx_miners functionality so it may be stored via an extrinsic function + // and voted on by governance, and so it just includes a list of account addresses that we check against. + // if the list needs to be changed then just call it and add all of them again once approved. + + res = Self::store_mpower_raw_unsigned(block_number.clone(), start_of_requested_date_millis.clone(), mpower_data_vec.clone()); + if let Err(e) = res { + log::error!("offchain_workers error storing mpower: {}", e); + } + let mut miner_count = 0; for (index, miner) in reg_dhx_miners.iter().enumerate() { @@ -1200,27 +1238,26 @@ pub mod pallet { } // println!("min_mpower_daily_u128 {:#?}", min_mpower_daily_u128); - // TODO - integrate this with functionality of off-chain workers function where we - // fetch the mpower from off-chain and store it with `set_mpower_of_account_for_date` // TODO - fetch the mPower of the miner currently being iterated to check if it's greater than the min. // mPower that is required let mut mpower_current_u128: u128 = 0u128; - // let _mpower_current_u128 = >::get((start_of_requested_date_millis.clone(), miner.clone())); - // FIXME - this is temporary - let _mpower_data = ( - Some(0u128), - start_of_requested_date_millis.clone(), - 1u64, - ); - match _mpower_data.0 { - None => { - log::error!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); - // println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); - }, - Some(x) => { - mpower_current_u128 = x; - } - } + + let _mpower_current_u128 = >::get((start_of_requested_date_millis.clone(), miner.clone())); + // // FIXME - this is temporary + // let _mpower_data = ( + // Some(0u128), + // start_of_requested_date_millis.clone(), + // 1u64, + // ); + // match _mpower_data.0 { + // None => { + // log::error!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); + // // println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); + // }, + // Some(x) => { + // mpower_current_u128 = x; + // } + // } log::info!("mpower_current_u128 {:#?}, {:?}", mpower_current_u128, start_of_requested_date_millis.clone()); // println!("mpower_current_u128 {:#?}, {:?}", mpower_current_u128, start_of_requested_date_millis.clone()); @@ -1588,16 +1625,6 @@ pub mod pallet { log::info!("Finished initial loop of registered miners"); println!("Finished initial loop of registered miners"); - - // We are going to send unsigned transactions - let should_send = Self::choose_transaction_type(block_number); - let res = match should_send { - TransactionType::Raw => Self::fetch_mpower_and_send_raw_unsigned(block_number), - TransactionType::None => Ok(()), - }; - if let Err(e) = res { - log::error!("offchain_workers error: {}", e); - } } // `on_initialize` is executed at the beginning of the block before any extrinsic are @@ -2262,12 +2289,13 @@ pub mod pallet { pub fn submit_mpower_unsigned( origin: OriginFor, _block_number: T::BlockNumber, + start_of_requested_date_millis: Date, mpower_payload_vec: Vec>, ) -> DispatchResultWithPostInfo { // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; // Add the mpower vec on-chain, but mark it as coming from an empty address. - Self::add_mpower(Default::default(), mpower_payload_vec.clone()); + Self::add_mpower(Default::default(), start_of_requested_date_millis.clone(), mpower_payload_vec.clone()); // now increment the block number at which we expect next unsigned transaction. let current_block = >::block_number(); >::put(current_block + T::UnsignedInterval::get()); @@ -2285,8 +2313,8 @@ pub mod pallet { /// here we make sure that some particular calls (the ones produced by offchain worker) /// are being whitelisted and marked as valid. fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { - if let Call::submit_mpower_unsigned(block_number, new_mpower_data_vec) = call { - Self::validate_transaction_parameters(block_number, new_mpower_data_vec) + if let Call::submit_mpower_unsigned(block_number, start_of_requested_date_millis, new_mpower_data_vec) = call { + Self::validate_transaction_parameters(block_number, start_of_requested_date_millis, new_mpower_data_vec) } else { InvalidTransaction::Call.into() } @@ -2530,37 +2558,30 @@ pub mod pallet { Ok(bonded_dhx_current_u128.clone()) } - // FIXME - we're using `next_start_date`, but in off-chain workers we'll try doing it all on the same date we received it - // we need to set the mPower for the next start date so it's available from off-chain in time - pub fn set_mpower_of_account_for_date(account_id: Vec, mpower: u128, next_start_date: Date) -> Result { - // pub fn set_mpower_of_account_for_date(account_id: T::AccountId, mpower: u128, next_start_date: Date) -> Result { - // // Note: we DO need the following as we're using the current timestamp, rather than a function parameter. - // let timestamp: ::Moment = >::get(); - // let requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone())?; - // log::info!("set_mpower_of_account_for_date - requested_date_as_u64: {:?}", requested_date_as_u64.clone()); - - // convert the requested date/time to the start of that day date/time to signify that date for lookup - // i.e. 21 Apr @ 1420 -> 21 Apr @ 0000 - let start_of_next_start_date_millis = Self::convert_i64_in_milliseconds_to_start_of_date(next_start_date.clone())?; - + // TODO - this is an internal function, do we want to create an extrinsic too that + // governance may choose to call to set the mpower of an account for a date if it needs to be corrected in future + // before they claim? + pub fn set_mpower_of_account_for_date(account_id: Vec, start_of_requested_date_millis: Date, mpower: u128) -> Result { let mpower_current_u128 = mpower.clone(); // Update storage. Override the default that may have been set in on_initialize >::insert( ( - start_of_next_start_date_millis.clone(), + start_of_requested_date_millis.clone(), account_id.clone(), ), mpower_current_u128.clone(), ); - log::info!("set_mpower_of_account_for_date - start_of_next_start_date_millis: {:?}", &start_of_next_start_date_millis); - log::info!("set_mpower_of_account_for_date - account_id: {:?}", &account_id); - log::info!("set_mpower_of_account_for_date - mpower_current: {:?}", &mpower_current_u128); + log::info!("Added MPowerForAccountForDate {:?} {:?} {:?}", + start_of_requested_date_millis.clone(), + account_id.clone(), + mpower_current_u128.clone(), + ); // Emit an event. - Self::deposit_event(Event::SetMPowerOfAccountForDateStored( - start_of_next_start_date_millis.clone(), + Self::deposit_event(Event::NewMPowerForAccountForDate( + start_of_requested_date_millis.clone(), account_id.clone(), mpower_current_u128.clone(), )); @@ -2722,8 +2743,8 @@ pub mod pallet { } } - /// A helper function to fetch the mpower and send a raw unsigned transaction. - fn fetch_mpower_and_send_raw_unsigned(block_number: T::BlockNumber) -> Result<(), &'static str> { + /// A helper function to fetch the mpower + fn fetch_mpower_process(block_number: T::BlockNumber, start_of_requested_date_millis: Date) -> Result>, &'static str> { // Make sure we don't fetch the mpower if unsigned transaction is going to be rejected // anyway. let next_unsigned_at = >::get(); @@ -2733,12 +2754,17 @@ pub mod pallet { // Make an external HTTP request to fetch the current mpower. // Note this call will block until response is received. - let mpower_data_vec: Vec> = Self::fetch_mpower(block_number.clone()).map_err(|_| "Failed to fetch mpower data vec")?; + let mpower_data_vec: Vec> = Self::fetch_mpower(block_number.clone(), start_of_requested_date_millis.clone()).map_err(|_| "Failed to fetch mpower data vec")?; + Ok(mpower_data_vec.clone()) + } + + /// A helper function to send a raw unsigned transaction to store the mpower data. + fn store_mpower_raw_unsigned(block_number: T::BlockNumber, start_of_requested_date_millis: Date, mpower_data_vec: Vec>) -> Result<(), &'static str> { // Received mpower data is wrapped into a call to `submit_mpower_unsigned` public function of this // pallet. This means that the transaction, when executed, will simply call that function // passing `mpower_data_vec` as an argument. - let call = Call::submit_mpower_unsigned(block_number, mpower_data_vec); + let call = Call::submit_mpower_unsigned(block_number.clone(), start_of_requested_date_millis.clone(), mpower_data_vec.clone()); // Now let's create a transaction out of this call and submit it to the pool. // Here we showcase two ways to send an unsigned transaction / unsigned payload (raw) @@ -2755,7 +2781,7 @@ pub mod pallet { } /// Fetch current mPower and return the result. - fn fetch_mpower(block_number: T::BlockNumber) -> Result>, http::Error> { + fn fetch_mpower(block_number: T::BlockNumber, start_of_requested_date_millis: Date) -> Result>, http::Error> { // We want to keep the offchain worker execution time reasonable, so we set a hard-coded // deadline to 2s to complete the external call. // You can also wait idefinitely for the response, however you may still get a timeout @@ -2766,8 +2792,13 @@ pub mod pallet { // you can find in `sp_io`. The API is trying to be similar to `reqwest`, but // since we are running in a custom WASM execution environment we can't simply // import the library here. + + // Example from Substrate + // let request = + // http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); + // Example of request we may use let request = - http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); + http::Request::get("https://api.datahighway.com/price?start_of_requested_date_millis=BTC"); // We set the deadline for sending of the request, note that awaiting response can // have a separate deadline. Next we send the request, before that it's also possible // to alter request headers or stream body content in case of non-GET requests. @@ -2805,7 +2836,8 @@ pub mod pallet { "data": [ { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "11" }, { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "12" } - ] + ], + "start_of_requested_date_millis": "1630195200000", }"#; let mpower_data_vec = match Self::parse_mpower_data(mpower_data, block_number.clone()) { @@ -2942,41 +2974,17 @@ pub mod pallet { } /// Add new mPower on-chain. - fn add_mpower(who: T::AccountId, mpower_data_vec: Vec>) -> Option>> { - log::info!("Adding mPower to storage"); + fn add_mpower(account_id: T::AccountId, start_of_requested_date_millis: Date, mpower_data_vec: Vec>) -> Option>> { + log::info!("Adding mPower to storage for date: {:?}", start_of_requested_date_millis.clone()); - let timestamp = >::get(); - let received_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()).ok()?; - log::info!("received_date_as_u64: {:?}", received_date_as_u64.clone()); - // convert the received date/time to the start of that day date/time to signify that date for lookup - // i.e. 21 Apr @ 1420 -> 21 Apr @ 0000 - let start_of_received_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(received_date_as_u64.clone()).ok()?; - log::info!("start_of_received_date_millis: {:?}", start_of_received_date_millis.clone()); + // TODO - convert AccountId into Vec for (index, mpower_data_item) in mpower_data_vec.iter().enumerate() { - >::insert( - ( - start_of_received_date_millis.clone(), - mpower_data_item.account_id_registered_dhx_miner.clone(), - ), - mpower_data_item.mpower_registered_dhx_miner.clone(), - ); - log::info!("Added MPowerForAccountForDate {:?} {:?} {:?}", - start_of_received_date_millis.clone(), - mpower_data_item.account_id_registered_dhx_miner.clone(), + Self::set_mpower_of_account_for_date( + account_id.to_public_key().clone(), + start_of_requested_date_millis.clone(), mpower_data_item.mpower_registered_dhx_miner.clone(), ); - - // let average = Self::average_mpower() - // .expect("The average is not empty, because it was just mutated; qed"); - // log::info!("Current average mpower is: {}", average); - // here we are raising the NewPrice event - - Self::deposit_event(Event::NewMPowerForAccountForDate( - start_of_received_date_millis.clone(), - mpower_data_item.account_id_registered_dhx_miner.clone(), - mpower_data_item.mpower_registered_dhx_miner.clone(), - )); } Some(mpower_data_vec.clone()) @@ -2998,6 +3006,7 @@ pub mod pallet { fn validate_transaction_parameters( block_number: &T::BlockNumber, + start_of_requested_date_millis: &Date, new_mpower_data: &Vec>, ) -> TransactionValidity { // Now let's check if the transaction has any chance to succeed. diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 3d90ece37..d69ef9b5d 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -339,24 +339,24 @@ fn setup_min_mpower_daily(min_mpower_daily: u128) { } // we have to get their mpower the day before we check if they are eligible incase there are delays in getting the off-chain data -fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, next_start_date: i64) { +fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, start_date: i64) { let account_1_public_key = vec![1]; let account_2_public_key = vec![2]; let account_3_public_key = vec![3]; // https://aws1.discourse-cdn.com/business5/uploads/rust_lang/original/3X/9/0/909baa7e3d9569489b07c791ca76f2223bd7bac2.webp - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_1_public_key.clone(), amount_mpower_each_miner.clone(), next_start_date)); - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_2_public_key.clone(), amount_mpower_each_miner.clone(), next_start_date)); - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_3_public_key.clone(), amount_mpower_each_miner.clone(), next_start_date)); + assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_1_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); + assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_2_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); + assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_3_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); assert_eq!( - MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_1_public_key.clone())), + MiningRewardsAllowanceTestModule::mpower_of_account_for_date((start_date, account_1_public_key.clone())), Some(amount_mpower_each_miner.clone()) ); assert_eq!( - MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_2_public_key.clone())), + MiningRewardsAllowanceTestModule::mpower_of_account_for_date((start_date, account_2_public_key.clone())), Some(amount_mpower_each_miner.clone()) ); assert_eq!( - MiningRewardsAllowanceTestModule::mpower_of_account_for_date((next_start_date, account_3_public_key.clone())), + MiningRewardsAllowanceTestModule::mpower_of_account_for_date((start_date, account_3_public_key.clone())), Some(amount_mpower_each_miner.clone()) ); } From ca94095508d64e818410377650043d457c75d6b5 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 24 Nov 2021 07:41:11 +0100 Subject: [PATCH 15/37] convert AccountId to Vec for storing accounts --- pallets/mining/rewards-allowance/src/lib.rs | 27 ++++++++++----------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 8d88c8863..4439a611d 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -1241,8 +1241,9 @@ pub mod pallet { // TODO - fetch the mPower of the miner currently being iterated to check if it's greater than the min. // mPower that is required let mut mpower_current_u128: u128 = 0u128; - - let _mpower_current_u128 = >::get((start_of_requested_date_millis.clone(), miner.clone())); + let miner_public_key = miner.clone().encode(); + log::info!("Public key {:?}", miner_public_key); + let _mpower_current_u128 = >::get((start_of_requested_date_millis.clone(), miner_public_key.clone())); // // FIXME - this is temporary // let _mpower_data = ( // Some(0u128), @@ -1624,7 +1625,7 @@ pub mod pallet { } log::info!("Finished initial loop of registered miners"); - println!("Finished initial loop of registered miners"); + // println!("Finished initial loop of registered miners"); } // `on_initialize` is executed at the beginning of the block before any extrinsic are @@ -2794,11 +2795,11 @@ pub mod pallet { // import the library here. // Example from Substrate - // let request = - // http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); - // Example of request we may use let request = - http::Request::get("https://api.datahighway.com/price?start_of_requested_date_millis=BTC"); + http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); + // Example of request we may use + // let request = + // http::Request::get("https://api.datahighway.com/price?start_of_requested_date_millis=BTC"); // We set the deadline for sending of the request, note that awaiting response can // have a separate deadline. Next we send the request, before that it's also possible // to alter request headers or stream body content in case of non-GET requests. @@ -2834,10 +2835,9 @@ pub mod pallet { // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d let mpower_data = r#"{ "data": [ - { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "11" }, - { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "12" } - ], - "start_of_requested_date_millis": "1630195200000", + { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "11", "start_of_requested_date_millis": "1630195200000" }, + { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "12", "start_of_requested_date_millis": "1630195200000" } + ] }"#; let mpower_data_vec = match Self::parse_mpower_data(mpower_data, block_number.clone()) { @@ -2977,11 +2977,10 @@ pub mod pallet { fn add_mpower(account_id: T::AccountId, start_of_requested_date_millis: Date, mpower_data_vec: Vec>) -> Option>> { log::info!("Adding mPower to storage for date: {:?}", start_of_requested_date_millis.clone()); - // TODO - convert AccountId into Vec - for (index, mpower_data_item) in mpower_data_vec.iter().enumerate() { Self::set_mpower_of_account_for_date( - account_id.to_public_key().clone(), + // convert AccountId into Vec. This is [0, 0, ... 0] since its an unsigned transaction + account_id.clone().encode(), start_of_requested_date_millis.clone(), mpower_data_item.mpower_registered_dhx_miner.clone(), ); From 32ac4b9d70615b66acc50dd6bc0a9b9151f682d4 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 24 Nov 2021 09:07:37 +0100 Subject: [PATCH 16/37] interpolate the start of current date into the api http request url params --- pallets/mining/rewards-allowance/src/lib.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 4439a611d..c922e50e7 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -28,6 +28,11 @@ //! #![cfg_attr(not(feature = "std"), no_std)] +// We need this to allow use of `format!` in a no_std environment +#![crate_type = "dylib"] +#[macro_use] +extern crate alloc; + use core::str; use chrono::{ NaiveDateTime, @@ -2795,11 +2800,16 @@ pub mod pallet { // import the library here. // Example from Substrate - let request = - http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); + // let request = + // http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); + // Example of request we may use + // let start_of_requested_date_millis = 1630195200000i64; + // let url = format!("https://api.datahighway.com/data/mpower-for-date?start_of_requested_date_millis={}", start_of_requested_date_millis); + // log::info!("Request URL: {}", url.clone()); // let request = - // http::Request::get("https://api.datahighway.com/price?start_of_requested_date_millis=BTC"); + // http::Request::get(&url); + // We set the deadline for sending of the request, note that awaiting response can // have a separate deadline. Next we send the request, before that it's also possible // to alter request headers or stream body content in case of non-GET requests. From 1deca20535b39b63e450e22248a82ae9b580f893 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 25 Nov 2021 08:59:03 +0100 Subject: [PATCH 17/37] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit resolved errors that i was getting in the logsoffchain_workers error fetching mpower and offchain_workers error unknown transaction type , which appears to because i needed to change the GRACE_PERIOD to a shorter period of say 10 seconds instead of 1 minute i also only had a single account Alice in the chain_spec as a value for cooling_off_period_days_remaining, but I also needed Bob since, and because in the hard-coded mpower data response from the API i had two accounts with an mpower value, but they accidently both had Alice’s public key hex, so it was using the same account when iterating over multiple miners. i also wasn’t providing the correct value for the account id to the function set_mpower_of_account_for_date (i was providing the unsigned account id instead of the account id property i’d added as mpower_data_item.account_id_registered_dhx_miner i checked that i could successfully check on-chain storage for MPowerForAccountForDate` by providing the start of a current date that had been stored, and the public key (hex) value that was provided for the account id in the API response (even though we’re storing the key as Vec it still fetches it correctly in the UI change to store accounts as public keys Vec instead of AccountId --- node/src/chain_spec.rs | 30 +++++++-- pallets/mining/rewards-allowance/src/lib.rs | 70 ++++++++++---------- pallets/mining/rewards-allowance/src/mock.rs | 7 +- pallets/primitives/src/constants/mod.rs | 1 + runtime/src/lib.rs | 11 ++- 5 files changed, 74 insertions(+), 45 deletions(-) diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index bf2f066c0..a6bf8badd 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -935,7 +935,7 @@ fn testnet_genesis( registered_dhx_miners: vec![ get_account_id_from_seed::("Alice"), get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), + // get_account_id_from_seed::("Charlie"), ], rewards_aggregated_dhx_for_all_miners_for_date: Default::default(), rewards_accumulated_dhx_for_miner_for_date: Default::default(), @@ -946,7 +946,18 @@ fn testnet_genesis( cooling_off_period_days: 7u32, cooling_off_period_days_remaining: vec![ ( - get_account_id_from_seed::("Alice"), + // get_account_id_from_seed::("Alice").encode(), + // Alice + vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125], + ( + 0, + 7u32, + 0u32, + ), + ), + ( + // Bob + vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72], ( 0, 7u32, @@ -1064,7 +1075,7 @@ fn mainnet_genesis( registered_dhx_miners: vec![ get_account_id_from_seed::("Alice"), get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), + // get_account_id_from_seed::("Charlie"), ], rewards_aggregated_dhx_for_all_miners_for_date: Default::default(), rewards_accumulated_dhx_for_miner_for_date: Default::default(), @@ -1075,7 +1086,18 @@ fn mainnet_genesis( cooling_off_period_days: 7u32, cooling_off_period_days_remaining: vec![ ( - get_account_id_from_seed::("Alice"), + // get_account_id_from_seed::("Alice").encode(), + // Alice + vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125], + ( + 0, + 7u32, + 0u32, + ), + ), + ( + // Bob + vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72], ( 0, 7u32, diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index c922e50e7..01a58fea8 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -249,11 +249,10 @@ pub mod pallet { ::BlockNumber, >; - // FIXME - change these to the types we really want - type MPowerAccountDataType = MPowerAccountData< - ::AccountId, - u128, - >; + // type MPowerAccountDataType = MPowerAccountData< + // ::AccountId, + // u128, + // >; enum TransactionType { Raw, @@ -275,7 +274,7 @@ pub mod pallet { pub(super) type BondedDHXForAccountForDate = StorageMap<_, Blake2_128Concat, ( Date, - T::AccountId, + Vec, // public key of AccountId ), BalanceOf, >; @@ -362,7 +361,7 @@ pub mod pallet { pub(super) type RewardsAccumulatedDHXForMinerForDate = StorageMap<_, Blake2_128Concat, ( Date, - T::AccountId, + Vec, ), BalanceOf, >; @@ -397,7 +396,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn cooling_off_period_days_remaining)] pub(super) type CoolingOffPeriodDaysRemaining = StorageMap<_, Blake2_128Concat, - T::AccountId, + Vec, // public key of AccountId ( // date when cooling off period started for a given miner, or the date when we last reduced their cooling off period. // we do not reduce their cooling off period days remaining if we've already set this to a date that is the @@ -455,14 +454,14 @@ pub mod pallet { pub rewards_multiplier_current_period_days_remaining: (Date, Date, u32, u32), pub rewards_multiplier_operation: u8, pub rewards_aggregated_dhx_for_all_miners_for_date: Vec<(Date, BalanceOf)>, - pub rewards_accumulated_dhx_for_miner_for_date: Vec<((Date, T::AccountId), BalanceOf)>, + pub rewards_accumulated_dhx_for_miner_for_date: Vec<((Date, Vec), BalanceOf)>, pub registered_dhx_miners: Vec, pub min_bonded_dhx_daily: BalanceOf, pub min_bonded_dhx_daily_default: BalanceOf, pub min_mpower_daily: u128, pub min_mpower_daily_default: u128, pub cooling_off_period_days: u32, - pub cooling_off_period_days_remaining: Vec<(T::AccountId, (Date, u32, u32))>, + pub cooling_off_period_days_remaining: Vec<(Vec, (Date, u32, u32))>, } // The default value for the genesis config type. @@ -636,8 +635,7 @@ pub mod pallet { /// Event generated when new mPower data is accepted to contribute to the rewards allowance. /// \[start_date_requested, registered_dhx_miner_account_id, mpower\] - NewMPowerForAccountForDate(Date, Vec, u128), - // NewMPowerForAccountForDate(Date, T::AccountId, u128), + NewMPowerForAccountForDate(Date, Vec, u128), } // Errors inform users that something went wrong should be descriptive and have helpful documentation @@ -1197,6 +1195,9 @@ pub mod pallet { // reasons: Reasons::Misc, // }, + let miner_public_key = miner.clone().encode(); + log::info!("Public key {:?}", miner_public_key); + let bonded_dhx_current_u128; let _bonded_dhx_current_u128 = Self::set_bonded_dhx_of_account_for_date( miner.clone(), @@ -1246,8 +1247,6 @@ pub mod pallet { // TODO - fetch the mPower of the miner currently being iterated to check if it's greater than the min. // mPower that is required let mut mpower_current_u128: u128 = 0u128; - let miner_public_key = miner.clone().encode(); - log::info!("Public key {:?}", miner_public_key); let _mpower_current_u128 = >::get((start_of_requested_date_millis.clone(), miner_public_key.clone())); // // FIXME - this is temporary // let _mpower_data = ( @@ -1294,7 +1293,7 @@ pub mod pallet { 7u32, 0u32, ); - if let Some(_cooling_off_period_days_remaining) = >::get(miner.clone()) { + if let Some(_cooling_off_period_days_remaining) = >::get(miner_public_key.clone()) { // we do not change cooling_off_period_days_remaining.0 to the default value in the chain_spec.rs of 0, // instead we want to use today's date `start_of_requested_date_millis.clone()` by default, as we did above. if _cooling_off_period_days_remaining.0 != 0 { @@ -1303,7 +1302,7 @@ pub mod pallet { cooling_off_period_days_remaining.1 = _cooling_off_period_days_remaining.1; cooling_off_period_days_remaining.2 = _cooling_off_period_days_remaining.2; } else { - log::info!("Unable to retrieve cooling off period days remaining for given miner, using default {:?}", miner.clone()); + log::info!("Unable to retrieve cooling off period days remaining for given miner, using default {:?}, {:?}", miner.clone(), miner_public_key.clone()); } log::info!("cooling_off_period_days_remaining {:?} {:?} {:?}", start_of_requested_date_millis.clone(), cooling_off_period_days_remaining, miner.clone()); // if cooling_off_period_days_remaining.2 is 0u32, it means we haven't recognised they that have the min. bonded yet (or unbonded), @@ -1317,7 +1316,7 @@ pub mod pallet { has_min_mpower_daily == true { >::insert( - miner.clone(), + miner_public_key.clone(), ( start_of_requested_date_millis.clone(), cooling_off_period_days.clone(), @@ -1359,7 +1358,7 @@ pub mod pallet { // Write the new value to storage >::insert( - miner.clone(), + miner_public_key.clone(), ( start_of_requested_date_millis.clone(), new_cooling_off_period_days_remaining.clone(), @@ -1385,7 +1384,7 @@ pub mod pallet { // we need to add that they are eligible for rewards on the current date too >::insert( - miner.clone(), + miner_public_key.clone(), ( start_of_requested_date_millis.clone(), 0u32, @@ -1398,7 +1397,7 @@ pub mod pallet { if >::contains_key( ( start_of_requested_date_millis.clone(), - miner.clone(), + miner_public_key.clone(), ) ) == true { continue; @@ -1518,7 +1517,7 @@ pub mod pallet { >::insert( ( start_of_requested_date_millis.clone(), - miner.clone(), + miner_public_key.clone(), ), daily_reward_for_miner.clone(), ); @@ -1545,7 +1544,7 @@ pub mod pallet { { // Write the new value to storage >::insert( - miner.clone(), + miner_public_key.clone(), ( start_of_requested_date_millis.clone(), cooling_off_period_days.clone(), @@ -1592,7 +1591,7 @@ pub mod pallet { // Write the new value to storage >::insert( - miner.clone(), + miner_public_key.clone(), ( start_of_requested_date_millis.clone(), new_cooling_off_period_days_remaining.clone(), @@ -1617,7 +1616,7 @@ pub mod pallet { { // Write the new value to storage >::insert( - miner.clone(), + miner_public_key.clone(), ( start_of_requested_date_millis.clone(), 0u32, @@ -1813,7 +1812,7 @@ pub mod pallet { // let daily_reward_for_miner_to_try = >::get( // ( // start_of_requested_date_millis.clone(), - // miner.clone(), + // miner_public_key.clone(), // ), // ); // if let Some(_daily_reward_for_miner_to_try) = daily_reward_for_miner_to_try.clone() { @@ -2499,7 +2498,7 @@ pub mod pallet { return Err(DispatchError::Other("Non-digit ASCII char in input")); }, } - log::info!("digit {:?}", digit); + if digit != 0u128 && out != 0u128 { multiplier *= 10; } else if digit != 0u128 && out == 0u128 { @@ -2510,9 +2509,7 @@ pub mod pallet { multiplier *= 10; } - log::info!("multiplier {:?}", multiplier); out += multiplier * digit; - log::info!("out {:?}", out); } Ok(out) @@ -2546,7 +2543,7 @@ pub mod pallet { >::insert( ( start_of_requested_date_millis.clone(), - account_id.clone(), + account_id.clone().encode(), ), bonded_dhx_current.clone(), ); @@ -2570,6 +2567,9 @@ pub mod pallet { pub fn set_mpower_of_account_for_date(account_id: Vec, start_of_requested_date_millis: Date, mpower: u128) -> Result { let mpower_current_u128 = mpower.clone(); + // TODO - use .get to check if the new mpower value differs from the value that is already in storage + // for the given key, and only insert if it is different + // Update storage. Override the default that may have been set in on_initialize >::insert( ( @@ -2800,8 +2800,8 @@ pub mod pallet { // import the library here. // Example from Substrate - // let request = - // http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); + let request = + http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); // Example of request we may use // let start_of_requested_date_millis = 1630195200000i64; @@ -2843,10 +2843,11 @@ pub mod pallet { // FIXME - replace the below hard-coded example in future with use of the response body // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d + // Bob public key 0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48 let mpower_data = r#"{ "data": [ { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "11", "start_of_requested_date_millis": "1630195200000" }, - { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "12", "start_of_requested_date_millis": "1630195200000" } + { "acct_id": "8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", "mpower": "12", "start_of_requested_date_millis": "1630195200000" } ] }"#; @@ -2975,7 +2976,6 @@ pub mod pallet { }; mpower_data_vec.push(mpower_data_elem); - } // log::info!("mpower_data_vec {:?}", mpower_data_vec); @@ -2985,12 +2985,12 @@ pub mod pallet { /// Add new mPower on-chain. fn add_mpower(account_id: T::AccountId, start_of_requested_date_millis: Date, mpower_data_vec: Vec>) -> Option>> { + // note: AccountId as Vec is [0, 0, ... 0] since its an unsigned transaction log::info!("Adding mPower to storage for date: {:?}", start_of_requested_date_millis.clone()); for (index, mpower_data_item) in mpower_data_vec.iter().enumerate() { Self::set_mpower_of_account_for_date( - // convert AccountId into Vec. This is [0, 0, ... 0] since its an unsigned transaction - account_id.clone().encode(), + mpower_data_item.account_id_registered_dhx_miner.clone(), start_of_requested_date_millis.clone(), mpower_data_item.mpower_registered_dhx_miner.clone(), ); diff --git a/pallets/mining/rewards-allowance/src/mock.rs b/pallets/mining/rewards-allowance/src/mock.rs index dfa3fe0c7..67a41f855 100644 --- a/pallets/mining/rewards-allowance/src/mock.rs +++ b/pallets/mining/rewards-allowance/src/mock.rs @@ -113,6 +113,7 @@ pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a c pub const DOLLARS: Balance = 100 * CENTS; pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); pub const HOURS: BlockNumber = MINUTES * 60; +pub const SECONDS: BlockNumber = MINUTES / 60; pub const DAYS: BlockNumber = HOURS * 24; // from Substrate pallet_democracy tests @@ -478,9 +479,9 @@ where } parameter_types! { - pub const GracePeriod: BlockNumber = 1 * MINUTES; - pub const UnsignedInterval: BlockNumber = 1 * MINUTES; - pub const UnsignedPriority: BlockNumber = 1 * MINUTES; + pub const GracePeriod: BlockNumber = 10 * SECONDS; // 1 * MINUTES; + pub const UnsignedInterval: BlockNumber = 10 * SECONDS; // 1 * MINUTES; + pub const UnsignedPriority: BlockNumber = 10 * SECONDS; // 1 * MINUTES; } impl MiningRewardsAllowanceConfig for Test { diff --git a/pallets/primitives/src/constants/mod.rs b/pallets/primitives/src/constants/mod.rs index 558d11052..f7211058c 100644 --- a/pallets/primitives/src/constants/mod.rs +++ b/pallets/primitives/src/constants/mod.rs @@ -32,6 +32,7 @@ pub mod time { pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); pub const HOURS: BlockNumber = MINUTES * 60; pub const DAYS: BlockNumber = HOURS * 24; + pub const SECONDS: BlockNumber = MINUTES / 60; // 1 in 4 blocks (on average, not counting collisions) will be primary BABE blocks. pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index e228c58b9..4c2e3247c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -188,6 +188,7 @@ pub use module_primitives::{ MILLISECS_PER_BLOCK, MINUTES, PRIMARY_PROBABILITY, + SECONDS, SLOT_DURATION, }, types::*, @@ -1164,9 +1165,13 @@ impl mining_execution_token::Config for Runtime { // } parameter_types! { - pub const GracePeriod: BlockNumber = 1 * MINUTES; - pub const UnsignedInterval: BlockNumber = 1 * MINUTES; - pub const UnsignedPriority: BlockNumber = 1 * MINUTES; + // Note: if this is set to a longer period of 1 * MINUTE + // then it will cause an error in the logs: + // `offchain_workers error fetching mpower: Too early to send unsigned transaction ` or + // `offchain_workers error unknown transaction type` + pub const GracePeriod: BlockNumber = 10 * SECONDS; // 1 * MINUTES; + pub const UnsignedInterval: BlockNumber = 10 * SECONDS; // 1 * MINUTES; + pub const UnsignedPriority: BlockNumber = 10 * SECONDS; // 1 * MINUTES; } impl mining_rewards_allowance::Config for Runtime { From d4d5d6edfacfa9d0fdb481d1f4b33dae0aafa574 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 25 Nov 2021 12:03:19 +0100 Subject: [PATCH 18/37] add extrinsic change_mpower_of_account_for_date. change to ensure_root so only Sudo or governance may change --- pallets/mining/rewards-allowance/src/lib.rs | 91 +++++++++------ pallets/mining/rewards-allowance/src/tests.rs | 104 ++++++++++-------- 2 files changed, 116 insertions(+), 79 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 01a58fea8..b6e28f1a4 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -572,13 +572,13 @@ pub mod pallet { /// Storage of the minimum DHX that must be bonded by each registered DHX miner each day /// to be eligible for rewards - /// \[amount_dhx, sender\] - SetMinBondedDHXDailyStored(BalanceOf, T::AccountId), + /// \[amount_dhx\] + SetMinBondedDHXDailyStored(BalanceOf), /// Storage of the minimum mPower that must be held by each registered DHX miner each day /// to be eligible for rewards - /// \[amount_mpower, sender\] - SetMinMPowerDailyStored(u128, T::AccountId), + /// \[amount_mpower\] + SetMinMPowerDailyStored(u128), /// Storage of the default cooling off period in days /// \[cooling_off_period_days\] @@ -589,14 +589,14 @@ pub mod pallet { SetBondedDHXOfAccountForDateStored(Date, BalanceOf, T::AccountId), /// Storage of the default daily reward allowance in DHX by an origin account. - /// \[amount_dhx, sender\] - SetRewardsAllowanceDHXDailyStored(BalanceOf, T::AccountId), + /// \[amount_dhx\] + SetRewardsAllowanceDHXDailyStored(BalanceOf), /// Change the stored reward allowance in DHX for a specific date by an origin account, and /// where change is 0 for an decrease or any other value like 1 for an increase to the remaining /// rewards allowance. - /// \[date, change_amount_dhx, sender, change\] - ChangedRewardsAllowanceDHXForDateRemainingStored(Date, BalanceOf, T::AccountId, u8), + /// \[date, change_amount_dhx, change\] + ChangedRewardsAllowanceDHXForDateRemainingStored(Date, BalanceOf, u8), /// Transferred a proportion of the daily DHX rewards allowance to a DHX Miner on a given date /// \[date, miner_reward, remaining_rewards_allowance_today, miner_account_id\] @@ -612,16 +612,16 @@ pub mod pallet { ChangedMinBondedDHXDailyUsingNewRewardsMultiplier(Date, BalanceOf, u32, u8, u32), /// Storage of a new reward operation (1u8: addition) by an origin account. - /// \[operation, sender\] - SetRewardsMultiplierOperationStored(u8, T::AccountId), + /// \[operation\] + SetRewardsMultiplierOperationStored(u8), /// Storage of a new reward multiplier default period in days (i.e. 90 for 3 months) by an origin account. - /// \[days, sender\] - SetRewardsMultiplierDefaultPeriodDaysStored(u32, T::AccountId), + /// \[days\] + SetRewardsMultiplierDefaultPeriodDaysStored(u32), /// Storage of a new reward multiplier next period in days (i.e. 90 for 3 months) by an origin account. - /// \[days, sender\] - SetRewardsMultiplierNextPeriodDaysStored(u32, T::AccountId), + /// \[days\] + SetRewardsMultiplierNextPeriodDaysStored(u32), /// Storage of new rewards multiplier paused status /// \[new_status] @@ -2067,39 +2067,40 @@ pub mod pallet { Ok(()) } + // only modifiable by governance as root rather than just any user #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn set_min_bonded_dhx_daily(origin: OriginFor, min_bonded_dhx_daily: BalanceOf) -> DispatchResult { - let _sender: T::AccountId = ensure_signed(origin)?; + let _sender = ensure_root(origin)?; >::put(&min_bonded_dhx_daily.clone()); log::info!("set_min_bonded_dhx_daily: {:?}", &min_bonded_dhx_daily); Self::deposit_event(Event::SetMinBondedDHXDailyStored( min_bonded_dhx_daily.clone(), - _sender.clone(), )); Ok(()) } + // only modifiable by governance as root rather than just any user #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn set_min_mpower_daily(origin: OriginFor, min_mpower_daily: u128) -> DispatchResult { - let _sender: T::AccountId = ensure_signed(origin)?; + let _sender = ensure_root(origin)?; >::put(&min_mpower_daily.clone()); log::info!("set_min_mpower_daily: {:?}", &min_mpower_daily); Self::deposit_event(Event::SetMinMPowerDailyStored( min_mpower_daily.clone(), - _sender.clone(), )); Ok(()) } + // only modifiable by governance as root rather than just any user #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn set_cooling_off_period_days(origin: OriginFor, cooling_off_period_days: u32) -> DispatchResult { - let _sender: T::AccountId = ensure_signed(origin)?; + let _sender = ensure_root(origin)?; >::put(&cooling_off_period_days.clone()); log::info!("cooling_off_period_days: {:?}", &cooling_off_period_days); @@ -2111,11 +2112,10 @@ pub mod pallet { Ok(()) } - // TODO: we need to change this in future so it is only modifiable by governance, - // rather than just any user + // only modifiable by governance as root rather than just any user #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn set_rewards_allowance_dhx_daily(origin: OriginFor, rewards_allowance: BalanceOf) -> DispatchResult { - let _who = ensure_signed(origin)?; + let _who = ensure_root(origin)?; // Update storage >::put(&rewards_allowance.clone()); log::info!("set_rewards_allowance_dhx_daily - rewards_allowance: {:?}", &rewards_allowance); @@ -2123,7 +2123,6 @@ pub mod pallet { // Emit an event. Self::deposit_event(Event::SetRewardsAllowanceDHXDailyStored( rewards_allowance.clone(), - _who.clone() )); // Return a successful DispatchResultWithPostInfo @@ -2134,7 +2133,7 @@ pub mod pallet { // https://docs.google.com/spreadsheets/d/1W2AzOH9Cs9oCR8UYfYCbpmd9X7hp-USbYXL7AuwMY_Q/edit#gid=970997021 #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn set_rewards_allowance_dhx_for_date_remaining(origin: OriginFor, rewards_allowance: BalanceOf, timestamp: u64) -> DispatchResult { - let _who = ensure_signed(origin)?; + let _who = ensure_root(origin)?; // Note: we do not need the following as we're not using the current timestamp, rather the function parameter. // let current_date = >::get(); @@ -2154,7 +2153,6 @@ pub mod pallet { Self::deposit_event(Event::ChangedRewardsAllowanceDHXForDateRemainingStored( start_of_requested_date_millis.clone(), rewards_allowance.clone(), - _who.clone(), 1u8, // increment )); @@ -2163,10 +2161,11 @@ pub mod pallet { } #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + // only modifiable by governance as root rather than just any user // parameter `change: u8` value may be 0 or 1 (or any other value) to represent that we want to make a // corresponding decrease or increase to the remaining dhx rewards allowance for a given date. pub fn change_rewards_allowance_dhx_for_date_remaining(origin: OriginFor, daily_rewards: BalanceOf, timestamp: u64, change: u8) -> DispatchResult { - let _who = ensure_signed(origin)?; + let _who = ensure_root(origin)?; let start_of_requested_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(timestamp.clone())?; @@ -2216,7 +2215,6 @@ pub mod pallet { Self::deposit_event(Event::ChangedRewardsAllowanceDHXForDateRemainingStored( start_of_requested_date_millis.clone(), new_remaining_allowance_as_balance.clone(), - _who.clone(), change.clone(), )); @@ -2224,54 +2222,78 @@ pub mod pallet { Ok(()) } + // only modifiable by governance as root rather than just any user #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn set_rewards_multiplier_operation(origin: OriginFor, operation: u8) -> DispatchResult { - let _who = ensure_signed(origin)?; + let _who = ensure_root(origin)?; >::put(&operation.clone()); log::info!("set_rewards_multiplier_operation - operation: {:?}", &operation); // Emit an event. Self::deposit_event(Event::SetRewardsMultiplierOperationStored( operation.clone(), - _who.clone() )); // Return a successful DispatchResultWithPostInfo Ok(()) } + // only modifiable by governance as root rather than just any user #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn set_rewards_multiplier_default_period_days(origin: OriginFor, days: u32) -> DispatchResult { - let _who = ensure_signed(origin)?; + let _who = ensure_root(origin)?; >::put(&days.clone()); log::info!("set_rewards_multiplier_default_period_days - days: {:?}", &days); // Emit an event. Self::deposit_event(Event::SetRewardsMultiplierDefaultPeriodDaysStored( days.clone(), - _who.clone() )); // Return a successful DispatchResultWithPostInfo Ok(()) } + // only modifiable by governance as root rather than just any user #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn set_rewards_multiplier_next_period_days(origin: OriginFor, days: u32) -> DispatchResult { - let _who = ensure_signed(origin)?; + let _who = ensure_root(origin)?; >::put(&days.clone()); log::info!("set_rewards_multiplier_next_period_days - days: {:?}", &days); // Emit an event. Self::deposit_event(Event::SetRewardsMultiplierNextPeriodDaysStored( days.clone(), - _who.clone() )); // Return a successful DispatchResultWithPostInfo Ok(()) } + // extrinsic that governance may choose to call to set the mpower of an account for a date + // if it needs to be corrected in future before they claim + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn change_mpower_of_account_for_date(origin: OriginFor, account_id: Vec, start_of_requested_date_millis: Date, mpower: u128) -> DispatchResult { + let _who = ensure_root(origin)?; + + let mpower_current_u128 = mpower.clone(); + + log::info!("change_mpower_of_account_for_date {:?} {:?} {:?}", + account_id.clone(), + start_of_requested_date_millis.clone(), + mpower_current_u128.clone(), + ); + + Self::set_mpower_of_account_for_date( + account_id.clone(), + start_of_requested_date_millis.clone(), + mpower_current_u128.clone(), + ); + + // Return a successful DispatchResultWithPostInfo + Ok(()) + } + // Off-chain workers /// Submit new mPower data on-chain via unsigned transaction. @@ -2561,9 +2583,6 @@ pub mod pallet { Ok(bonded_dhx_current_u128.clone()) } - // TODO - this is an internal function, do we want to create an extrinsic too that - // governance may choose to call to set the mpower of an account for a date if it needs to be corrected in future - // before they claim? pub fn set_mpower_of_account_for_date(account_id: Vec, start_of_requested_date_millis: Date, mpower: u128) -> Result { let mpower_current_u128 = mpower.clone(); diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index d69ef9b5d..b8bb1c28e 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -97,12 +97,12 @@ fn it_sets_rewards_allowance_with_timestamp() { Timestamp::set_timestamp(1630049371000u64); assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_allowance_dhx_daily( - Origin::signed(0), + Origin::root(), FIVE_THOUSAND_DHX )); assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_allowance_dhx_for_date_remaining( - Origin::signed(0), + Origin::root(), FIVE_THOUSAND_DHX, 1630049371000 )); @@ -113,7 +113,7 @@ fn it_sets_rewards_allowance_with_timestamp() { assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630022400000), Some(FIVE_THOUSAND_DHX)); assert_ok!(MiningRewardsAllowanceTestModule::change_rewards_allowance_dhx_for_date_remaining( - Origin::signed(0), + Origin::root(), FIVE_HUNDRED_DHX, 1630049371000, 0 @@ -125,7 +125,7 @@ fn it_sets_rewards_allowance_with_timestamp() { assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630022400000), Some(4_500_000_000_000_000_000_000u128)); assert_ok!(MiningRewardsAllowanceTestModule::change_rewards_allowance_dhx_for_date_remaining( - Origin::signed(0), + Origin::root(), TWO_THOUSAND_DHX, 1630049371000, 1 @@ -275,7 +275,7 @@ fn setup_preimage() { fn it_sets_min_mpower_daily() { new_test_ext().execute_with(|| { assert_ok!(MiningRewardsAllowanceTestModule::set_min_mpower_daily( - Origin::signed(1), + Origin::root(), 5u128, )); }); @@ -307,11 +307,11 @@ fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(3))); assert_ok!(MiningRewardsAllowanceTestModule::set_cooling_off_period_days( - Origin::signed(1), + Origin::root(), 1_u32, // debug quickly for testing )); assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_allowance_dhx_daily( - Origin::signed(1), + Origin::root(), FIVE_THOUSAND_DHX, )); @@ -332,7 +332,7 @@ fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: fn setup_min_mpower_daily(min_mpower_daily: u128) { assert_ok!(MiningRewardsAllowanceTestModule::set_min_mpower_daily( - Origin::signed(1), + Origin::root(), min_mpower_daily.clone(), )); assert_eq!(MiningRewardsAllowanceTestModule::min_mpower_daily(), Some(min_mpower_daily.clone())); @@ -343,10 +343,11 @@ fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, start_date: i64) let account_1_public_key = vec![1]; let account_2_public_key = vec![2]; let account_3_public_key = vec![3]; + // https://aws1.discourse-cdn.com/business5/uploads/rust_lang/original/3X/9/0/909baa7e3d9569489b07c791ca76f2223bd7bac2.webp - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_1_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_2_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); - assert_ok!(MiningRewardsAllowanceTestModule::set_mpower_of_account_for_date(account_3_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); + assert_ok!(MiningRewardsAllowanceTestModule::change_mpower_of_account_for_date(Origin::root(), account_1_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); + assert_ok!(MiningRewardsAllowanceTestModule::change_mpower_of_account_for_date(Origin::root(), account_2_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); + assert_ok!(MiningRewardsAllowanceTestModule::change_mpower_of_account_for_date(Origin::root(), account_3_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); assert_eq!( MiningRewardsAllowanceTestModule::mpower_of_account_for_date((start_date, account_1_public_key.clone())), Some(amount_mpower_each_miner.clone()) @@ -363,7 +364,7 @@ fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, start_date: i64) fn setup_bonding(amount_bonded_each_miner: u128, min_bonding_dhx_daily: u128) -> u32 { assert_ok!(MiningRewardsAllowanceTestModule::set_min_bonded_dhx_daily( - Origin::signed(1), + Origin::root(), min_bonding_dhx_daily.clone(), )); assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(min_bonding_dhx_daily.clone())); @@ -397,19 +398,19 @@ fn setup_bonding(amount_bonded_each_miner: u128, min_bonding_dhx_daily: u128) -> fn setup_multiplier() { assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_operation( - Origin::signed(0), + Origin::root(), 1u8, )); // in the tests we want the period between each 10:1, 20:1 cycle to be just 2 days instead of 90 days // since we don't want to wait so long to check that it changes each cycle in the tests assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_default_period_days( - Origin::signed(0), + Origin::root(), 2u32, )); assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_next_period_days( - Origin::signed(0), + Origin::root(), 2u32, )); } @@ -478,6 +479,10 @@ fn unbond_each_miner_by_removing_their_referendum_vote(referendum_index: u32) { } fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128) { + let account_1_public_key = vec![1]; + let account_2_public_key = vec![2]; + let account_3_public_key = vec![3]; + // since the timestamp is 0 (corresponds to 1970-01-01) at block number #1, we early exit from on_initialize in // that block in the implementation and do not set any storage values associated with the date until block #2. // in the tests we could set the timestamp before we run on_initialize(1), but that wouldn't reflect reality. @@ -516,9 +521,9 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1635379200000), Some(FIVE_THOUSAND_DHX)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1635379200000), Some(false)); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1635379200000, 1)), Some(amount_bonded_each_miner)); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1635379200000, 2)), Some(amount_bonded_each_miner)); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1635379200000, 3)), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1635379200000, account_1_public_key.clone())), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1635379200000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1635379200000, account_3_public_key.clone())), Some(amount_bonded_each_miner)); change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630195200000i64); @@ -530,9 +535,9 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount // a day before we start the new multiplier period and change from 10:1 to 20:1 since no more days remaining assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1630195200000, 2u32, 0u32))); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, 1)), Some(amount_bonded_each_miner)); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, 2)), Some(amount_bonded_each_miner)); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, 3)), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_1_public_key.clone())), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_3_public_key.clone())), Some(amount_bonded_each_miner)); // i.e. for example, if locked is 25_133_000_000_000_000_000_000u128 (NORMAL_AMOUNT), which is 25,133 DHX, // then with 10:1 each of the 3x accounts get 2513.3 DHX, which is ~7538.9 DHX combined @@ -541,20 +546,20 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount if amount_bonded_each_miner.clone() == NORMAL_AMOUNT { assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(7_539_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, 1)), Some(2_513_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, 2)), Some(2_513_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, 3)), Some(2_513_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(9_999_999_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, 1)), Some(3_333_333_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, 2)), Some(3_333_333_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, 3)), Some(3_333_333_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); } assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1630195200000, 0, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); @@ -565,7 +570,7 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded // amount below the min. bonded DHX daily amount - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1630281600000, 0, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); // the change between each multiplier period is 10 unless a user sets it to a different value @@ -593,6 +598,10 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount } fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { + let account_1_public_key = vec![1]; + let account_2_public_key = vec![2]; + let account_3_public_key = vec![3]; + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630368000000i64); // 31th August 2021 @ ~7am is 1630393200000 @@ -600,7 +609,7 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { Timestamp::set_timestamp(1630393200000u64); MiningRewardsAllowanceTestModule::on_initialize(6); // cooling off period doesn't change again unless they unbond - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1630368000000, 0, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630368000000, 0, 1))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630368000000, 2u32, 1u32))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); @@ -610,7 +619,7 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { // 1st Sept 2021 @ 12am is 1630454400000 (start of day) Timestamp::set_timestamp(1630479600000u64); MiningRewardsAllowanceTestModule::on_initialize(7); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1630454400000, 0, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630454400000, 0, 1))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630454400000, 2u32, 0u32))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); @@ -620,7 +629,7 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { // 2nd Sept 2021 @ 12am is 1630540800000 (start of day) Timestamp::set_timestamp(1630566000000u64); MiningRewardsAllowanceTestModule::on_initialize(7); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1630540800000, 0, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630540800000, 0, 1))); // start of new multiplier period assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630540800000, 1630540800000, 2u32, 2u32))); // check that the min_bonded_dhx_daily doubled after 3 months (we're only doing it after 2 days in the tests though) from 20 DHX to 30 DHX @@ -628,6 +637,10 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { } fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_bonded(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { + let account_1_public_key = vec![1]; + let account_2_public_key = vec![2]; + let account_3_public_key = vec![3]; + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630627200000i64); // 3rd Sept 2021 @ ~7am is 1630652400000 @@ -666,18 +679,18 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b // params: start of date, days remaining, bonding status // note: since they don't have the min. DHX bonded their bonding status changes to `2`, which is unbonding - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1630713600000, 1, 2))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630713600000, 1, 2))); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, 1)), Some(0u128)); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, 2)), Some(0u128)); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, 3)), Some(0u128)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, account_1_public_key.clone())), Some(0u128)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, account_2_public_key.clone())), Some(0u128)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, account_3_public_key.clone())), Some(0u128)); // check they are not eligible for rewards due to insufficient bonded amount assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630713600000), None); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630713600000, 1)), None); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630713600000, 2)), None); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630713600000, 3)), None); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630713600000, account_1_public_key.clone())), None); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630713600000, account_2_public_key.clone())), None); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630713600000, account_3_public_key.clone())), None); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630713600000), Some(FIVE_THOUSAND_DHX)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630713600000), Some(false)); @@ -686,6 +699,7 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b } fn check_cooling_off_period_starts_again_if_sufficient_bonded_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { + let account_1_public_key = vec![1]; bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner, referendum_index); @@ -699,12 +713,14 @@ fn check_cooling_off_period_starts_again_if_sufficient_bonded_again(amount_bonde // params: start of date, days remaining, bonding status // note: since they have the min. DHX bonded again their bonding status changes to `1`, which is bonding - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1630800000000, 0, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630800000000, 0, 1))); check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_mpower(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); } fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_mpower(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { + let account_1_public_key = vec![1]; + // no mpower to check they'll be ineligible for rewards change_mpower_for_each_miner(0u128, 1630886400000i64); @@ -723,12 +739,14 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_m // params: start of date, days remaining, bonding status // note: since they don't have min. mPower their bonding status changes to `2`, which is unbonding - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1630972800000, 0, 2))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630972800000, 0, 2))); check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); } fn check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { + let account_1_public_key = vec![1]; + // reset mpower to what it was change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1631059200000i64); @@ -739,7 +757,7 @@ fn check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonde // params: start of date, days remaining, bonding status // note: they have min. mPower again so their bonding status changes to `0`, which is unbonded - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1631059200000, 0, 0))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1631059200000, 0, 0))); // use original mpower change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1631145600000i64); @@ -751,7 +769,7 @@ fn check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonde // params: start of date, days remaining, bonding status // note: they have min. mPower again so their bonding status changes to `1`, which means they are bonded again - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1631145600000, 1, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1631145600000, 1, 1))); // params: total days, days remaining assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1631059200000, 1631145600000, 2u32, 1u32))); From 86cab12f1bbcea1deefb52fe4f2dbf68d2af3b09 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 25 Nov 2021 12:41:18 +0100 Subject: [PATCH 19/37] only storage mpower for account for date from api if that account/date does not already exist in storage --- pallets/mining/rewards-allowance/src/lib.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index b6e28f1a4..a779e955e 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -2586,8 +2586,22 @@ pub mod pallet { pub fn set_mpower_of_account_for_date(account_id: Vec, start_of_requested_date_millis: Date, mpower: u128) -> Result { let mpower_current_u128 = mpower.clone(); - // TODO - use .get to check if the new mpower value differs from the value that is already in storage + // check if the new mpower value differs from the value that is already in storage // for the given key, and only insert if it is different + let mpower_for_account_for_date = >::get( + ( + start_of_requested_date_millis.clone(), + account_id.clone(), + ) + ); + match mpower_for_account_for_date { + None => { + }, + Some(x) => { + log::warn!("Existing storage value of mPower for account for date of data retrieved from API"); + return Err(DispatchError::Other("Existing storage value of mPower for account for date of data retrieved from API")); + } + } // Update storage. Override the default that may have been set in on_initialize >::insert( @@ -3005,7 +3019,7 @@ pub mod pallet { /// Add new mPower on-chain. fn add_mpower(account_id: T::AccountId, start_of_requested_date_millis: Date, mpower_data_vec: Vec>) -> Option>> { // note: AccountId as Vec is [0, 0, ... 0] since its an unsigned transaction - log::info!("Adding mPower to storage for date: {:?}", start_of_requested_date_millis.clone()); + log::info!("Processing mPower for account for date into storage: {:?}", start_of_requested_date_millis.clone()); for (index, mpower_data_item) in mpower_data_vec.iter().enumerate() { Self::set_mpower_of_account_for_date( From be9828c4dcfb51b521e6137841385efb02a0cfbd Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 26 Nov 2021 11:14:20 +0100 Subject: [PATCH 20/37] wip --- node/src/chain_spec.rs | 16 +- pallets/mining/rewards-allowance/src/lib.rs | 141 +++++++++++------- pallets/mining/rewards-allowance/src/tests.rs | 22 ++- 3 files changed, 113 insertions(+), 66 deletions(-) diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index a6bf8badd..5a8d1fc37 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -933,9 +933,13 @@ fn testnet_genesis( rewards_multiplier_current_period_days_remaining: Default::default(), rewards_multiplier_operation: 1u8, registered_dhx_miners: vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), + // get_account_id_from_seed::("Alice"), + // get_account_id_from_seed::("Bob"), // get_account_id_from_seed::("Charlie"), + // Alice + vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125], + // Bob + vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72], ], rewards_aggregated_dhx_for_all_miners_for_date: Default::default(), rewards_accumulated_dhx_for_miner_for_date: Default::default(), @@ -1073,9 +1077,13 @@ fn mainnet_genesis( rewards_multiplier_current_period_days_remaining: Default::default(), rewards_multiplier_operation: 1u8, registered_dhx_miners: vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), + // get_account_id_from_seed::("Alice"), + // get_account_id_from_seed::("Bob"), // get_account_id_from_seed::("Charlie"), + // Alice + vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125], + // Bob + vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72], ], rewards_aggregated_dhx_for_all_miners_for_date: Default::default(), rewards_accumulated_dhx_for_miner_for_date: Default::default(), diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index a779e955e..9307687dd 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -40,6 +40,9 @@ use chrono::{ use codec::{ Decode, Encode, + Error, + Input, + Output, }; use frame_support::{ dispatch::DispatchResult, @@ -371,7 +374,7 @@ pub mod pallet { /// TWOX-NOTE: Safe, as increasing integer keys are safe. #[pallet::storage] #[pallet::getter(fn registered_dhx_miners)] - pub(super) type RegisteredDHXMiners = StorageValue<_, Vec>; + pub(super) type RegisteredDHXMiners = StorageValue<_, Vec>>; #[pallet::storage] #[pallet::getter(fn min_bonded_dhx_daily)] @@ -455,7 +458,7 @@ pub mod pallet { pub rewards_multiplier_operation: u8, pub rewards_aggregated_dhx_for_all_miners_for_date: Vec<(Date, BalanceOf)>, pub rewards_accumulated_dhx_for_miner_for_date: Vec<((Date, Vec), BalanceOf)>, - pub registered_dhx_miners: Vec, + pub registered_dhx_miners: Vec>, pub min_bonded_dhx_daily: BalanceOf, pub min_bonded_dhx_daily_default: BalanceOf, pub min_mpower_daily: u128, @@ -561,14 +564,14 @@ pub mod pallet { T::AccountId = "AccountId", BondedData = "BondedData", BalanceOf = "BalanceOf", - T::AccountId = "Date", + Date = "Date", T::BlockNumber = "BlockNumber", )] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Storage of a sending account as a registered DHX miner - /// \[sender] - SetRegisteredDHXMiner(T::AccountId), + /// Storage of provided accounts as a registered DHX miners + /// \[sender, registered_dhx_miners] + SetRegisteredDHXMiners(Vec>), /// Storage of the minimum DHX that must be bonded by each registered DHX miner each day /// to be eligible for rewards @@ -586,7 +589,7 @@ pub mod pallet { /// Storage of the bonded DHX of an account on a specific date. /// \[date, amount_dhx_bonded, account_dhx_bonded\] - SetBondedDHXOfAccountForDateStored(Date, BalanceOf, T::AccountId), + SetBondedDHXOfAccountForDateStored(Date, BalanceOf, Vec), /// Storage of the default daily reward allowance in DHX by an origin account. /// \[amount_dhx\] @@ -599,8 +602,8 @@ pub mod pallet { ChangedRewardsAllowanceDHXForDateRemainingStored(Date, BalanceOf, u8), /// Transferred a proportion of the daily DHX rewards allowance to a DHX Miner on a given date - /// \[date, miner_reward, remaining_rewards_allowance_today, miner_account_id\] - TransferredRewardsAllowanceDHXToMinerForDate(Date, BalanceOf, BalanceOf, T::AccountId), + /// \[date, miner_reward, remaining_rewards_allowance_today, miner_public_key\] + TransferredRewardsAllowanceDHXToMinerForDate(Date, BalanceOf, BalanceOf, Vec), /// Exhausted distributing all the daily DHX rewards allowance to DHX Miners on a given date. /// Note: There may be some leftover for the day so we record it here @@ -1128,11 +1131,11 @@ pub mod pallet { let mut miner_count = 0; - for (index, miner) in reg_dhx_miners.iter().enumerate() { + for (index, miner_public_key) in reg_dhx_miners.iter().enumerate() { miner_count += 1; log::info!("miner_count {:#?}", miner_count); - log::info!("miner {:#?}", miner); - // let locks_until_block_for_account = >::locks(miner.clone()); + log::info!("miner_public_key {:#?}", miner_public_key); + // let locks_until_block_for_account = >::locks(miner_public_key.clone()); // // NOTE - I fixed the following error by using `.into_inner()` after asking the community here and getting a // // response in Substrate Builders weekly meeting https://matrix.to/#/!HzySYSaIhtyWrwiwEV:matrix.org/$163243681163543vyfkW:matrix.org?via=matrix.parity.io&via=matrix.org&via=corepaper.org // // @@ -1157,11 +1160,33 @@ pub mod pallet { // initialise so they have no locks and are ineligible for rewards let mut locks_first_amount_as_u128 = 0u128.clone(); - let locked_vec = >::locks(miner.clone()).into_inner(); + let miner_account_id: T::AccountId; + + let miner_public_key_u8: &[u8]; + if let Some(_miner_public_key_u8) = + TryInto::<&[u8]>::try_into(miner_public_key.clone()).ok() { + miner_public_key_u8 = _miner_public_key_u8; + } else { + log::error!("Unable to convert Vec to [u8] for miner_public_key"); + return; + } + + let _miner_account_id = Decode::decode(&mut miner_public_key_u8.clone()); + match _miner_account_id.clone() { + Err(_e) => { + log::error!("Unable to decode miner_public_key"); + return; + }, + Ok(x) => { + miner_account_id = x; + } + } + + let locked_vec = >::locks(miner_account_id.clone()).into_inner(); if locked_vec.len() != 0 { // println!("locked_vec: {:?}", locked_vec); let locks_first_amount: ::Balance = - >::locks(miner.clone()).into_inner().clone()[0].amount; + >::locks(miner_account_id.clone()).into_inner().clone()[0].amount; let _locks_first_amount_as_u128 = Self::convert_balance_to_u128_from_pallet_balance(locks_first_amount.clone()); match _locks_first_amount_as_u128.clone() { @@ -1195,12 +1220,12 @@ pub mod pallet { // reasons: Reasons::Misc, // }, - let miner_public_key = miner.clone().encode(); + // let miner_public_key = miner.clone().encode(); log::info!("Public key {:?}", miner_public_key); let bonded_dhx_current_u128; let _bonded_dhx_current_u128 = Self::set_bonded_dhx_of_account_for_date( - miner.clone(), + miner_public_key.clone(), locks_first_amount_as_u128.clone() ); match _bonded_dhx_current_u128 { @@ -1231,7 +1256,7 @@ pub mod pallet { if locks_first_amount_as_u128 >= min_bonded_dhx_daily_u128 { is_bonding_min_dhx = true; } - log::info!("is_bonding_min_dhx: {:?} {:?}", is_bonding_min_dhx.clone(), miner.clone()); + log::info!("is_bonding_min_dhx: {:?} {:?}", is_bonding_min_dhx.clone(), miner_public_key.clone()); // println!("is_bonding_min_dhx {:#?}", is_bonding_min_dhx); // println!("min_bonded_dhx_daily_u128 {:#?}", min_bonded_dhx_daily_u128); @@ -1270,7 +1295,7 @@ pub mod pallet { if mpower_current_u128 >= min_mpower_daily_u128 { has_min_mpower_daily = true; } - log::info!("has_min_mpower_daily: {:?} {:?}", has_min_mpower_daily.clone(), miner.clone()); + log::info!("has_min_mpower_daily: {:?} {:?}", has_min_mpower_daily.clone(), miner_public_key.clone()); // println!("has_min_mpower_daily {:#?}", has_min_mpower_daily); // TODO - after fetching their mPower from the off-chain workers function where we iterate through @@ -1302,9 +1327,9 @@ pub mod pallet { cooling_off_period_days_remaining.1 = _cooling_off_period_days_remaining.1; cooling_off_period_days_remaining.2 = _cooling_off_period_days_remaining.2; } else { - log::info!("Unable to retrieve cooling off period days remaining for given miner, using default {:?}, {:?}", miner.clone(), miner_public_key.clone()); + log::info!("Unable to retrieve cooling off period days remaining for given miner, using default {:?}", miner_public_key.clone()); } - log::info!("cooling_off_period_days_remaining {:?} {:?} {:?}", start_of_requested_date_millis.clone(), cooling_off_period_days_remaining, miner.clone()); + log::info!("cooling_off_period_days_remaining {:?} {:?} {:?}", start_of_requested_date_millis.clone(), cooling_off_period_days_remaining, miner_public_key.clone()); // if cooling_off_period_days_remaining.2 is 0u32, it means we haven't recognised they that have the min. bonded yet (or unbonded), // they aren't currently bonding, they haven't started cooling off to start bonding, // or have already finished cooling down after bonding. @@ -1323,7 +1348,7 @@ pub mod pallet { 1u32, // they are bonded again, waiting to start getting rewards ), ); - log::info!("Added CoolingOffPeriodDaysRemaining for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner.clone(), cooling_off_period_days.clone()); + log::info!("Added CoolingOffPeriodDaysRemaining for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), cooling_off_period_days.clone()); // if cooling_off_period_days_remaining.0 is not the start of the current date // (since if they just started with min. bonded dhx and min. mPower and we just set days remaining to 7, or we already decremented // a miner's days remaining for the current date, then we want to wait until the next day until we @@ -1365,7 +1390,7 @@ pub mod pallet { 1u32, // they are bonded again, waiting to start getting rewards ), ); - log::info!("Reduced CoolingOffPeriodDaysRemaining for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner.clone(), new_cooling_off_period_days_remaining.clone()); + log::info!("Reduced CoolingOffPeriodDaysRemaining for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_cooling_off_period_days_remaining.clone()); // if cooling_off_period_days_remaining.0 is not the start of the current date // (since if we decremented days remaining from 1 to 0 days left for a miner // then we want to wait until the next day before we distribute the rewards to them) @@ -1510,7 +1535,7 @@ pub mod pallet { start_of_requested_date_millis.clone(), new_rewards_aggregated_dhx_daily.clone(), ); - log::info!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner.clone(), new_rewards_aggregated_dhx_daily.clone()); + log::info!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); // add to storage item that maps the date to the registered miner and the calculated reward // (prior to possibly reducing it so they get a proportion of the daily rewards that are available) @@ -1521,7 +1546,7 @@ pub mod pallet { ), daily_reward_for_miner.clone(), ); - log::info!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner.clone(), daily_reward_for_miner.clone()); + log::info!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); // println!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); // if last miner being iterated then reset for next day @@ -1552,7 +1577,7 @@ pub mod pallet { ), ); - log::info!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner.clone(), cooling_off_period_days.clone()); + log::info!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_off_period_days.clone()); // if cooling_off_period_days_remaining.0 is not the start of the current date // (since if they just started un-bonding or just had less than min. mPower @@ -1600,7 +1625,7 @@ pub mod pallet { ); // println!("[reduce] block: {:#?}, miner: {:#?}, date_start: {:#?} new_cooling_off_period_days_remaining: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_cooling_off_period_days_remaining); - log::info!("Unbonded miner. Reducing cooling down period dates remaining {:?} {:?}", miner.clone(), new_cooling_off_period_days_remaining.clone()); + log::info!("Unbonded miner. Reducing cooling down period dates remaining {:?} {:?}", miner_public_key.clone(), new_cooling_off_period_days_remaining.clone()); // if cooling_off_period_days_remaining.0 is not the start of the current date // (since if we decremented days remaining to from 1 to 0 days left for a miner @@ -1624,7 +1649,7 @@ pub mod pallet { ), ); - log::info!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner.clone()); + log::info!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); } } @@ -1661,7 +1686,7 @@ pub mod pallet { // // and still hadn't added to the aggregated rewards for the day // return 0; // } - // // println!("[multiplier] block: {:#?}, miner: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, miner_count, start_of_requested_date_millis, rewards_aggregated_dhx_daily); + // // println!("[multiplier] block: {:#?}, miner_count: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, miner_count, start_of_requested_date_millis, rewards_aggregated_dhx_daily); // if rewards_aggregated_dhx_daily == 0u32.into() { // log::error!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); @@ -1787,16 +1812,16 @@ pub mod pallet { // } // } // log::info!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); - // // println!("[multiplier] block: {:#?}, miner: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, miner_count, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); + // // println!("[multiplier] block: {:#?}, miner_count: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, miner_count, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); // // Initialise outside the loop as we need this value after the loop after we finish iterating through all the miners // let mut rewards_allowance_dhx_remaining_today_as_u128 = 0u128; // miner_count = 0; - // for (index, miner) in reg_dhx_miners.iter().enumerate() { + // for (index, miner_public_key) in reg_dhx_miners.iter().enumerate() { // miner_count += 1; // log::info!("rewards loop - miner_count {:#?}", miner_count); - // log::info!("rewards loop - miner {:#?}", miner); + // log::info!("rewards loop - miner_public_key {:#?}", miner_public_key); // // only run the following once per day per miner until rewards_allowance_dhx_for_date_remaining is exhausted // // but since we're giving each registered miner a proportion of the daily reward allowance @@ -1829,7 +1854,7 @@ pub mod pallet { // } else { // // If any of the miner's don't have a reward, we won't waste storing that, // // so we want to move to the next miner in the loop - // log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner.clone()); + // log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); // continue; // } // log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); @@ -1878,12 +1903,12 @@ pub mod pallet { // return 0; // } - // // println!("[rewards] block: {:#?}, miner: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); + // // println!("[rewards] block: {:#?}, miner_count: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); // let treasury_account_id: T::AccountId = >::account_id(); // let max_payout = pallet_balances::Pallet::::usable_balance(treasury_account_id.clone()); // log::info!("Treasury account id: {:?}", treasury_account_id.clone()); - // log::info!("Miner to receive reward: {:?}", miner.clone()); + // log::info!("Miner to receive reward: {:?}", miner_public_key.clone()); // log::info!("Treasury balance max payout: {:?}", max_payout.clone()); // let proportion_of_daily_reward_for_miner; @@ -1926,7 +1951,7 @@ pub mod pallet { // return 0; // } - // // println!("[prepared-for-payment] block: {:#?}, miner: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, miner_count, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); + // // println!("[prepared-for-payment] block: {:#?}, miner_count: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, miner_count, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); // // check if miner's reward is less than or equal to: rewards_allowance_dhx_daily_remaining // if restored_proportion_of_daily_reward_for_miner_u128.clone() > 0u128 && @@ -1939,13 +1964,13 @@ pub mod pallet { // let tx_result; // let _tx_result = ::Currency::transfer( // &treasury_account_id, - // &miner.clone(), + // &miner_public_key.clone(), // proportion_of_daily_reward_for_miner.clone(), // ExistenceRequirement::KeepAlive // ); // match _tx_result { // Err(_e) => { - // log::error!("Unable to transfer from treasury to miner {:?}", miner.clone()); + // log::error!("Unable to transfer from treasury to miner {:?}", miner_public_key.clone()); // return 0; // }, // Ok(ref x) => { @@ -1990,21 +2015,21 @@ pub mod pallet { // new_rewards_allowance_dhx_remaining_today.clone(), // ); - // // println!("[paid] block: {:#?}, miner: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); + // // println!("[paid] block: {:#?}, miner_count: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); // // emit event with reward payment history rather than bloating storage // Self::deposit_event(Event::TransferredRewardsAllowanceDHXToMinerForDate( // start_of_requested_date_millis.clone(), // proportion_of_daily_reward_for_miner.clone(), // new_rewards_allowance_dhx_remaining_today.clone(), - // miner.clone(), + // miner_public_key.clone(), // )); // log::info!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", // start_of_requested_date_millis.clone(), // proportion_of_daily_reward_for_miner.clone(), // new_rewards_allowance_dhx_remaining_today.clone(), - // miner.clone(), + // miner_public_key.clone(), // ); // continue; @@ -2032,7 +2057,7 @@ pub mod pallet { // true // ); - // // println!("[distributed] block: {:#?}, miner: {:#?}, date_start: {:#?} ", block_number, miner_count, start_of_requested_date_millis); + // // println!("[distributed] block: {:#?}, miner_count: {:#?}, date_start: {:#?} ", block_number, miner_count, start_of_requested_date_millis); // Self::deposit_event(Event::DistributedRewardsAllowanceDHXForDateRemaining( // start_of_requested_date_millis.clone(), @@ -2054,14 +2079,18 @@ pub mod pallet { #[pallet::call] impl Pallet { #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn set_registered_dhx_miner(origin: OriginFor) -> DispatchResult { - let _sender: T::AccountId = ensure_signed(origin)?; + pub fn set_registered_dhx_miners(origin: OriginFor, register_dhx_miners: Vec>) -> DispatchResult { + let _sender = ensure_root(origin)?; - >::append(_sender.clone()); - log::info!("register_dhx_miner - account_id: {:?}", &_sender); + for &miner_public_key in register_dhx_miners.iter().rev() { + // log::info!("{:?}", miner); - Self::deposit_event(Event::SetRegisteredDHXMiner( - _sender.clone(), + >::append(miner_public_key.clone()); + log::info!("set_registered_dhx_miners: {:?}", &_sender); + } + + Self::deposit_event(Event::SetRegisteredDHXMiners( + register_dhx_miners.clone(), )); Ok(()) @@ -2537,7 +2566,7 @@ pub mod pallet { Ok(out) } - fn set_bonded_dhx_of_account_for_date(account_id: T::AccountId, bonded_dhx: u128) -> Result { + fn set_bonded_dhx_of_account_for_date(account_public_key: Vec, bonded_dhx: u128) -> Result { // Note: we DO need the following as we're using the current timestamp, rather than a function parameter. let timestamp: ::Moment = >::get(); let requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone())?; @@ -2565,25 +2594,25 @@ pub mod pallet { >::insert( ( start_of_requested_date_millis.clone(), - account_id.clone().encode(), + account_public_key.clone(), ), bonded_dhx_current.clone(), ); - log::info!("set_bonded_dhx_of_account_for_date - account_id: {:?}", &account_id); + log::info!("set_bonded_dhx_of_account_for_date - account_public_key: {:?}", &account_public_key); log::info!("set_bonded_dhx_of_account_for_date - bonded_dhx_current: {:?}", &bonded_dhx_current); // Emit an event. Self::deposit_event(Event::SetBondedDHXOfAccountForDateStored( start_of_requested_date_millis.clone(), bonded_dhx_current.clone(), - account_id.clone(), + account_public_key.clone(), )); // Return a successful DispatchResultWithPostInfo Ok(bonded_dhx_current_u128.clone()) } - pub fn set_mpower_of_account_for_date(account_id: Vec, start_of_requested_date_millis: Date, mpower: u128) -> Result { + pub fn set_mpower_of_account_for_date(account_public_key: Vec, start_of_requested_date_millis: Date, mpower: u128) -> Result { let mpower_current_u128 = mpower.clone(); // check if the new mpower value differs from the value that is already in storage @@ -2591,7 +2620,7 @@ pub mod pallet { let mpower_for_account_for_date = >::get( ( start_of_requested_date_millis.clone(), - account_id.clone(), + account_public_key.clone(), ) ); match mpower_for_account_for_date { @@ -2607,21 +2636,21 @@ pub mod pallet { >::insert( ( start_of_requested_date_millis.clone(), - account_id.clone(), + account_public_key.clone(), ), mpower_current_u128.clone(), ); log::info!("Added MPowerForAccountForDate {:?} {:?} {:?}", start_of_requested_date_millis.clone(), - account_id.clone(), + account_public_key.clone(), mpower_current_u128.clone(), ); // Emit an event. Self::deposit_event(Event::NewMPowerForAccountForDate( start_of_requested_date_millis.clone(), - account_id.clone(), + account_public_key.clone(), mpower_current_u128.clone(), )); diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index b8bb1c28e..b6de88b0a 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -30,9 +30,14 @@ const TWO_DHX: u128 = 2_000_000_000_000_000_000_u128; // 2 #[ignore] fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_if_not_already_set_for_today() { new_test_ext().execute_with(|| { - assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(1))); - assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(2))); - assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(3))); + assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( + Origin::root(), + vec![ + vec![1], + vec![2], + vec![3], + ] + )); // 27th August 2021 @ ~7am is 1630049371000 // where milliseconds/day 86400000 @@ -302,9 +307,14 @@ fn it_converts_vec_u8_to_u128() { } fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(1))); - assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(2))); - assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(3))); + assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( + Origin::root(), + vec![ + vec![1], + vec![2], + vec![3], + ] + )); assert_ok!(MiningRewardsAllowanceTestModule::set_cooling_off_period_days( Origin::root(), From 15eafe9ace1d98d9abf2d147bc47b95246ceeb6a Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 26 Nov 2021 12:19:26 +0100 Subject: [PATCH 21/37] convert Vec to T::AccountId --- pallets/mining/rewards-allowance/src/lib.rs | 16 ++++------------ pallets/mining/rewards-allowance/src/tests.rs | 16 ++++------------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 9307687dd..916e27e91 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -1134,7 +1134,7 @@ pub mod pallet { for (index, miner_public_key) in reg_dhx_miners.iter().enumerate() { miner_count += 1; log::info!("miner_count {:#?}", miner_count); - log::info!("miner_public_key {:#?}", miner_public_key); + log::info!("miner_public_key {:?}", miner_public_key); // let locks_until_block_for_account = >::locks(miner_public_key.clone()); // // NOTE - I fixed the following error by using `.into_inner()` after asking the community here and getting a // // response in Substrate Builders weekly meeting https://matrix.to/#/!HzySYSaIhtyWrwiwEV:matrix.org/$163243681163543vyfkW:matrix.org?via=matrix.parity.io&via=matrix.org&via=corepaper.org @@ -1162,16 +1162,8 @@ pub mod pallet { let mut locks_first_amount_as_u128 = 0u128.clone(); let miner_account_id: T::AccountId; - let miner_public_key_u8: &[u8]; - if let Some(_miner_public_key_u8) = - TryInto::<&[u8]>::try_into(miner_public_key.clone()).ok() { - miner_public_key_u8 = _miner_public_key_u8; - } else { - log::error!("Unable to convert Vec to [u8] for miner_public_key"); - return; - } - - let _miner_account_id = Decode::decode(&mut miner_public_key_u8.clone()); + // convert type public key Vec to type T::AccountId + let _miner_account_id = Decode::decode(&mut miner_public_key.as_slice().clone()); match _miner_account_id.clone() { Err(_e) => { log::error!("Unable to decode miner_public_key"); @@ -2082,7 +2074,7 @@ pub mod pallet { pub fn set_registered_dhx_miners(origin: OriginFor, register_dhx_miners: Vec>) -> DispatchResult { let _sender = ensure_root(origin)?; - for &miner_public_key in register_dhx_miners.iter().rev() { + for miner_public_key in register_dhx_miners.iter().rev() { // log::info!("{:?}", miner); >::append(miner_public_key.clone()); diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index b6de88b0a..9de9dbf68 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -32,11 +32,7 @@ fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_ new_test_ext().execute_with(|| { assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( Origin::root(), - vec![ - vec![1], - vec![2], - vec![3], - ] + vec![vec![3], vec![2], vec![1]], )); // 27th August 2021 @ ~7am is 1630049371000 @@ -155,7 +151,7 @@ fn setup_preimage() { let encoded_proposal_preimage = vec![0; 500]; match Democracy::note_preimage(Origin::signed(1), encoded_proposal_preimage.clone()) { Ok(_) => (), - Err(x) if x == Error::::DuplicatePreimage.into() => (), + // Err(x) if x == Error::::DuplicatePreimage.into() => (), Err(x) => panic!("Democracy::note_preimage error {:?}", x), } System::set_block_number(1); @@ -309,11 +305,7 @@ fn it_converts_vec_u8_to_u128() { fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( Origin::root(), - vec![ - vec![1], - vec![2], - vec![3], - ] + vec![vec![3], vec![2], vec![1]], )); assert_ok!(MiningRewardsAllowanceTestModule::set_cooling_off_period_days( @@ -325,7 +317,7 @@ fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: FIVE_THOUSAND_DHX, )); - assert_eq!(MiningRewardsAllowanceTestModule::registered_dhx_miners(), Some(vec![1, 2, 3])); + assert_eq!(MiningRewardsAllowanceTestModule::registered_dhx_miners(), Some(vec![vec![1], vec![2], vec![3]])); assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days(), Some(1)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_daily(), Some(FIVE_THOUSAND_DHX)); From b732e510bc001df92bf884217d1a3786a82e61a8 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 2 Dec 2021 05:22:26 +0100 Subject: [PATCH 22/37] wip - fix challenge period --- node/src/chain_spec.rs | 2 + pallets/mining/rewards-allowance/src/lib.rs | 1238 +++++++++-------- pallets/mining/rewards-allowance/src/mock.rs | 1 + pallets/mining/rewards-allowance/src/tests.rs | 21 + 4 files changed, 711 insertions(+), 551 deletions(-) diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index 5a8d1fc37..0b5faadba 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -947,6 +947,7 @@ fn testnet_genesis( min_bonded_dhx_daily_default: TEN, // 10 DHX min_mpower_daily: 5u128, min_mpower_daily_default: 5u128, + challenge_period_days: 7u64, cooling_off_period_days: 7u32, cooling_off_period_days_remaining: vec![ ( @@ -1091,6 +1092,7 @@ fn mainnet_genesis( min_bonded_dhx_daily_default: TEN, // 10 DHX min_mpower_daily: 5u128, min_mpower_daily_default: 5u128, + challenge_period_days: 7u64, cooling_off_period_days: 7u32, cooling_off_period_days_remaining: vec![ ( diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 916e27e91..61639503c 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -392,6 +392,10 @@ pub mod pallet { #[pallet::getter(fn min_mpower_daily_default)] pub(super) type MinMPowerDailyDefault = StorageValue<_, u128>; + #[pallet::storage] + #[pallet::getter(fn challenge_period_days)] + pub(super) type ChallengePeriodDays = StorageValue<_, u64>; + #[pallet::storage] #[pallet::getter(fn cooling_off_period_days)] pub(super) type CoolingOffPeriodDays = StorageValue<_, u32>; @@ -463,6 +467,7 @@ pub mod pallet { pub min_bonded_dhx_daily_default: BalanceOf, pub min_mpower_daily: u128, pub min_mpower_daily_default: u128, + pub challenge_period_days: u64, pub cooling_off_period_days: u32, pub cooling_off_period_days_remaining: Vec<(Vec, (Date, u32, u32))>, } @@ -499,6 +504,7 @@ pub mod pallet { min_bonded_dhx_daily_default: Default::default(), min_mpower_daily: 5u128, min_mpower_daily_default: 5u128, + challenge_period_days: Default::default(), cooling_off_period_days: Default::default(), // Note: this doesn't seem to work, even if it's just `vec![Default::default()]` it doesn't use // the defaults in chain_spec.rs, so we set defaults later with `let mut cooling_off_period_days_remaining` @@ -550,6 +556,7 @@ pub mod pallet { >::put(&self.min_bonded_dhx_daily_default); >::put(&self.min_mpower_daily); >::put(&self.min_mpower_daily_default); + >::put(&self.challenge_period_days); >::put(&self.cooling_off_period_days); for (a, (b, c, d)) in &self.cooling_off_period_days_remaining { >::insert(a, (b, c, d)); @@ -583,6 +590,10 @@ pub mod pallet { /// \[amount_mpower\] SetMinMPowerDailyStored(u128), + /// Storage of the default challenge period in days + /// \[challenge_period_days\] + SetChallengePeriodDaysStored(u64), + /// Storage of the default cooling off period in days /// \[cooling_off_period_days\] SetCoolingOffPeriodDaysStored(u32), @@ -1661,477 +1672,96 @@ pub mod pallet { } return 0; + } - // TODO - move the below into an extrinsic function + // `on_finalize` is executed at the end of block after all extrinsic are dispatched. + fn on_finalize(block_number: T::BlockNumber) { + // Perform necessary data/state clean up here. + } + } - // // TODO - consider the miner's mPower that we have fetched. it should have been added earlier above - // // to the aggregated (all miners for that day) and accumulated (specific miner for a day) rewards + // Dispatchable functions allows users to interact with the pallet and invoke state changes. + // These functions materialize as "extrinsics", which are often compared to transactions. + // Dispatchable functions must be annotated with a weight and must return a DispatchResult. + #[pallet::call] + impl Pallet { + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn set_registered_dhx_miners(origin: OriginFor, register_dhx_miners: Vec>) -> DispatchResult { + let _sender = ensure_root(origin)?; - // // fetch accumulated total rewards for all registered miners for the day - // // TODO - we've done this twice, create a function to fetch it - // let mut rewards_aggregated_dhx_daily: BalanceOf = 0u32.into(); // initialize - // if let Some(_rewards_aggregated_dhx_daily) = >::get(&start_of_requested_date_millis) { - // rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; - // } else { - // log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period may not be finished yet"); - // // Note: it would be an issue if we got past the first loop of looping through the registered miners - // // and still hadn't added to the aggregated rewards for the day - // return 0; - // } - // // println!("[multiplier] block: {:#?}, miner_count: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, miner_count, start_of_requested_date_millis, rewards_aggregated_dhx_daily); + for miner_public_key in register_dhx_miners.iter().rev() { + // log::info!("{:?}", miner); - // if rewards_aggregated_dhx_daily == 0u32.into() { - // log::error!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); - // return 0; - // } + >::append(miner_public_key.clone()); + log::info!("set_registered_dhx_miners: {:?}", &_sender); + } - // let rewards_aggregated_dhx_daily_as_u128; - // let _rewards_aggregated_dhx_daily_as_u128 = Self::convert_balance_to_u128(rewards_aggregated_dhx_daily.clone()); - // match _rewards_aggregated_dhx_daily_as_u128.clone() { - // Err(_e) => { - // log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); - // return 0; - // }, - // Ok(x) => { - // rewards_aggregated_dhx_daily_as_u128 = x; - // } - // } - // log::info!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); + Self::deposit_event(Event::SetRegisteredDHXMiners( + register_dhx_miners.clone(), + )); - // // TODO - we've done this twice, create a function to fetch it - // let rewards_allowance_dhx_daily; - // if let Some(_rewards_allowance_dhx_daily) = >::get() { - // rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; - // } else { - // log::error!("Unable to get rewards_allowance_dhx_daily"); - // return 0; - // } + Ok(()) + } - // let rewards_allowance_dhx_daily_u128; - // let _rewards_allowance_dhx_daily_u128 = Self::convert_balance_to_u128(rewards_allowance_dhx_daily.clone()); - // match _rewards_allowance_dhx_daily_u128.clone() { - // Err(_e) => { - // log::error!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); - // return 0; - // }, - // Ok(x) => { - // rewards_allowance_dhx_daily_u128 = x; - // } - // } + // only modifiable by governance as root rather than just any user + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn set_min_bonded_dhx_daily(origin: OriginFor, min_bonded_dhx_daily: BalanceOf) -> DispatchResult { + let _sender = ensure_root(origin)?; - // if rewards_allowance_dhx_daily_u128 == 0u128 { - // log::error!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); - // return 0; - // } + >::put(&min_bonded_dhx_daily.clone()); + log::info!("set_min_bonded_dhx_daily: {:?}", &min_bonded_dhx_daily); - // // previously when we looped through all the registered dhx miners we calculated the - // // reward for each registered miner based on the 10:1 ratio, and stored that along with - // // the corresponding day in storage. since that loop we've fetched the total - // // aggregated rewards that all reg miners are eligible for on that day as `rewards_aggregated_dhx_daily`, - // // lets say it adds up to 8000 DHX, but say we only have 5000 DHX availabe to distribute - // // from `rewards_allowance_dhx_daily`, so we'll constrain the rewards they'll receive further by - // // applying a `distribution_multiplier_for_day_u128` of (5000/8000)*reg_miner_reward on each of - // // the rewards that are distributed to them. + Self::deposit_event(Event::SetMinBondedDHXDailyStored( + min_bonded_dhx_daily.clone(), + )); - // // if the aggregated rewards isn't more than the daily rewards allowance available - // // then just set the multiplier to 1, so they actually get the previously calculated reward rather - // // than a scaled down proportion. - // // - // // e.g. 1: if miner rewards are 2000 & 4000 DHX respectively, this is greater than 5000 DHX daily allowance - // // so we'd have a multiplier of 5000/6000 = 5/6, so they'd receive ~1666 & 3333 DHX respectively. - // // e.g. 2: if miner rewards are 2000 & 2000 DHX respectively, this is less than 5000 DHX daily allowance - // // so we'd just use a multiplier of 1, so they'd receive 2000 & 2000 DHX respectively. - // // https://docs.rs/fixed/0.5.4/fixed/struct.FixedU128.html - // let mut distribution_multiplier_for_day_fixed128 = FixedU128::from_num(1); // initialize + Ok(()) + } - // if rewards_aggregated_dhx_daily_as_u128.clone() > rewards_allowance_dhx_daily_u128.clone() { - // // Divide, handling overflow + // only modifiable by governance as root rather than just any user + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn set_min_mpower_daily(origin: OriginFor, min_mpower_daily: u128) -> DispatchResult { + let _sender = ensure_root(origin)?; - // // Note: If the rewards_allowance_dhx_daily_u128 is 5000 DHX, its 5000000000000000000000, - // // but we can't convert to u64 since largest value is 18446744073709551615. - // // Since we expect the rewards_aggregated_dhx_daily_as_u128 to be at least 1 DHX (i.e. 1000000000000000000), - // // we could just divide both numbers by 1000000000000000000, so we'd have say 5000 and 1 instead, - // // since we're just using these values to get a multiplier output. + >::put(&min_mpower_daily.clone()); + log::info!("set_min_mpower_daily: {:?}", &min_mpower_daily); - // let mut manageable_rewards_allowance_dhx_daily_u128 = 0u128; - // if let Some(_manageable_rewards_allowance_dhx_daily_u128) = - // rewards_allowance_dhx_daily_u128.clone().checked_div(1000000000000000000u128) { - // manageable_rewards_allowance_dhx_daily_u128 = _manageable_rewards_allowance_dhx_daily_u128; - // } else { - // log::error!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); - // return 0; - // } + Self::deposit_event(Event::SetMinMPowerDailyStored( + min_mpower_daily.clone(), + )); - // let mut rewards_allowance_dhx_daily_u64 = 0u64; - // if let Some(_rewards_allowance_dhx_daily_u64) = - // TryInto::::try_into(manageable_rewards_allowance_dhx_daily_u128.clone()).ok() { - // rewards_allowance_dhx_daily_u64 = _rewards_allowance_dhx_daily_u64; - // } else { - // log::error!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); - // return 0; - // } + Ok(()) + } - // let mut manageable_rewards_aggregated_dhx_daily_as_u128 = 0u128; - // if let Some(_manageable_rewards_aggregated_dhx_daily_as_u128) = rewards_aggregated_dhx_daily_as_u128.clone().checked_div(1000000000000000000u128) { - // manageable_rewards_aggregated_dhx_daily_as_u128 = _manageable_rewards_aggregated_dhx_daily_as_u128; - // } else { - // log::error!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); - // return 0; - // } + // only modifiable by governance as root rather than just any user + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn set_challenge_period_days(origin: OriginFor, challenge_period_days: u64) -> DispatchResult { + let _sender = ensure_root(origin)?; - // let mut rewards_aggregated_dhx_daily_as_u64 = 0u64; - // if let Some(_rewards_aggregated_dhx_daily_as_u64) = - // TryInto::::try_into(manageable_rewards_aggregated_dhx_daily_as_u128.clone()).ok() { - // rewards_aggregated_dhx_daily_as_u64 = _rewards_aggregated_dhx_daily_as_u64; - // } else { - // log::error!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); - // return 0; - // } + >::put(&challenge_period_days.clone()); + log::info!("challenge_period_days: {:?}", &challenge_period_days); - // // See https://github.com/ltfschoen/substrate-node-template/pull/6/commits/175ef4805d07093042431c5814dda52da1ebde18 - // let _fraction_distribution_multiplier_for_day_fixed128 = - // U64F64::from_num(manageable_rewards_allowance_dhx_daily_u128.clone()) - // .checked_div(U64F64::from_num(manageable_rewards_aggregated_dhx_daily_as_u128.clone())); - // let _distribution_multiplier_for_day_fixed128 = _fraction_distribution_multiplier_for_day_fixed128.clone(); - // match _distribution_multiplier_for_day_fixed128 { - // None => { - // log::error!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); - // return 0; - // }, - // Some(x) => { - // distribution_multiplier_for_day_fixed128 = x; - // } - // } - // } - // log::info!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); - // // println!("[multiplier] block: {:#?}, miner_count: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, miner_count, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); + Self::deposit_event(Event::SetChallengePeriodDaysStored( + challenge_period_days.clone(), + )); - // // Initialise outside the loop as we need this value after the loop after we finish iterating through all the miners - // let mut rewards_allowance_dhx_remaining_today_as_u128 = 0u128; + Ok(()) + } - // miner_count = 0; - // for (index, miner_public_key) in reg_dhx_miners.iter().enumerate() { - // miner_count += 1; - // log::info!("rewards loop - miner_count {:#?}", miner_count); - // log::info!("rewards loop - miner_public_key {:#?}", miner_public_key); + // only modifiable by governance as root rather than just any user + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn set_cooling_off_period_days(origin: OriginFor, cooling_off_period_days: u32) -> DispatchResult { + let _sender = ensure_root(origin)?; - // // only run the following once per day per miner until rewards_allowance_dhx_for_date_remaining is exhausted - // // but since we're giving each registered miner a proportion of the daily reward allowance - // // (if their aggregated rewards is above daily allowance) each proportion is rounded down, - // // it shouldn't become exhausted anyway - // let is_already_distributed = >::get(start_of_requested_date_millis.clone()); - // if is_already_distributed == Some(true) { - // log::error!("Unable to distribute further rewards allowance today"); - // return 0; - // } + >::put(&cooling_off_period_days.clone()); + log::info!("cooling_off_period_days: {:?}", &cooling_off_period_days); - // let daily_reward_for_miner_as_u128; - // let daily_reward_for_miner_to_try = >::get( - // ( - // start_of_requested_date_millis.clone(), - // miner_public_key.clone(), - // ), - // ); - // if let Some(_daily_reward_for_miner_to_try) = daily_reward_for_miner_to_try.clone() { - // let _daily_reward_for_miner_as_u128 = Self::convert_balance_to_u128(_daily_reward_for_miner_to_try.clone()); - // match _daily_reward_for_miner_as_u128.clone() { - // Err(_e) => { - // log::error!("Unable to convert balance to u128 for daily_reward_for_miner_as_u128"); - // return 0; - // }, - // Ok(x) => { - // daily_reward_for_miner_as_u128 = x; - // } - // } - // } else { - // // If any of the miner's don't have a reward, we won't waste storing that, - // // so we want to move to the next miner in the loop - // log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); - // continue; - // } - // log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); + Self::deposit_event(Event::SetCoolingOffPeriodDaysStored( + cooling_off_period_days.clone(), + )); - // let mut manageable_daily_reward_for_miner_as_u128 = 0u128; - // if let Some(_manageable_daily_reward_for_miner_as_u128) = - // daily_reward_for_miner_as_u128.clone().checked_div(1000000000000000000u128) { - // manageable_daily_reward_for_miner_as_u128 = _manageable_daily_reward_for_miner_as_u128; - // } else { - // log::error!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); - // return 0; - // } - - // // Multiply, handling overflow - // // TODO - probably have to initialise below proportion_of_daily_reward_for_miner_fixed128 to 0u128, - // // and convert distribution_multiplier_for_day_fixed128 to u64, - // // and convert daily_reward_for_miner_as_u128 to u64 too, like i did earlier. - // // but it works so this doesn't seem necessary. - // let proportion_of_daily_reward_for_miner_fixed128; - // let _proportion_of_daily_reward_for_miner_fixed128 = - // U64F64::from_num(distribution_multiplier_for_day_fixed128.clone()).checked_mul(U64F64::from_num(manageable_daily_reward_for_miner_as_u128.clone())); - // match _proportion_of_daily_reward_for_miner_fixed128 { - // None => { - // log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); - // return 0; - // }, - // Some(x) => { - // proportion_of_daily_reward_for_miner_fixed128 = x; - // } - // } - // log::info!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); - - // // round down to nearest integer. we need to round down, because if we round up then if there are - // // 3x registered miners with 5000 DHX rewards allowance per day then they would each get 1667 rewards, - // // but there would only be 1666 remaining after the first two, so the last one would miss out. - // // so if we round down they each get 1666 DHX and there is 2 DHX from the daily allocation that doesn't get distributed at all. - // let proportion_of_daily_reward_for_miner_u128: u128 = proportion_of_daily_reward_for_miner_fixed128.floor().to_num::(); - - // // we lose some accuracy doing this conversion, but at least we split the bulk of the rewards proportionally and fairly - // let mut restored_proportion_of_daily_reward_for_miner_u128 = 0u128; - // if let Some(_restored_proportion_of_daily_reward_for_miner_u128) = - // proportion_of_daily_reward_for_miner_u128.clone().checked_mul(1000000000000000000u128) { - // restored_proportion_of_daily_reward_for_miner_u128 = _restored_proportion_of_daily_reward_for_miner_u128; - // } else { - // log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); - // return 0; - // } - - // // println!("[rewards] block: {:#?}, miner_count: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); - - // let treasury_account_id: T::AccountId = >::account_id(); - // let max_payout = pallet_balances::Pallet::::usable_balance(treasury_account_id.clone()); - // log::info!("Treasury account id: {:?}", treasury_account_id.clone()); - // log::info!("Miner to receive reward: {:?}", miner_public_key.clone()); - // log::info!("Treasury balance max payout: {:?}", max_payout.clone()); - - // let proportion_of_daily_reward_for_miner; - // let _proportion_of_daily_reward_for_miner = Self::convert_u128_to_balance(restored_proportion_of_daily_reward_for_miner_u128.clone()); - // match _proportion_of_daily_reward_for_miner { - // Err(_e) => { - // log::error!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); - // return 0; - // }, - // Ok(ref x) => { - // proportion_of_daily_reward_for_miner = x; - // } - // } - - // let max_payout_as_u128; - // if let Some(_max_payout_as_u128) = TryInto::::try_into(max_payout).ok() { - // max_payout_as_u128 = _max_payout_as_u128; - // } else { - // log::error!("Unable to convert Balance to u128 for max_payout"); - // return 0; - // } - // log::info!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); - - // // Store output `rewards_allowance_dhx_remaining_today_as_u128` outside the loop - // // Validate inputs so the daily_rewards is less or equal to the existing_allowance - // if let Some(_rewards_allowance_dhx_remaining_today) = >::get(&start_of_requested_date_millis) { - // let _rewards_allowance_dhx_remaining_today_as_u128 = Self::convert_balance_to_u128(_rewards_allowance_dhx_remaining_today.clone()); - // match _rewards_allowance_dhx_remaining_today_as_u128.clone() { - // Err(_e) => { - // log::error!("Unable to convert balance to u128"); - // return 0; - // }, - // Ok(x) => { - // rewards_allowance_dhx_remaining_today_as_u128 = x; - // } - // } - // log::info!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); - // } else { - // log::error!("Unable to retrieve balance from value provided."); - // return 0; - // } - - // // println!("[prepared-for-payment] block: {:#?}, miner_count: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, miner_count, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); - - // // check if miner's reward is less than or equal to: rewards_allowance_dhx_daily_remaining - // if restored_proportion_of_daily_reward_for_miner_u128.clone() > 0u128 && - // rewards_allowance_dhx_remaining_today_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() && - // max_payout_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() - // { - // // pay the miner their daily reward - // info!("Paying the miner a proportion of the remaining daily reward allowance"); - - // let tx_result; - // let _tx_result = ::Currency::transfer( - // &treasury_account_id, - // &miner_public_key.clone(), - // proportion_of_daily_reward_for_miner.clone(), - // ExistenceRequirement::KeepAlive - // ); - // match _tx_result { - // Err(_e) => { - // log::error!("Unable to transfer from treasury to miner {:?}", miner_public_key.clone()); - // return 0; - // }, - // Ok(ref x) => { - // tx_result = x; - // } - // } - // info!("Transfer to the miner tx_result: {:?}", tx_result.clone()); - - // info!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); - - // // TODO - move into function `reduce_rewards_allowance_dhx_for_date_remaining`? - - // // Subtract, handling overflow - // let new_rewards_allowance_dhx_remaining_today_as_u128; - // let _new_rewards_allowance_dhx_remaining_today_as_u128 = - // rewards_allowance_dhx_remaining_today_as_u128.clone().checked_sub(restored_proportion_of_daily_reward_for_miner_u128.clone()); - // match _new_rewards_allowance_dhx_remaining_today_as_u128 { - // None => { - // log::error!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); - // return 0; - // }, - // Some(x) => { - // new_rewards_allowance_dhx_remaining_today_as_u128 = x; - // } - // } - - // let new_rewards_allowance_dhx_remaining_today; - // let _new_rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(new_rewards_allowance_dhx_remaining_today_as_u128.clone()); - // match _new_rewards_allowance_dhx_remaining_today { - // Err(_e) => { - // log::error!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); - // return 0; - // }, - // Ok(ref x) => { - // new_rewards_allowance_dhx_remaining_today = x; - // } - // } - - // // Write the new value to storage - // >::insert( - // start_of_requested_date_millis.clone(), - // new_rewards_allowance_dhx_remaining_today.clone(), - // ); - - // // println!("[paid] block: {:#?}, miner_count: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); - - // // emit event with reward payment history rather than bloating storage - // Self::deposit_event(Event::TransferredRewardsAllowanceDHXToMinerForDate( - // start_of_requested_date_millis.clone(), - // proportion_of_daily_reward_for_miner.clone(), - // new_rewards_allowance_dhx_remaining_today.clone(), - // miner_public_key.clone(), - // )); - - // log::info!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", - // start_of_requested_date_millis.clone(), - // proportion_of_daily_reward_for_miner.clone(), - // new_rewards_allowance_dhx_remaining_today.clone(), - // miner_public_key.clone(), - // ); - - // continue; - // } else { - // log::error!("Insufficient remaining rewards allowance to pay daily reward to miner"); - - // break; - // } - // } - - // let rewards_allowance_dhx_remaining_today; - // let _rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(rewards_allowance_dhx_remaining_today_as_u128.clone()); - // match _rewards_allowance_dhx_remaining_today { - // Err(_e) => { - // log::error!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); - // return 0; - // }, - // Ok(ref x) => { - // rewards_allowance_dhx_remaining_today = x; - // } - // } - - // >::insert( - // start_of_requested_date_millis.clone(), - // true - // ); - - // // println!("[distributed] block: {:#?}, miner_count: {:#?}, date_start: {:#?} ", block_number, miner_count, start_of_requested_date_millis); - - // Self::deposit_event(Event::DistributedRewardsAllowanceDHXForDateRemaining( - // start_of_requested_date_millis.clone(), - // rewards_allowance_dhx_remaining_today.clone(), - // )); - - // return 0; - } - - // `on_finalize` is executed at the end of block after all extrinsic are dispatched. - fn on_finalize(block_number: T::BlockNumber) { - // Perform necessary data/state clean up here. - } - } - - // Dispatchable functions allows users to interact with the pallet and invoke state changes. - // These functions materialize as "extrinsics", which are often compared to transactions. - // Dispatchable functions must be annotated with a weight and must return a DispatchResult. - #[pallet::call] - impl Pallet { - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn set_registered_dhx_miners(origin: OriginFor, register_dhx_miners: Vec>) -> DispatchResult { - let _sender = ensure_root(origin)?; - - for miner_public_key in register_dhx_miners.iter().rev() { - // log::info!("{:?}", miner); - - >::append(miner_public_key.clone()); - log::info!("set_registered_dhx_miners: {:?}", &_sender); - } - - Self::deposit_event(Event::SetRegisteredDHXMiners( - register_dhx_miners.clone(), - )); - - Ok(()) - } - - // only modifiable by governance as root rather than just any user - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn set_min_bonded_dhx_daily(origin: OriginFor, min_bonded_dhx_daily: BalanceOf) -> DispatchResult { - let _sender = ensure_root(origin)?; - - >::put(&min_bonded_dhx_daily.clone()); - log::info!("set_min_bonded_dhx_daily: {:?}", &min_bonded_dhx_daily); - - Self::deposit_event(Event::SetMinBondedDHXDailyStored( - min_bonded_dhx_daily.clone(), - )); - - Ok(()) - } - - // only modifiable by governance as root rather than just any user - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn set_min_mpower_daily(origin: OriginFor, min_mpower_daily: u128) -> DispatchResult { - let _sender = ensure_root(origin)?; - - >::put(&min_mpower_daily.clone()); - log::info!("set_min_mpower_daily: {:?}", &min_mpower_daily); - - Self::deposit_event(Event::SetMinMPowerDailyStored( - min_mpower_daily.clone(), - )); - - Ok(()) - } - - // only modifiable by governance as root rather than just any user - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn set_cooling_off_period_days(origin: OriginFor, cooling_off_period_days: u32) -> DispatchResult { - let _sender = ensure_root(origin)?; - - >::put(&cooling_off_period_days.clone()); - log::info!("cooling_off_period_days: {:?}", &cooling_off_period_days); - - Self::deposit_event(Event::SetCoolingOffPeriodDaysStored( - cooling_off_period_days.clone(), - )); - - Ok(()) - } + Ok(()) + } // only modifiable by governance as root rather than just any user #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] @@ -2190,129 +1820,575 @@ pub mod pallet { let start_of_requested_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(timestamp.clone())?; - // https://substrate.dev/rustdocs/latest/frame_support/storage/trait.StorageMap.html - ensure!(>::contains_key(&start_of_requested_date_millis), DispatchError::Other("Date key must exist to reduce allowance.")); + // https://substrate.dev/rustdocs/latest/frame_support/storage/trait.StorageMap.html + ensure!(>::contains_key(&start_of_requested_date_millis), DispatchError::Other("Date key must exist to reduce allowance.")); + + // Validate inputs so the daily_rewards is less or equal to the existing_allowance + let existing_allowance_as_u128; + if let Some(_existing_allowance) = >::get(&start_of_requested_date_millis) { + existing_allowance_as_u128 = Self::convert_balance_to_u128(_existing_allowance.clone())?; + log::info!("change_rewards_allowance_dhx_for_date_remaining - existing_allowance_as_u128: {:?}", existing_allowance_as_u128.clone()); + } else { + return Err(DispatchError::Other("Unable to retrieve balance from value provided")); + } + + let daily_rewards_as_u128; + daily_rewards_as_u128 = Self::convert_balance_to_u128(daily_rewards.clone())?; + log::info!("change_rewards_allowance_dhx_for_date_remaining - daily_rewards_as_u128: {:?}", daily_rewards_as_u128.clone()); + + ensure!(daily_rewards_as_u128 > 0u128, DispatchError::Other("Daily rewards must be greater than zero")); + ensure!(existing_allowance_as_u128 >= daily_rewards_as_u128, DispatchError::Other("Daily rewards cannot exceed current remaining allowance")); + + let new_remaining_allowance_as_balance; + if change == 0 { + // Decrementing the value will error in the event of underflow. + let new_remaining_allowance_as_u128 = existing_allowance_as_u128.checked_sub(daily_rewards_as_u128).ok_or(Error::::StorageUnderflow)?; + new_remaining_allowance_as_balance = Self::convert_u128_to_balance(new_remaining_allowance_as_u128.clone())?; + log::info!("change_rewards_allowance_dhx_for_date_remaining - Decreasing rewards_allowance_dhx_for_date_remaining at Date: {:?}", &start_of_requested_date_millis); + } else { + // Incrementing the value will error in the event of overflow. + let new_remaining_allowance_as_u128 = existing_allowance_as_u128.checked_add(daily_rewards_as_u128).ok_or(Error::::StorageOverflow)?; + new_remaining_allowance_as_balance = Self::convert_u128_to_balance(new_remaining_allowance_as_u128.clone())?; + log::info!("change_rewards_allowance_dhx_for_date_remaining - Increasing rewards_allowance_dhx_for_date_remaining at Date: {:?}", &start_of_requested_date_millis); + } + + // Update storage + >::mutate( + &start_of_requested_date_millis, + |allowance| { + if let Some(_allowance) = allowance { + *_allowance = new_remaining_allowance_as_balance.clone(); + } + }, + ); + + // Emit an event. + Self::deposit_event(Event::ChangedRewardsAllowanceDHXForDateRemainingStored( + start_of_requested_date_millis.clone(), + new_remaining_allowance_as_balance.clone(), + change.clone(), + )); + + // Return a successful DispatchResultWithPostInfo + Ok(()) + } + + // only modifiable by governance as root rather than just any user + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn set_rewards_multiplier_operation(origin: OriginFor, operation: u8) -> DispatchResult { + let _who = ensure_root(origin)?; + >::put(&operation.clone()); + log::info!("set_rewards_multiplier_operation - operation: {:?}", &operation); + + // Emit an event. + Self::deposit_event(Event::SetRewardsMultiplierOperationStored( + operation.clone(), + )); + + // Return a successful DispatchResultWithPostInfo + Ok(()) + } + + // only modifiable by governance as root rather than just any user + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn set_rewards_multiplier_default_period_days(origin: OriginFor, days: u32) -> DispatchResult { + let _who = ensure_root(origin)?; + >::put(&days.clone()); + log::info!("set_rewards_multiplier_default_period_days - days: {:?}", &days); + + // Emit an event. + Self::deposit_event(Event::SetRewardsMultiplierDefaultPeriodDaysStored( + days.clone(), + )); + + // Return a successful DispatchResultWithPostInfo + Ok(()) + } + + // only modifiable by governance as root rather than just any user + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn set_rewards_multiplier_next_period_days(origin: OriginFor, days: u32) -> DispatchResult { + let _who = ensure_root(origin)?; + >::put(&days.clone()); + log::info!("set_rewards_multiplier_next_period_days - days: {:?}", &days); + + // Emit an event. + Self::deposit_event(Event::SetRewardsMultiplierNextPeriodDaysStored( + days.clone(), + )); + + // Return a successful DispatchResultWithPostInfo + Ok(()) + } + + // extrinsic that governance may choose to call to set the mpower of an account for a date + // if it needs to be corrected in future before they claim + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn change_mpower_of_account_for_date(origin: OriginFor, account_id: Vec, start_of_requested_date_millis: Date, mpower: u128) -> DispatchResult { + let _who = ensure_root(origin)?; + + let mpower_current_u128 = mpower.clone(); + + log::info!("change_mpower_of_account_for_date {:?} {:?} {:?}", + account_id.clone(), + start_of_requested_date_millis.clone(), + mpower_current_u128.clone(), + ); + + Self::set_mpower_of_account_for_date( + account_id.clone(), + start_of_requested_date_millis.clone(), + mpower_current_u128.clone(), + ); + + // Return a successful DispatchResultWithPostInfo + Ok(()) + } + + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn claim_rewards_of_account_for_date(origin: OriginFor, start_of_requested_date_millis: Date) -> DispatchResult { + let _who = ensure_signed(origin)?; + + // check that the current date start_of_current_date_millis is at least 7 days after the provided start_of_requested_date_millis + // so there is sufficient time for the community to audit the reward eligibility. + // we could use `CoolingOffPeriodDays` for this, but probably better to call it a `ChallengePeriodDays` + // since it serves a different purpose (`CoolingOffPeriodDays` gives rewards for first 7 days after they + // start bonding in bulk on the 8th day, and then the next day after each day after that, whereas + // `ChallengePeriodDays` you can only claim each daily rewards manually 7 days after it, even for the first + // 7 days after they start bonding) + + let current_timestamp = >::get(); + let current_timestamp_as_u64 = Self::convert_moment_to_u64_in_milliseconds(current_timestamp.clone())?; + log::info!("current_timestamp_as_u64: {:?}", current_timestamp_as_u64.clone()); + // convert the current timestamp to the start of that day date/time + // i.e. 21 Apr @ 1420 -> 21 Apr @ 0000 + let start_of_current_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(current_timestamp_as_u64.clone())?; + + // where there are 86400000 milliseconds in a day + // there are 7 * 86400000 = 604800000 milliseconds in 7 days + // so we want to make sure `start_of_current_date_millis` - `start_of_requested_date_millis` > 604800000 + + let mut is_more_than_challenge_period = false; + let _is_more_than_challenge_period = Self::is_more_than_challenge_period(start_of_requested_date_millis.clone()); + match _is_more_than_challenge_period.clone() { + Err(_e) => { + log::error!("{:?}", _e); + return Err(_e);; + }, + Ok(x) => { + is_more_than_challenge_period = x; + } + } + + // log::info!("claimed_rewards_of_account_for_date {:?} {:?} {:?}", + // account_id.clone(), + // start_of_requested_date_millis.clone(), + // rewards_claimed.clone(), + // ); + + // Self::claimed_rewards_of_account_for_date( + // account_id.clone(), + // start_of_requested_date_millis.clone(), + // rewards_claimed.clone(), + // ); + + // Return a successful DispatchResultWithPostInfo + Ok(()) + + // // TODO - consider the miner's mPower that we have fetched. it should have been added earlier above + // // to the aggregated (all miners for that day) and accumulated (specific miner for a day) rewards + + // fetch accumulated total rewards for all registered miners for the day + // TODO - we've done this twice, create a function to fetch it + // let mut rewards_aggregated_dhx_daily: BalanceOf = 0u32.into(); // initialize + // if let Some(_rewards_aggregated_dhx_daily) = >::get(&start_of_requested_date_millis) { + // rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; + // } else { + // log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period may not be finished yet"); + // // Note: it would be an issue if we got past the first loop of looping through the registered miners + // // and still hadn't added to the aggregated rewards for the day + // return 0; + // } + // println!("[multiplier] block: {:#?}, miner_count: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, miner_count, start_of_requested_date_millis, rewards_aggregated_dhx_daily); + + // if rewards_aggregated_dhx_daily == 0u32.into() { + // log::error!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); + // return 0; + // } + + // let rewards_aggregated_dhx_daily_as_u128; + // let _rewards_aggregated_dhx_daily_as_u128 = Self::convert_balance_to_u128(rewards_aggregated_dhx_daily.clone()); + // match _rewards_aggregated_dhx_daily_as_u128.clone() { + // Err(_e) => { + // log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); + // return 0; + // }, + // Ok(x) => { + // rewards_aggregated_dhx_daily_as_u128 = x; + // } + // } + // log::info!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); + + // // TODO - we've done this twice, create a function to fetch it + // let rewards_allowance_dhx_daily; + // if let Some(_rewards_allowance_dhx_daily) = >::get() { + // rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; + // } else { + // log::error!("Unable to get rewards_allowance_dhx_daily"); + // return 0; + // } + + // let rewards_allowance_dhx_daily_u128; + // let _rewards_allowance_dhx_daily_u128 = Self::convert_balance_to_u128(rewards_allowance_dhx_daily.clone()); + // match _rewards_allowance_dhx_daily_u128.clone() { + // Err(_e) => { + // log::error!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); + // return 0; + // }, + // Ok(x) => { + // rewards_allowance_dhx_daily_u128 = x; + // } + // } + + // if rewards_allowance_dhx_daily_u128 == 0u128 { + // log::error!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); + // return 0; + // } + + // // previously when we looped through all the registered dhx miners we calculated the + // // reward for each registered miner based on the 10:1 ratio, and stored that along with + // // the corresponding day in storage. since that loop we've fetched the total + // // aggregated rewards that all reg miners are eligible for on that day as `rewards_aggregated_dhx_daily`, + // // lets say it adds up to 8000 DHX, but say we only have 5000 DHX availabe to distribute + // // from `rewards_allowance_dhx_daily`, so we'll constrain the rewards they'll receive further by + // // applying a `distribution_multiplier_for_day_u128` of (5000/8000)*reg_miner_reward on each of + // // the rewards that are distributed to them. + + // // if the aggregated rewards isn't more than the daily rewards allowance available + // // then just set the multiplier to 1, so they actually get the previously calculated reward rather + // // than a scaled down proportion. + // // + // // e.g. 1: if miner rewards are 2000 & 4000 DHX respectively, this is greater than 5000 DHX daily allowance + // // so we'd have a multiplier of 5000/6000 = 5/6, so they'd receive ~1666 & 3333 DHX respectively. + // // e.g. 2: if miner rewards are 2000 & 2000 DHX respectively, this is less than 5000 DHX daily allowance + // // so we'd just use a multiplier of 1, so they'd receive 2000 & 2000 DHX respectively. + // // https://docs.rs/fixed/0.5.4/fixed/struct.FixedU128.html + // let mut distribution_multiplier_for_day_fixed128 = FixedU128::from_num(1); // initialize + + // if rewards_aggregated_dhx_daily_as_u128.clone() > rewards_allowance_dhx_daily_u128.clone() { + // // Divide, handling overflow + + // // Note: If the rewards_allowance_dhx_daily_u128 is 5000 DHX, its 5000000000000000000000, + // // but we can't convert to u64 since largest value is 18446744073709551615. + // // Since we expect the rewards_aggregated_dhx_daily_as_u128 to be at least 1 DHX (i.e. 1000000000000000000), + // // we could just divide both numbers by 1000000000000000000, so we'd have say 5000 and 1 instead, + // // since we're just using these values to get a multiplier output. + + // let mut manageable_rewards_allowance_dhx_daily_u128 = 0u128; + // if let Some(_manageable_rewards_allowance_dhx_daily_u128) = + // rewards_allowance_dhx_daily_u128.clone().checked_div(1000000000000000000u128) { + // manageable_rewards_allowance_dhx_daily_u128 = _manageable_rewards_allowance_dhx_daily_u128; + // } else { + // log::error!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); + // return 0; + // } + + // let mut rewards_allowance_dhx_daily_u64 = 0u64; + // if let Some(_rewards_allowance_dhx_daily_u64) = + // TryInto::::try_into(manageable_rewards_allowance_dhx_daily_u128.clone()).ok() { + // rewards_allowance_dhx_daily_u64 = _rewards_allowance_dhx_daily_u64; + // } else { + // log::error!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); + // return 0; + // } + + // let mut manageable_rewards_aggregated_dhx_daily_as_u128 = 0u128; + // if let Some(_manageable_rewards_aggregated_dhx_daily_as_u128) = rewards_aggregated_dhx_daily_as_u128.clone().checked_div(1000000000000000000u128) { + // manageable_rewards_aggregated_dhx_daily_as_u128 = _manageable_rewards_aggregated_dhx_daily_as_u128; + // } else { + // log::error!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); + // return 0; + // } + + // let mut rewards_aggregated_dhx_daily_as_u64 = 0u64; + // if let Some(_rewards_aggregated_dhx_daily_as_u64) = + // TryInto::::try_into(manageable_rewards_aggregated_dhx_daily_as_u128.clone()).ok() { + // rewards_aggregated_dhx_daily_as_u64 = _rewards_aggregated_dhx_daily_as_u64; + // } else { + // log::error!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); + // return 0; + // } + + // // See https://github.com/ltfschoen/substrate-node-template/pull/6/commits/175ef4805d07093042431c5814dda52da1ebde18 + // let _fraction_distribution_multiplier_for_day_fixed128 = + // U64F64::from_num(manageable_rewards_allowance_dhx_daily_u128.clone()) + // .checked_div(U64F64::from_num(manageable_rewards_aggregated_dhx_daily_as_u128.clone())); + // let _distribution_multiplier_for_day_fixed128 = _fraction_distribution_multiplier_for_day_fixed128.clone(); + // match _distribution_multiplier_for_day_fixed128 { + // None => { + // log::error!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); + // return 0; + // }, + // Some(x) => { + // distribution_multiplier_for_day_fixed128 = x; + // } + // } + // } + // log::info!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); + // // println!("[multiplier] block: {:#?}, miner_count: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, miner_count, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); + + // // Initialise outside the loop as we need this value after the loop after we finish iterating through all the miners + // let mut rewards_allowance_dhx_remaining_today_as_u128 = 0u128; + + // miner_count = 0; + // for (index, miner_public_key) in reg_dhx_miners.iter().enumerate() { + // miner_count += 1; + // log::info!("rewards loop - miner_count {:#?}", miner_count); + // log::info!("rewards loop - miner_public_key {:#?}", miner_public_key); + + // // only run the following once per day per miner until rewards_allowance_dhx_for_date_remaining is exhausted + // // but since we're giving each registered miner a proportion of the daily reward allowance + // // (if their aggregated rewards is above daily allowance) each proportion is rounded down, + // // it shouldn't become exhausted anyway + // let is_already_distributed = >::get(start_of_requested_date_millis.clone()); + // if is_already_distributed == Some(true) { + // log::error!("Unable to distribute further rewards allowance today"); + // return 0; + // } + + // let daily_reward_for_miner_as_u128; + // let daily_reward_for_miner_to_try = >::get( + // ( + // start_of_requested_date_millis.clone(), + // miner_public_key.clone(), + // ), + // ); + // if let Some(_daily_reward_for_miner_to_try) = daily_reward_for_miner_to_try.clone() { + // let _daily_reward_for_miner_as_u128 = Self::convert_balance_to_u128(_daily_reward_for_miner_to_try.clone()); + // match _daily_reward_for_miner_as_u128.clone() { + // Err(_e) => { + // log::error!("Unable to convert balance to u128 for daily_reward_for_miner_as_u128"); + // return 0; + // }, + // Ok(x) => { + // daily_reward_for_miner_as_u128 = x; + // } + // } + // } else { + // // If any of the miner's don't have a reward, we won't waste storing that, + // // so we want to move to the next miner in the loop + // log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); + // continue; + // } + // log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); + + // let mut manageable_daily_reward_for_miner_as_u128 = 0u128; + // if let Some(_manageable_daily_reward_for_miner_as_u128) = + // daily_reward_for_miner_as_u128.clone().checked_div(1000000000000000000u128) { + // manageable_daily_reward_for_miner_as_u128 = _manageable_daily_reward_for_miner_as_u128; + // } else { + // log::error!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); + // return 0; + // } + + // // Multiply, handling overflow + // // TODO - probably have to initialise below proportion_of_daily_reward_for_miner_fixed128 to 0u128, + // // and convert distribution_multiplier_for_day_fixed128 to u64, + // // and convert daily_reward_for_miner_as_u128 to u64 too, like i did earlier. + // // but it works so this doesn't seem necessary. + // let proportion_of_daily_reward_for_miner_fixed128; + // let _proportion_of_daily_reward_for_miner_fixed128 = + // U64F64::from_num(distribution_multiplier_for_day_fixed128.clone()).checked_mul(U64F64::from_num(manageable_daily_reward_for_miner_as_u128.clone())); + // match _proportion_of_daily_reward_for_miner_fixed128 { + // None => { + // log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); + // return 0; + // }, + // Some(x) => { + // proportion_of_daily_reward_for_miner_fixed128 = x; + // } + // } + // log::info!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); + + // // round down to nearest integer. we need to round down, because if we round up then if there are + // // 3x registered miners with 5000 DHX rewards allowance per day then they would each get 1667 rewards, + // // but there would only be 1666 remaining after the first two, so the last one would miss out. + // // so if we round down they each get 1666 DHX and there is 2 DHX from the daily allocation that doesn't get distributed at all. + // let proportion_of_daily_reward_for_miner_u128: u128 = proportion_of_daily_reward_for_miner_fixed128.floor().to_num::(); + + // // we lose some accuracy doing this conversion, but at least we split the bulk of the rewards proportionally and fairly + // let mut restored_proportion_of_daily_reward_for_miner_u128 = 0u128; + // if let Some(_restored_proportion_of_daily_reward_for_miner_u128) = + // proportion_of_daily_reward_for_miner_u128.clone().checked_mul(1000000000000000000u128) { + // restored_proportion_of_daily_reward_for_miner_u128 = _restored_proportion_of_daily_reward_for_miner_u128; + // } else { + // log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); + // return 0; + // } + + // // println!("[rewards] block: {:#?}, miner_count: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); + + // let treasury_account_id: T::AccountId = >::account_id(); + // let max_payout = pallet_balances::Pallet::::usable_balance(treasury_account_id.clone()); + // log::info!("Treasury account id: {:?}", treasury_account_id.clone()); + // log::info!("Miner to receive reward: {:?}", miner_public_key.clone()); + // log::info!("Treasury balance max payout: {:?}", max_payout.clone()); + + // let proportion_of_daily_reward_for_miner; + // let _proportion_of_daily_reward_for_miner = Self::convert_u128_to_balance(restored_proportion_of_daily_reward_for_miner_u128.clone()); + // match _proportion_of_daily_reward_for_miner { + // Err(_e) => { + // log::error!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); + // return 0; + // }, + // Ok(ref x) => { + // proportion_of_daily_reward_for_miner = x; + // } + // } - // Validate inputs so the daily_rewards is less or equal to the existing_allowance - let existing_allowance_as_u128; - if let Some(_existing_allowance) = >::get(&start_of_requested_date_millis) { - existing_allowance_as_u128 = Self::convert_balance_to_u128(_existing_allowance.clone())?; - log::info!("change_rewards_allowance_dhx_for_date_remaining - existing_allowance_as_u128: {:?}", existing_allowance_as_u128.clone()); - } else { - return Err(DispatchError::Other("Unable to retrieve balance from value provided")); - } + // let max_payout_as_u128; + // if let Some(_max_payout_as_u128) = TryInto::::try_into(max_payout).ok() { + // max_payout_as_u128 = _max_payout_as_u128; + // } else { + // log::error!("Unable to convert Balance to u128 for max_payout"); + // return 0; + // } + // log::info!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); - let daily_rewards_as_u128; - daily_rewards_as_u128 = Self::convert_balance_to_u128(daily_rewards.clone())?; - log::info!("change_rewards_allowance_dhx_for_date_remaining - daily_rewards_as_u128: {:?}", daily_rewards_as_u128.clone()); + // // Store output `rewards_allowance_dhx_remaining_today_as_u128` outside the loop + // // Validate inputs so the daily_rewards is less or equal to the existing_allowance + // if let Some(_rewards_allowance_dhx_remaining_today) = >::get(&start_of_requested_date_millis) { + // let _rewards_allowance_dhx_remaining_today_as_u128 = Self::convert_balance_to_u128(_rewards_allowance_dhx_remaining_today.clone()); + // match _rewards_allowance_dhx_remaining_today_as_u128.clone() { + // Err(_e) => { + // log::error!("Unable to convert balance to u128"); + // return 0; + // }, + // Ok(x) => { + // rewards_allowance_dhx_remaining_today_as_u128 = x; + // } + // } + // log::info!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); + // } else { + // log::error!("Unable to retrieve balance from value provided."); + // return 0; + // } - ensure!(daily_rewards_as_u128 > 0u128, DispatchError::Other("Daily rewards must be greater than zero")); - ensure!(existing_allowance_as_u128 >= daily_rewards_as_u128, DispatchError::Other("Daily rewards cannot exceed current remaining allowance")); + // // println!("[prepared-for-payment] block: {:#?}, miner_count: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, miner_count, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); - let new_remaining_allowance_as_balance; - if change == 0 { - // Decrementing the value will error in the event of underflow. - let new_remaining_allowance_as_u128 = existing_allowance_as_u128.checked_sub(daily_rewards_as_u128).ok_or(Error::::StorageUnderflow)?; - new_remaining_allowance_as_balance = Self::convert_u128_to_balance(new_remaining_allowance_as_u128.clone())?; - log::info!("change_rewards_allowance_dhx_for_date_remaining - Decreasing rewards_allowance_dhx_for_date_remaining at Date: {:?}", &start_of_requested_date_millis); - } else { - // Incrementing the value will error in the event of overflow. - let new_remaining_allowance_as_u128 = existing_allowance_as_u128.checked_add(daily_rewards_as_u128).ok_or(Error::::StorageOverflow)?; - new_remaining_allowance_as_balance = Self::convert_u128_to_balance(new_remaining_allowance_as_u128.clone())?; - log::info!("change_rewards_allowance_dhx_for_date_remaining - Increasing rewards_allowance_dhx_for_date_remaining at Date: {:?}", &start_of_requested_date_millis); - } + // // check if miner's reward is less than or equal to: rewards_allowance_dhx_daily_remaining + // if restored_proportion_of_daily_reward_for_miner_u128.clone() > 0u128 && + // rewards_allowance_dhx_remaining_today_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() && + // max_payout_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() + // { + // // pay the miner their daily reward + // info!("Paying the miner a proportion of the remaining daily reward allowance"); - // Update storage - >::mutate( - &start_of_requested_date_millis, - |allowance| { - if let Some(_allowance) = allowance { - *_allowance = new_remaining_allowance_as_balance.clone(); - } - }, - ); + // let tx_result; + // let _tx_result = ::Currency::transfer( + // &treasury_account_id, + // &miner_public_key.clone(), + // proportion_of_daily_reward_for_miner.clone(), + // ExistenceRequirement::KeepAlive + // ); + // match _tx_result { + // Err(_e) => { + // log::error!("Unable to transfer from treasury to miner {:?}", miner_public_key.clone()); + // return 0; + // }, + // Ok(ref x) => { + // tx_result = x; + // } + // } + // info!("Transfer to the miner tx_result: {:?}", tx_result.clone()); - // Emit an event. - Self::deposit_event(Event::ChangedRewardsAllowanceDHXForDateRemainingStored( - start_of_requested_date_millis.clone(), - new_remaining_allowance_as_balance.clone(), - change.clone(), - )); + // info!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); - // Return a successful DispatchResultWithPostInfo - Ok(()) - } + // // TODO - move into function `reduce_rewards_allowance_dhx_for_date_remaining`? - // only modifiable by governance as root rather than just any user - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn set_rewards_multiplier_operation(origin: OriginFor, operation: u8) -> DispatchResult { - let _who = ensure_root(origin)?; - >::put(&operation.clone()); - log::info!("set_rewards_multiplier_operation - operation: {:?}", &operation); + // // Subtract, handling overflow + // let new_rewards_allowance_dhx_remaining_today_as_u128; + // let _new_rewards_allowance_dhx_remaining_today_as_u128 = + // rewards_allowance_dhx_remaining_today_as_u128.clone().checked_sub(restored_proportion_of_daily_reward_for_miner_u128.clone()); + // match _new_rewards_allowance_dhx_remaining_today_as_u128 { + // None => { + // log::error!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); + // return 0; + // }, + // Some(x) => { + // new_rewards_allowance_dhx_remaining_today_as_u128 = x; + // } + // } - // Emit an event. - Self::deposit_event(Event::SetRewardsMultiplierOperationStored( - operation.clone(), - )); + // let new_rewards_allowance_dhx_remaining_today; + // let _new_rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(new_rewards_allowance_dhx_remaining_today_as_u128.clone()); + // match _new_rewards_allowance_dhx_remaining_today { + // Err(_e) => { + // log::error!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); + // return 0; + // }, + // Ok(ref x) => { + // new_rewards_allowance_dhx_remaining_today = x; + // } + // } - // Return a successful DispatchResultWithPostInfo - Ok(()) - } + // // Write the new value to storage + // >::insert( + // start_of_requested_date_millis.clone(), + // new_rewards_allowance_dhx_remaining_today.clone(), + // ); - // only modifiable by governance as root rather than just any user - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn set_rewards_multiplier_default_period_days(origin: OriginFor, days: u32) -> DispatchResult { - let _who = ensure_root(origin)?; - >::put(&days.clone()); - log::info!("set_rewards_multiplier_default_period_days - days: {:?}", &days); + // // println!("[paid] block: {:#?}, miner_count: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); - // Emit an event. - Self::deposit_event(Event::SetRewardsMultiplierDefaultPeriodDaysStored( - days.clone(), - )); + // // emit event with reward payment history rather than bloating storage + // Self::deposit_event(Event::TransferredRewardsAllowanceDHXToMinerForDate( + // start_of_requested_date_millis.clone(), + // proportion_of_daily_reward_for_miner.clone(), + // new_rewards_allowance_dhx_remaining_today.clone(), + // miner_public_key.clone(), + // )); - // Return a successful DispatchResultWithPostInfo - Ok(()) - } + // log::info!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", + // start_of_requested_date_millis.clone(), + // proportion_of_daily_reward_for_miner.clone(), + // new_rewards_allowance_dhx_remaining_today.clone(), + // miner_public_key.clone(), + // ); - // only modifiable by governance as root rather than just any user - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn set_rewards_multiplier_next_period_days(origin: OriginFor, days: u32) -> DispatchResult { - let _who = ensure_root(origin)?; - >::put(&days.clone()); - log::info!("set_rewards_multiplier_next_period_days - days: {:?}", &days); + // continue; + // } else { + // log::error!("Insufficient remaining rewards allowance to pay daily reward to miner"); - // Emit an event. - Self::deposit_event(Event::SetRewardsMultiplierNextPeriodDaysStored( - days.clone(), - )); + // break; + // } + // } - // Return a successful DispatchResultWithPostInfo - Ok(()) - } + // let rewards_allowance_dhx_remaining_today; + // let _rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(rewards_allowance_dhx_remaining_today_as_u128.clone()); + // match _rewards_allowance_dhx_remaining_today { + // Err(_e) => { + // log::error!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); + // return 0; + // }, + // Ok(ref x) => { + // rewards_allowance_dhx_remaining_today = x; + // } + // } - // extrinsic that governance may choose to call to set the mpower of an account for a date - // if it needs to be corrected in future before they claim - #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn change_mpower_of_account_for_date(origin: OriginFor, account_id: Vec, start_of_requested_date_millis: Date, mpower: u128) -> DispatchResult { - let _who = ensure_root(origin)?; + // >::insert( + // start_of_requested_date_millis.clone(), + // true + // ); - let mpower_current_u128 = mpower.clone(); + // // println!("[distributed] block: {:#?}, miner_count: {:#?}, date_start: {:#?} ", block_number, miner_count, start_of_requested_date_millis); - log::info!("change_mpower_of_account_for_date {:?} {:?} {:?}", - account_id.clone(), - start_of_requested_date_millis.clone(), - mpower_current_u128.clone(), - ); + // Self::deposit_event(Event::DistributedRewardsAllowanceDHXForDateRemaining( + // start_of_requested_date_millis.clone(), + // rewards_allowance_dhx_remaining_today.clone(), + // )); - Self::set_mpower_of_account_for_date( - account_id.clone(), - start_of_requested_date_millis.clone(), - mpower_current_u128.clone(), - ); + // return 0; - // Return a successful DispatchResultWithPostInfo - Ok(()) } // Off-chain workers @@ -3128,5 +3204,65 @@ pub mod pallet { // .propagate(true) // .build() } + + // check that the current date start_of_current_date_millis is at least 7 days after the provided + // start_of_requested_date_millis so there is sufficient time for the community to audit the reward eligibility. + // we could use `CoolingOffPeriodDays` for this, but probably better to call it a `ChallengePeriodDays` + // since it serves a different purpose (`CoolingOffPeriodDays` gives rewards for first 7 days after they + // start bonding in bulk on the 8th day, and then the next day after each day after that, whereas + // `ChallengePeriodDays` you can only claim each daily rewards manually 7 days after it, even for the first + // 7 days after they start bonding) + pub fn is_more_than_challenge_period(start_of_requested_date_millis: i64) -> Result { + let current_timestamp = >::get(); + let current_timestamp_as_u64 = Self::convert_moment_to_u64_in_milliseconds(current_timestamp.clone())?; + log::info!("current_timestamp_as_u64: {:?}", current_timestamp_as_u64.clone()); + // convert the current timestamp to the start of that day date/time + // i.e. 21 Apr @ 1420 -> 21 Apr @ 0000 + let start_of_current_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(current_timestamp_as_u64.clone())?; + + // where there are 86400000 milliseconds in a day then challenge_period_millis is + // 7 * 86400000 = 604800000 milliseconds if challenge_period_days is 7 days + // so we want to make sure `start_of_current_date_millis` - `start_of_requested_date_millis` > 604800000 + + let mut is_more_than_challenge_period = false; + if let Some(_period_millis) = start_of_current_date_millis.clone().checked_sub(start_of_requested_date_millis.clone()) { + let millis_per_day = 86400000u64; + let mut challenge_period_days = 0u64; + if let Some(_challenge_period_days) = >::get() { + challenge_period_days = _challenge_period_days; + } else { + log::error!("Unable to get challenge_period_days"); + return Err(DispatchError::Other("Unable to get challenge_period_days"));; + } + let mut challenge_period_millis = 0u64; + if let Some(_challenge_period_millis) = challenge_period_days.clone().checked_mul(millis_per_day.clone()) { + challenge_period_millis = _challenge_period_millis; + } else { + log::error!("Unable to multiply to determine challenge_period_millis"); + return Err(DispatchError::Other("Unable to multiply to determine challenge_period_millis")); + } + + let challenge_period_millis = challenge_period_days.clone() * millis_per_day.clone(); + + let mut period_millis_u64 = 0u64; // initialize + if let Some(_period_millis_u64) = TryInto::::try_into(_period_millis.clone()).ok() { + period_millis_u64 = _period_millis_u64; + } else { + log::error!("Unable to convert i32 to u64 for period_millis"); + return Err(DispatchError::Other("Unable to convert i32 to u64 for period_millis")); + } + + // log::info!("period_millis_u64: {:?}", period_millis_u64.clone()); + // println!("period_millis_u64: {:?}", period_millis_u64.clone()); + if (period_millis_u64 >= challenge_period_millis.clone()) { + is_more_than_challenge_period = true; + } + } else { + log::error!("Unable to subtract to determine if challenge period is satisfied"); + return Err(DispatchError::Other("Unable to subtract to determine if challenge period is satisfied")); + } + + return Ok(is_more_than_challenge_period.clone()); + } } } diff --git a/pallets/mining/rewards-allowance/src/mock.rs b/pallets/mining/rewards-allowance/src/mock.rs index 67a41f855..2fd42384e 100644 --- a/pallets/mining/rewards-allowance/src/mock.rs +++ b/pallets/mining/rewards-allowance/src/mock.rs @@ -551,6 +551,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { min_bonded_dhx_daily_default: TEN_DHX, // 10 DHX min_mpower_daily: 5u128, min_mpower_daily_default: 5u128, + challenge_period_days: 7u64, cooling_off_period_days: 7u32, // Note: i'm not sure how to mock Alice, just set in implementation at genesis // cooling_off_period_days_remaining: vec![ diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 9de9dbf68..9d6502ffe 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -302,6 +302,27 @@ fn it_converts_vec_u8_to_u128() { }); } +#[test] +// note: we're using a challenge period of 7 days +fn it_checks_if_is_more_than_challenge_period() { + new_test_ext().execute_with(|| { + // where milliseconds/day 86400000 + + // 1st Dec 2021 @ 12am is 1638316800000 (start of day) + let start_of_requested_date_millis: i64 = 1638316800000i64; + + // 7th Dec 2021 @ 12am is 1638835200000 (start of day) + let current_timestamp_6_days_later = 1638835200000u64; + Timestamp::set_timestamp(current_timestamp_6_days_later); + assert_eq!(MiningRewardsAllowanceTestModule::is_more_than_challenge_period(start_of_requested_date_millis), Ok(false)); + + // 8th Dec 2021 @ 12am is 1638921600000 (start of day) + let current_timestamp_7_days_later = 1638921600000u64; + Timestamp::set_timestamp(current_timestamp_7_days_later); + assert_eq!(MiningRewardsAllowanceTestModule::is_more_than_challenge_period(start_of_requested_date_millis), Ok(true)); + }); +} + fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( Origin::root(), From 18f919ac87c5300c8af9c458c5ff6ea8efb2ae0d Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 2 Dec 2021 08:12:11 +0100 Subject: [PATCH 23/37] wip --- node/src/chain_spec.rs | 4 + pallets/mining/rewards-allowance/src/lib.rs | 845 ++++++++++--------- pallets/mining/rewards-allowance/src/mock.rs | 2 + 3 files changed, 460 insertions(+), 391 deletions(-) diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index 0b5faadba..ec306d7a3 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -922,6 +922,7 @@ fn testnet_genesis( rewards_allowance_dhx_daily: FIVE_THOUSAND, // 5000 DHX rewards_allowance_dhx_for_date_remaining: Default::default(), rewards_allowance_dhx_for_date_remaining_distributed: Default::default(), + rewards_allowance_dhx_for_miner_for_date_remaining_distributed: Default::default(), rewards_multiplier_paused: false, rewards_multiplier_reset: false, rewards_multiplier_default_change: 10u32, @@ -941,6 +942,7 @@ fn testnet_genesis( // Bob vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72], ], + rewards_eligible_miners_for_date: Default::default(), rewards_aggregated_dhx_for_all_miners_for_date: Default::default(), rewards_accumulated_dhx_for_miner_for_date: Default::default(), min_bonded_dhx_daily: TEN, // 10 DHX @@ -1067,6 +1069,7 @@ fn mainnet_genesis( rewards_allowance_dhx_daily: FIVE_THOUSAND, // 5000 DHX rewards_allowance_dhx_for_date_remaining: Default::default(), rewards_allowance_dhx_for_date_remaining_distributed: Default::default(), + rewards_allowance_dhx_for_miner_for_date_remaining_distributed: Default::default(), rewards_multiplier_paused: false, rewards_multiplier_reset: false, rewards_multiplier_default_change: 10u32, @@ -1086,6 +1089,7 @@ fn mainnet_genesis( // Bob vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72], ], + rewards_eligible_miners_for_date: Default::default(), rewards_aggregated_dhx_for_all_miners_for_date: Default::default(), rewards_accumulated_dhx_for_miner_for_date: Default::default(), min_bonded_dhx_daily: TEN, // 10 DHX diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 61639503c..2426193d0 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -289,6 +289,7 @@ pub mod pallet { BalanceOf >; + // checks if all eligible registered dhx miners have already received their reward for a specific date #[pallet::storage] #[pallet::getter(fn rewards_allowance_dhx_for_date_remaining_distributed)] pub(super) type RewardsAllowanceDHXForDateRemainingDistributed = StorageMap<_, Blake2_128Concat, @@ -296,6 +297,17 @@ pub mod pallet { bool >; + // checks if a specific registered dhx miner has already received their reward for a specific date + #[pallet::storage] + #[pallet::getter(fn rewards_allowance_dhx_for_miner_for_date_remaining_distributed)] + pub(super) type RewardsAllowanceDHXForMinerForDateRemainingDistributed = StorageMap<_, Blake2_128Concat, + ( + Date, + Vec, // public key of AccountId + ), + bool + >; + #[pallet::storage] #[pallet::getter(fn rewards_allowance_dhx_daily)] pub(super) type RewardsAllowanceDHXDaily = StorageValue<_, BalanceOf>; @@ -376,6 +388,13 @@ pub mod pallet { #[pallet::getter(fn registered_dhx_miners)] pub(super) type RegisteredDHXMiners = StorageValue<_, Vec>>; + #[pallet::storage] + #[pallet::getter(fn rewards_eligible_miners_for_date)] + pub(super) type RewardsEligibleMinersForDate = StorageMap<_, Blake2_128Concat, + Date, + Vec>, + >; + #[pallet::storage] #[pallet::getter(fn min_bonded_dhx_daily)] pub(super) type MinBondedDHXDaily = StorageValue<_, BalanceOf>; @@ -449,6 +468,7 @@ pub mod pallet { pub struct GenesisConfig { pub rewards_allowance_dhx_for_date_remaining: Vec<(Date, BalanceOf)>, pub rewards_allowance_dhx_for_date_remaining_distributed: Vec<(Date, bool)>, + pub rewards_allowance_dhx_for_miner_for_date_remaining_distributed: Vec<((Date, Vec), bool)>, pub rewards_allowance_dhx_daily: BalanceOf, pub rewards_multiplier_paused: bool, pub rewards_multiplier_reset: bool, @@ -463,6 +483,7 @@ pub mod pallet { pub rewards_aggregated_dhx_for_all_miners_for_date: Vec<(Date, BalanceOf)>, pub rewards_accumulated_dhx_for_miner_for_date: Vec<((Date, Vec), BalanceOf)>, pub registered_dhx_miners: Vec>, + pub rewards_eligible_miners_for_date: Vec>>, pub min_bonded_dhx_daily: BalanceOf, pub min_bonded_dhx_daily_default: BalanceOf, pub min_mpower_daily: u128, @@ -479,6 +500,7 @@ pub mod pallet { Self { rewards_allowance_dhx_for_date_remaining: Default::default(), rewards_allowance_dhx_for_date_remaining_distributed: Default::default(), + rewards_allowance_dhx_for_miner_for_date_remaining_distributed: Default::default(), // 5000 UNIT, where UNIT token has 18 decimal places rewards_allowance_dhx_daily: Default::default(), rewards_multiplier_paused: false, @@ -500,6 +522,7 @@ pub mod pallet { Default::default(), Default::default(), ], + rewards_eligible_miners_for_date: Default::default(), min_bonded_dhx_daily: Default::default(), min_bonded_dhx_daily_default: Default::default(), min_mpower_daily: 5u128, @@ -532,6 +555,9 @@ pub mod pallet { for (a, b) in &self.rewards_allowance_dhx_for_date_remaining_distributed { >::insert(a, b); } + for ((a, b), c) in &self.rewards_allowance_dhx_for_miner_for_date_remaining_distributed { + >::insert((a, b), c); + } >::put(&self.rewards_allowance_dhx_daily); >::put(&self.rewards_multiplier_paused); >::put(&self.rewards_multiplier_reset); @@ -545,6 +571,9 @@ pub mod pallet { for (a) in &self.registered_dhx_miners { >::append(a); } + for (a, b) in &self.rewards_eligible_miners_for_date { + >::insert(a, b); + } >::put(&self.rewards_multiplier_operation); for (a, b) in &self.rewards_aggregated_dhx_for_all_miners_for_date { >::insert(a, b); @@ -1551,6 +1580,20 @@ pub mod pallet { ); log::info!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); + // Store a list of all the the registered_dhx_miners that are eligible for rewards on a given date + // so we know they have been used as keys for other storage maps like `RewardsAccumulatedDHXForMinerForDate` + // for future querying + let mut rewards_eligible_miners_for_date: Vec> = vec![]; // initialize + if let Some(_rewards_eligible_miners_for_date) = >::get(start_of_requested_date_millis.clone()) { + rewards_eligible_miners_for_date = _rewards_eligible_miners_for_date; + } else { + log::error!("Unable to retrieve rewards_eligible_miners_for_date"); + return; + } + + let new_rewards_eligible_miners_for_date = rewards_eligible_miners_for_date.push(miner_public_key.clone()); + >::insert(start_of_requested_date_millis.clone(), new_rewards_eligible_miners_for_date.clone()); + // println!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); // if last miner being iterated then reset for next day if reg_dhx_miners.len() == miner_count { @@ -1947,7 +1990,9 @@ pub mod pallet { #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn claim_rewards_of_account_for_date(origin: OriginFor, start_of_requested_date_millis: Date) -> DispatchResult { - let _who = ensure_signed(origin)?; + let _sender = ensure_signed(origin)?; + let miner_public_key = _sender.encode(); + let block_number = >::block_number(); // check that the current date start_of_current_date_millis is at least 7 days after the provided start_of_requested_date_millis // so there is sufficient time for the community to audit the reward eligibility. @@ -1973,422 +2018,440 @@ pub mod pallet { match _is_more_than_challenge_period.clone() { Err(_e) => { log::error!("{:?}", _e); - return Err(_e);; + return Err(_e); }, Ok(x) => { is_more_than_challenge_period = x; } } - // log::info!("claimed_rewards_of_account_for_date {:?} {:?} {:?}", - // account_id.clone(), - // start_of_requested_date_millis.clone(), - // rewards_claimed.clone(), - // ); - - // Self::claimed_rewards_of_account_for_date( - // account_id.clone(), - // start_of_requested_date_millis.clone(), - // rewards_claimed.clone(), - // ); - - // Return a successful DispatchResultWithPostInfo - Ok(()) - // // TODO - consider the miner's mPower that we have fetched. it should have been added earlier above // // to the aggregated (all miners for that day) and accumulated (specific miner for a day) rewards // fetch accumulated total rewards for all registered miners for the day // TODO - we've done this twice, create a function to fetch it - // let mut rewards_aggregated_dhx_daily: BalanceOf = 0u32.into(); // initialize - // if let Some(_rewards_aggregated_dhx_daily) = >::get(&start_of_requested_date_millis) { - // rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; - // } else { - // log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period may not be finished yet"); - // // Note: it would be an issue if we got past the first loop of looping through the registered miners - // // and still hadn't added to the aggregated rewards for the day - // return 0; - // } - // println!("[multiplier] block: {:#?}, miner_count: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, miner_count, start_of_requested_date_millis, rewards_aggregated_dhx_daily); + let mut rewards_aggregated_dhx_daily: BalanceOf = 0u32.into(); // initialize + if let Some(_rewards_aggregated_dhx_daily) = >::get(&start_of_requested_date_millis) { + rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; + } else { + log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet"); + // Note: it would be an issue if we got past the first loop of looping through the registered miners + // and still hadn't added to the aggregated rewards for the day + return Err(DispatchError::Other("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet")); + } + // println!("[multiplier] block: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, start_of_requested_date_millis, rewards_aggregated_dhx_daily); - // if rewards_aggregated_dhx_daily == 0u32.into() { - // log::error!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); - // return 0; - // } + if rewards_aggregated_dhx_daily == 0u32.into() { + log::error!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); + return Err(DispatchError::Other("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards")); + } - // let rewards_aggregated_dhx_daily_as_u128; - // let _rewards_aggregated_dhx_daily_as_u128 = Self::convert_balance_to_u128(rewards_aggregated_dhx_daily.clone()); - // match _rewards_aggregated_dhx_daily_as_u128.clone() { - // Err(_e) => { - // log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); - // return 0; - // }, - // Ok(x) => { - // rewards_aggregated_dhx_daily_as_u128 = x; - // } - // } - // log::info!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); + let rewards_aggregated_dhx_daily_as_u128; + let _rewards_aggregated_dhx_daily_as_u128 = Self::convert_balance_to_u128(rewards_aggregated_dhx_daily.clone()); + match _rewards_aggregated_dhx_daily_as_u128.clone() { + Err(_e) => { + log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); + return Err(DispatchError::Other("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128")); + }, + Ok(x) => { + rewards_aggregated_dhx_daily_as_u128 = x; + } + } + log::info!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); - // // TODO - we've done this twice, create a function to fetch it - // let rewards_allowance_dhx_daily; - // if let Some(_rewards_allowance_dhx_daily) = >::get() { - // rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; - // } else { - // log::error!("Unable to get rewards_allowance_dhx_daily"); - // return 0; - // } + // TODO - we've done this twice, create a function to fetch it + let rewards_allowance_dhx_daily; + if let Some(_rewards_allowance_dhx_daily) = >::get() { + rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; + } else { + log::error!("Unable to get rewards_allowance_dhx_daily"); + return Err(DispatchError::Other("Unable to get rewards_allowance_dhx_daily")); + } - // let rewards_allowance_dhx_daily_u128; - // let _rewards_allowance_dhx_daily_u128 = Self::convert_balance_to_u128(rewards_allowance_dhx_daily.clone()); - // match _rewards_allowance_dhx_daily_u128.clone() { - // Err(_e) => { - // log::error!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); - // return 0; - // }, - // Ok(x) => { - // rewards_allowance_dhx_daily_u128 = x; - // } - // } + let rewards_allowance_dhx_daily_u128; + let _rewards_allowance_dhx_daily_u128 = Self::convert_balance_to_u128(rewards_allowance_dhx_daily.clone()); + match _rewards_allowance_dhx_daily_u128.clone() { + Err(_e) => { + log::error!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); + return Err(DispatchError::Other("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128")); + }, + Ok(x) => { + rewards_allowance_dhx_daily_u128 = x; + } + } + + if rewards_allowance_dhx_daily_u128 == 0u128 { + log::error!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); + return Err(DispatchError::Other("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards")); + } + + // previously when we looped through all the registered dhx miners we calculated the + // reward for each registered miner based on the 10:1 ratio, and stored that along with + // the corresponding day in storage. since that loop we've fetched the total + // aggregated rewards that all reg miners are eligible for on that day as `rewards_aggregated_dhx_daily`, + // lets say it adds up to 8000 DHX, but say we only have 5000 DHX availabe to distribute + // from `rewards_allowance_dhx_daily`, so we'll constrain the rewards they'll receive further by + // applying a `distribution_multiplier_for_day_u128` of (5000/8000)*reg_miner_reward on each of + // the rewards that are distributed to them. + + // if the aggregated rewards isn't more than the daily rewards allowance available + // then just set the multiplier to 1, so they actually get the previously calculated reward rather + // than a scaled down proportion. + // + // e.g. 1: if miner rewards are 2000 & 4000 DHX respectively, this is greater than 5000 DHX daily allowance + // so we'd have a multiplier of 5000/6000 = 5/6, so they'd receive ~1666 & 3333 DHX respectively. + // e.g. 2: if miner rewards are 2000 & 2000 DHX respectively, this is less than 5000 DHX daily allowance + // so we'd just use a multiplier of 1, so they'd receive 2000 & 2000 DHX respectively. + // https://docs.rs/fixed/0.5.4/fixed/struct.FixedU128.html + let mut distribution_multiplier_for_day_fixed128 = FixedU128::from_num(1); // initialize + + if rewards_aggregated_dhx_daily_as_u128.clone() > rewards_allowance_dhx_daily_u128.clone() { + // Divide, handling overflow + + // Note: If the rewards_allowance_dhx_daily_u128 is 5000 DHX, its 5000000000000000000000, + // but we can't convert to u64 since largest value is 18446744073709551615. + // Since we expect the rewards_aggregated_dhx_daily_as_u128 to be at least 1 DHX (i.e. 1000000000000000000), + // we could just divide both numbers by 1000000000000000000, so we'd have say 5000 and 1 instead, + // since we're just using these values to get a multiplier output. + + let mut manageable_rewards_allowance_dhx_daily_u128 = 0u128; + if let Some(_manageable_rewards_allowance_dhx_daily_u128) = + rewards_allowance_dhx_daily_u128.clone().checked_div(1000000000000000000u128) { + manageable_rewards_allowance_dhx_daily_u128 = _manageable_rewards_allowance_dhx_daily_u128; + } else { + log::error!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); + return Err(DispatchError::Other("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller")); + } + + let mut rewards_allowance_dhx_daily_u64 = 0u64; + if let Some(_rewards_allowance_dhx_daily_u64) = + TryInto::::try_into(manageable_rewards_allowance_dhx_daily_u128.clone()).ok() { + rewards_allowance_dhx_daily_u64 = _rewards_allowance_dhx_daily_u64; + } else { + log::error!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); + return Err(DispatchError::Other("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128")); + } + + let mut manageable_rewards_aggregated_dhx_daily_as_u128 = 0u128; + if let Some(_manageable_rewards_aggregated_dhx_daily_as_u128) = rewards_aggregated_dhx_daily_as_u128.clone().checked_div(1000000000000000000u128) { + manageable_rewards_aggregated_dhx_daily_as_u128 = _manageable_rewards_aggregated_dhx_daily_as_u128; + } else { + log::error!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); + return Err(DispatchError::Other("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller")); + } + + let mut rewards_aggregated_dhx_daily_as_u64 = 0u64; + if let Some(_rewards_aggregated_dhx_daily_as_u64) = + TryInto::::try_into(manageable_rewards_aggregated_dhx_daily_as_u128.clone()).ok() { + rewards_aggregated_dhx_daily_as_u64 = _rewards_aggregated_dhx_daily_as_u64; + } else { + log::error!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); + return Err(DispatchError::Other("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128")); + } - // if rewards_allowance_dhx_daily_u128 == 0u128 { - // log::error!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); + // See https://github.com/ltfschoen/substrate-node-template/pull/6/commits/175ef4805d07093042431c5814dda52da1ebde18 + let _fraction_distribution_multiplier_for_day_fixed128 = + U64F64::from_num(manageable_rewards_allowance_dhx_daily_u128.clone()) + .checked_div(U64F64::from_num(manageable_rewards_aggregated_dhx_daily_as_u128.clone())); + let _distribution_multiplier_for_day_fixed128 = _fraction_distribution_multiplier_for_day_fixed128.clone(); + match _distribution_multiplier_for_day_fixed128 { + None => { + log::error!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); + return Err(DispatchError::Other("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128")); + }, + Some(x) => { + distribution_multiplier_for_day_fixed128 = x; + } + } + } + log::info!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); + // println!("[multiplier] block: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); + + // Initialise outside the loop as we need this value after the loop after we finish iterating through all the miners + let mut rewards_allowance_dhx_remaining_today_as_u128 = 0u128; + + + // only run the following once per day per miner until rewards_allowance_dhx_for_date_remaining is exhausted + // but since we're giving each registered miner a proportion of the daily reward allowance + // (if their aggregated rewards is above daily allowance) each proportion is rounded down, + // it shouldn't become exhausted anyway + // let is_already_distributed = >::get(start_of_requested_date_millis.clone()); + // if is_already_distributed == Some(true) { + // log::error!("Unable to distribute further rewards allowance today"); // return 0; // } - // // previously when we looped through all the registered dhx miners we calculated the - // // reward for each registered miner based on the 10:1 ratio, and stored that along with - // // the corresponding day in storage. since that loop we've fetched the total - // // aggregated rewards that all reg miners are eligible for on that day as `rewards_aggregated_dhx_daily`, - // // lets say it adds up to 8000 DHX, but say we only have 5000 DHX availabe to distribute - // // from `rewards_allowance_dhx_daily`, so we'll constrain the rewards they'll receive further by - // // applying a `distribution_multiplier_for_day_u128` of (5000/8000)*reg_miner_reward on each of - // // the rewards that are distributed to them. - - // // if the aggregated rewards isn't more than the daily rewards allowance available - // // then just set the multiplier to 1, so they actually get the previously calculated reward rather - // // than a scaled down proportion. - // // - // // e.g. 1: if miner rewards are 2000 & 4000 DHX respectively, this is greater than 5000 DHX daily allowance - // // so we'd have a multiplier of 5000/6000 = 5/6, so they'd receive ~1666 & 3333 DHX respectively. - // // e.g. 2: if miner rewards are 2000 & 2000 DHX respectively, this is less than 5000 DHX daily allowance - // // so we'd just use a multiplier of 1, so they'd receive 2000 & 2000 DHX respectively. - // // https://docs.rs/fixed/0.5.4/fixed/struct.FixedU128.html - // let mut distribution_multiplier_for_day_fixed128 = FixedU128::from_num(1); // initialize - - // if rewards_aggregated_dhx_daily_as_u128.clone() > rewards_allowance_dhx_daily_u128.clone() { - // // Divide, handling overflow - - // // Note: If the rewards_allowance_dhx_daily_u128 is 5000 DHX, its 5000000000000000000000, - // // but we can't convert to u64 since largest value is 18446744073709551615. - // // Since we expect the rewards_aggregated_dhx_daily_as_u128 to be at least 1 DHX (i.e. 1000000000000000000), - // // we could just divide both numbers by 1000000000000000000, so we'd have say 5000 and 1 instead, - // // since we're just using these values to get a multiplier output. - - // let mut manageable_rewards_allowance_dhx_daily_u128 = 0u128; - // if let Some(_manageable_rewards_allowance_dhx_daily_u128) = - // rewards_allowance_dhx_daily_u128.clone().checked_div(1000000000000000000u128) { - // manageable_rewards_allowance_dhx_daily_u128 = _manageable_rewards_allowance_dhx_daily_u128; - // } else { - // log::error!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); - // return 0; - // } - - // let mut rewards_allowance_dhx_daily_u64 = 0u64; - // if let Some(_rewards_allowance_dhx_daily_u64) = - // TryInto::::try_into(manageable_rewards_allowance_dhx_daily_u128.clone()).ok() { - // rewards_allowance_dhx_daily_u64 = _rewards_allowance_dhx_daily_u64; - // } else { - // log::error!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); - // return 0; - // } - - // let mut manageable_rewards_aggregated_dhx_daily_as_u128 = 0u128; - // if let Some(_manageable_rewards_aggregated_dhx_daily_as_u128) = rewards_aggregated_dhx_daily_as_u128.clone().checked_div(1000000000000000000u128) { - // manageable_rewards_aggregated_dhx_daily_as_u128 = _manageable_rewards_aggregated_dhx_daily_as_u128; - // } else { - // log::error!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); - // return 0; - // } - - // let mut rewards_aggregated_dhx_daily_as_u64 = 0u64; - // if let Some(_rewards_aggregated_dhx_daily_as_u64) = - // TryInto::::try_into(manageable_rewards_aggregated_dhx_daily_as_u128.clone()).ok() { - // rewards_aggregated_dhx_daily_as_u64 = _rewards_aggregated_dhx_daily_as_u64; - // } else { - // log::error!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); - // return 0; - // } - - // // See https://github.com/ltfschoen/substrate-node-template/pull/6/commits/175ef4805d07093042431c5814dda52da1ebde18 - // let _fraction_distribution_multiplier_for_day_fixed128 = - // U64F64::from_num(manageable_rewards_allowance_dhx_daily_u128.clone()) - // .checked_div(U64F64::from_num(manageable_rewards_aggregated_dhx_daily_as_u128.clone())); - // let _distribution_multiplier_for_day_fixed128 = _fraction_distribution_multiplier_for_day_fixed128.clone(); - // match _distribution_multiplier_for_day_fixed128 { - // None => { - // log::error!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); - // return 0; - // }, - // Some(x) => { - // distribution_multiplier_for_day_fixed128 = x; - // } - // } - // } - // log::info!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); - // // println!("[multiplier] block: {:#?}, miner_count: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, miner_count, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); - - // // Initialise outside the loop as we need this value after the loop after we finish iterating through all the miners - // let mut rewards_allowance_dhx_remaining_today_as_u128 = 0u128; - - // miner_count = 0; - // for (index, miner_public_key) in reg_dhx_miners.iter().enumerate() { - // miner_count += 1; - // log::info!("rewards loop - miner_count {:#?}", miner_count); - // log::info!("rewards loop - miner_public_key {:#?}", miner_public_key); - - // // only run the following once per day per miner until rewards_allowance_dhx_for_date_remaining is exhausted - // // but since we're giving each registered miner a proportion of the daily reward allowance - // // (if their aggregated rewards is above daily allowance) each proportion is rounded down, - // // it shouldn't become exhausted anyway - // let is_already_distributed = >::get(start_of_requested_date_millis.clone()); - // if is_already_distributed == Some(true) { - // log::error!("Unable to distribute further rewards allowance today"); - // return 0; - // } - - // let daily_reward_for_miner_as_u128; - // let daily_reward_for_miner_to_try = >::get( - // ( - // start_of_requested_date_millis.clone(), - // miner_public_key.clone(), - // ), - // ); - // if let Some(_daily_reward_for_miner_to_try) = daily_reward_for_miner_to_try.clone() { - // let _daily_reward_for_miner_as_u128 = Self::convert_balance_to_u128(_daily_reward_for_miner_to_try.clone()); - // match _daily_reward_for_miner_as_u128.clone() { - // Err(_e) => { - // log::error!("Unable to convert balance to u128 for daily_reward_for_miner_as_u128"); - // return 0; - // }, - // Ok(x) => { - // daily_reward_for_miner_as_u128 = x; - // } - // } - // } else { - // // If any of the miner's don't have a reward, we won't waste storing that, - // // so we want to move to the next miner in the loop - // log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); - // continue; - // } - // log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); - - // let mut manageable_daily_reward_for_miner_as_u128 = 0u128; - // if let Some(_manageable_daily_reward_for_miner_as_u128) = - // daily_reward_for_miner_as_u128.clone().checked_div(1000000000000000000u128) { - // manageable_daily_reward_for_miner_as_u128 = _manageable_daily_reward_for_miner_as_u128; - // } else { - // log::error!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); - // return 0; - // } - - // // Multiply, handling overflow - // // TODO - probably have to initialise below proportion_of_daily_reward_for_miner_fixed128 to 0u128, - // // and convert distribution_multiplier_for_day_fixed128 to u64, - // // and convert daily_reward_for_miner_as_u128 to u64 too, like i did earlier. - // // but it works so this doesn't seem necessary. - // let proportion_of_daily_reward_for_miner_fixed128; - // let _proportion_of_daily_reward_for_miner_fixed128 = - // U64F64::from_num(distribution_multiplier_for_day_fixed128.clone()).checked_mul(U64F64::from_num(manageable_daily_reward_for_miner_as_u128.clone())); - // match _proportion_of_daily_reward_for_miner_fixed128 { - // None => { - // log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); - // return 0; - // }, - // Some(x) => { - // proportion_of_daily_reward_for_miner_fixed128 = x; - // } - // } - // log::info!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); - - // // round down to nearest integer. we need to round down, because if we round up then if there are - // // 3x registered miners with 5000 DHX rewards allowance per day then they would each get 1667 rewards, - // // but there would only be 1666 remaining after the first two, so the last one would miss out. - // // so if we round down they each get 1666 DHX and there is 2 DHX from the daily allocation that doesn't get distributed at all. - // let proportion_of_daily_reward_for_miner_u128: u128 = proportion_of_daily_reward_for_miner_fixed128.floor().to_num::(); - - // // we lose some accuracy doing this conversion, but at least we split the bulk of the rewards proportionally and fairly - // let mut restored_proportion_of_daily_reward_for_miner_u128 = 0u128; - // if let Some(_restored_proportion_of_daily_reward_for_miner_u128) = - // proportion_of_daily_reward_for_miner_u128.clone().checked_mul(1000000000000000000u128) { - // restored_proportion_of_daily_reward_for_miner_u128 = _restored_proportion_of_daily_reward_for_miner_u128; - // } else { - // log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); - // return 0; - // } - - // // println!("[rewards] block: {:#?}, miner_count: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); - - // let treasury_account_id: T::AccountId = >::account_id(); - // let max_payout = pallet_balances::Pallet::::usable_balance(treasury_account_id.clone()); - // log::info!("Treasury account id: {:?}", treasury_account_id.clone()); - // log::info!("Miner to receive reward: {:?}", miner_public_key.clone()); - // log::info!("Treasury balance max payout: {:?}", max_payout.clone()); - - // let proportion_of_daily_reward_for_miner; - // let _proportion_of_daily_reward_for_miner = Self::convert_u128_to_balance(restored_proportion_of_daily_reward_for_miner_u128.clone()); - // match _proportion_of_daily_reward_for_miner { - // Err(_e) => { - // log::error!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); - // return 0; - // }, - // Ok(ref x) => { - // proportion_of_daily_reward_for_miner = x; - // } - // } - - // let max_payout_as_u128; - // if let Some(_max_payout_as_u128) = TryInto::::try_into(max_payout).ok() { - // max_payout_as_u128 = _max_payout_as_u128; - // } else { - // log::error!("Unable to convert Balance to u128 for max_payout"); - // return 0; - // } - // log::info!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); - - // // Store output `rewards_allowance_dhx_remaining_today_as_u128` outside the loop - // // Validate inputs so the daily_rewards is less or equal to the existing_allowance - // if let Some(_rewards_allowance_dhx_remaining_today) = >::get(&start_of_requested_date_millis) { - // let _rewards_allowance_dhx_remaining_today_as_u128 = Self::convert_balance_to_u128(_rewards_allowance_dhx_remaining_today.clone()); - // match _rewards_allowance_dhx_remaining_today_as_u128.clone() { - // Err(_e) => { - // log::error!("Unable to convert balance to u128"); - // return 0; - // }, - // Ok(x) => { - // rewards_allowance_dhx_remaining_today_as_u128 = x; - // } - // } - // log::info!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); - // } else { - // log::error!("Unable to retrieve balance from value provided."); - // return 0; - // } - - // // println!("[prepared-for-payment] block: {:#?}, miner_count: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, miner_count, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); - - // // check if miner's reward is less than or equal to: rewards_allowance_dhx_daily_remaining - // if restored_proportion_of_daily_reward_for_miner_u128.clone() > 0u128 && - // rewards_allowance_dhx_remaining_today_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() && - // max_payout_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() - // { - // // pay the miner their daily reward - // info!("Paying the miner a proportion of the remaining daily reward allowance"); - - // let tx_result; - // let _tx_result = ::Currency::transfer( - // &treasury_account_id, - // &miner_public_key.clone(), - // proportion_of_daily_reward_for_miner.clone(), - // ExistenceRequirement::KeepAlive - // ); - // match _tx_result { - // Err(_e) => { - // log::error!("Unable to transfer from treasury to miner {:?}", miner_public_key.clone()); - // return 0; - // }, - // Ok(ref x) => { - // tx_result = x; - // } - // } - // info!("Transfer to the miner tx_result: {:?}", tx_result.clone()); - - // info!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); - - // // TODO - move into function `reduce_rewards_allowance_dhx_for_date_remaining`? - - // // Subtract, handling overflow - // let new_rewards_allowance_dhx_remaining_today_as_u128; - // let _new_rewards_allowance_dhx_remaining_today_as_u128 = - // rewards_allowance_dhx_remaining_today_as_u128.clone().checked_sub(restored_proportion_of_daily_reward_for_miner_u128.clone()); - // match _new_rewards_allowance_dhx_remaining_today_as_u128 { - // None => { - // log::error!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); - // return 0; - // }, - // Some(x) => { - // new_rewards_allowance_dhx_remaining_today_as_u128 = x; - // } - // } - - // let new_rewards_allowance_dhx_remaining_today; - // let _new_rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(new_rewards_allowance_dhx_remaining_today_as_u128.clone()); - // match _new_rewards_allowance_dhx_remaining_today { - // Err(_e) => { - // log::error!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); - // return 0; - // }, - // Ok(ref x) => { - // new_rewards_allowance_dhx_remaining_today = x; - // } - // } - - // // Write the new value to storage - // >::insert( - // start_of_requested_date_millis.clone(), - // new_rewards_allowance_dhx_remaining_today.clone(), - // ); - - // // println!("[paid] block: {:#?}, miner_count: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); - - // // emit event with reward payment history rather than bloating storage - // Self::deposit_event(Event::TransferredRewardsAllowanceDHXToMinerForDate( - // start_of_requested_date_millis.clone(), - // proportion_of_daily_reward_for_miner.clone(), - // new_rewards_allowance_dhx_remaining_today.clone(), - // miner_public_key.clone(), - // )); - - // log::info!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", - // start_of_requested_date_millis.clone(), - // proportion_of_daily_reward_for_miner.clone(), - // new_rewards_allowance_dhx_remaining_today.clone(), - // miner_public_key.clone(), - // ); - - // continue; - // } else { - // log::error!("Insufficient remaining rewards allowance to pay daily reward to miner"); - - // break; - // } - // } + let is_already_distributed_to_miner = >::get( + ( + start_of_requested_date_millis.clone(), + miner_public_key.clone(), + ) + ); + if is_already_distributed_to_miner == Some(true) { + log::error!("Unable to distribute further rewards allowance to the registered dhx miner for this day"); + return Err(DispatchError::Other("Unable to distribute further rewards allowance to the registered dhx miner for this day")); + } - // let rewards_allowance_dhx_remaining_today; - // let _rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(rewards_allowance_dhx_remaining_today_as_u128.clone()); - // match _rewards_allowance_dhx_remaining_today { - // Err(_e) => { - // log::error!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); - // return 0; - // }, - // Ok(ref x) => { - // rewards_allowance_dhx_remaining_today = x; - // } - // } + let daily_reward_for_miner_as_u128; + let daily_reward_for_miner_to_try = >::get( + ( + start_of_requested_date_millis.clone(), + miner_public_key.clone(), + ), + ); + if let Some(_daily_reward_for_miner_to_try) = daily_reward_for_miner_to_try.clone() { + let _daily_reward_for_miner_as_u128 = Self::convert_balance_to_u128(_daily_reward_for_miner_to_try.clone()); + match _daily_reward_for_miner_as_u128.clone() { + Err(_e) => { + log::error!("Unable to convert balance to u128 for daily_reward_for_miner_as_u128"); + return Err(DispatchError::Other("Unable to convert balance to u128 for daily_reward_for_miner_as_u128")); + }, + Ok(x) => { + daily_reward_for_miner_as_u128 = x; + } + } + } else { + // If any of the miner's don't have a reward, we won't waste storing that, + // so we want to move to the next miner in the loop + log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); + return Err(DispatchError::Other("Unable to retrieve reward balance for daily_reward_for_miner")); + } + log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); + + let mut manageable_daily_reward_for_miner_as_u128 = 0u128; + if let Some(_manageable_daily_reward_for_miner_as_u128) = + daily_reward_for_miner_as_u128.clone().checked_div(1000000000000000000u128) { + manageable_daily_reward_for_miner_as_u128 = _manageable_daily_reward_for_miner_as_u128; + } else { + log::error!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); + return Err(DispatchError::Other("Unable to divide daily_reward_for_miner_as_u128 to make it smaller")); + } + + // Multiply, handling overflow + // TODO - probably have to initialise below proportion_of_daily_reward_for_miner_fixed128 to 0u128, + // and convert distribution_multiplier_for_day_fixed128 to u64, + // and convert daily_reward_for_miner_as_u128 to u64 too, like i did earlier. + // but it works so this doesn't seem necessary. + let proportion_of_daily_reward_for_miner_fixed128; + let _proportion_of_daily_reward_for_miner_fixed128 = + U64F64::from_num(distribution_multiplier_for_day_fixed128.clone()).checked_mul(U64F64::from_num(manageable_daily_reward_for_miner_as_u128.clone())); + match _proportion_of_daily_reward_for_miner_fixed128 { + None => { + log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); + return Err(DispatchError::Other("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow")); + }, + Some(x) => { + proportion_of_daily_reward_for_miner_fixed128 = x; + } + } + log::info!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); + + // round down to nearest integer. we need to round down, because if we round up then if there are + // 3x registered miners with 5000 DHX rewards allowance per day then they would each get 1667 rewards, + // but there would only be 1666 remaining after the first two, so the last one would miss out. + // so if we round down they each get 1666 DHX and there is 2 DHX from the daily allocation that doesn't get distributed at all. + let proportion_of_daily_reward_for_miner_u128: u128 = proportion_of_daily_reward_for_miner_fixed128.floor().to_num::(); + + // we lose some accuracy doing this conversion, but at least we split the bulk of the rewards proportionally and fairly + let mut restored_proportion_of_daily_reward_for_miner_u128 = 0u128; + if let Some(_restored_proportion_of_daily_reward_for_miner_u128) = + proportion_of_daily_reward_for_miner_u128.clone().checked_mul(1000000000000000000u128) { + restored_proportion_of_daily_reward_for_miner_u128 = _restored_proportion_of_daily_reward_for_miner_u128; + } else { + log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); + return Err(DispatchError::Other("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again")); + } + + // println!("[rewards] block: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); + + let treasury_account_id: T::AccountId = >::account_id(); + let max_payout = pallet_balances::Pallet::::usable_balance(treasury_account_id.clone()); + log::info!("Treasury account id: {:?}", treasury_account_id.clone()); + log::info!("Miner to receive reward: {:?}", miner_public_key.clone()); + log::info!("Treasury balance max payout: {:?}", max_payout.clone()); + + let proportion_of_daily_reward_for_miner; + let _proportion_of_daily_reward_for_miner = Self::convert_u128_to_balance(restored_proportion_of_daily_reward_for_miner_u128.clone()); + match _proportion_of_daily_reward_for_miner { + Err(_e) => { + log::error!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); + return Err(DispatchError::Other("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner")); + }, + Ok(ref x) => { + proportion_of_daily_reward_for_miner = x; + } + } + + let max_payout_as_u128; + if let Some(_max_payout_as_u128) = TryInto::::try_into(max_payout).ok() { + max_payout_as_u128 = _max_payout_as_u128; + } else { + log::error!("Unable to convert Balance to u128 for max_payout"); + return Err(DispatchError::Other("Unable to convert Balance to u128 for max_payout")); + } + log::info!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); + + // TODO - rename `rewards_allowance_dhx_remaining_today` to + // `rewards_allowance_dhx_remaining_for_date_rewards_being_claimed` + + // Store output `rewards_allowance_dhx_remaining_today_as_u128` outside the loop + // Validate inputs so the daily_rewards is less or equal to the existing_allowance + if let Some(_rewards_allowance_dhx_remaining_today) = >::get(&start_of_requested_date_millis) { + let _rewards_allowance_dhx_remaining_today_as_u128 = Self::convert_balance_to_u128(_rewards_allowance_dhx_remaining_today.clone()); + match _rewards_allowance_dhx_remaining_today_as_u128.clone() { + Err(_e) => { + log::error!("Unable to convert balance to u128"); + return Err(DispatchError::Other("Unable to convert balance to u128")); + }, + Ok(x) => { + rewards_allowance_dhx_remaining_today_as_u128 = x; + } + } + log::info!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); + } else { + log::error!("Unable to retrieve balance from value provided."); + return Err(DispatchError::Other("Unable to retrieve balance from value provided.")); + } + + // println!("[prepared-for-payment] block: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); + + // check if miner's reward is less than or equal to: rewards_allowance_dhx_daily_remaining + if restored_proportion_of_daily_reward_for_miner_u128.clone() > 0u128 && + rewards_allowance_dhx_remaining_today_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() && + max_payout_as_u128.clone() >= restored_proportion_of_daily_reward_for_miner_u128.clone() + { + // pay the miner their daily reward + info!("Paying the miner a proportion of the remaining daily reward allowance"); + + let tx_result; + let _tx_result = ::Currency::transfer( + &treasury_account_id, + &_sender.clone(), + proportion_of_daily_reward_for_miner.clone(), + ExistenceRequirement::KeepAlive + ); + match _tx_result { + Err(_e) => { + log::error!("Unable to transfer from treasury to miner {:?}", miner_public_key.clone()); + return Err(DispatchError::Other("Unable to transfer from treasury to miner")); + }, + Ok(ref x) => { + tx_result = x; + } + } + info!("Transfer to the miner tx_result: {:?}", tx_result.clone()); + + info!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); + // TODO - move into function `reduce_rewards_allowance_dhx_for_date_remaining`? + + // Subtract, handling overflow + let new_rewards_allowance_dhx_remaining_today_as_u128; + let _new_rewards_allowance_dhx_remaining_today_as_u128 = + rewards_allowance_dhx_remaining_today_as_u128.clone().checked_sub(restored_proportion_of_daily_reward_for_miner_u128.clone()); + match _new_rewards_allowance_dhx_remaining_today_as_u128 { + None => { + log::error!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); + return Err(DispatchError::Other("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow")); + }, + Some(x) => { + new_rewards_allowance_dhx_remaining_today_as_u128 = x; + } + } + + let new_rewards_allowance_dhx_remaining_today; + let _new_rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(new_rewards_allowance_dhx_remaining_today_as_u128.clone()); + match _new_rewards_allowance_dhx_remaining_today { + Err(_e) => { + log::error!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); + return Err(DispatchError::Other("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today")); + }, + Ok(ref x) => { + new_rewards_allowance_dhx_remaining_today = x; + } + } + + // Write the new value to storage + >::insert( + start_of_requested_date_millis.clone(), + new_rewards_allowance_dhx_remaining_today.clone(), + ); + + // println!("[paid] block: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); + + >::insert( + ( + start_of_requested_date_millis.clone(), + miner_public_key.clone(), + ), + true, + ); + + // emit event with reward payment history rather than bloating storage + Self::deposit_event(Event::TransferredRewardsAllowanceDHXToMinerForDate( + start_of_requested_date_millis.clone(), + proportion_of_daily_reward_for_miner.clone(), + new_rewards_allowance_dhx_remaining_today.clone(), + miner_public_key.clone(), + )); + + log::info!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", + start_of_requested_date_millis.clone(), + proportion_of_daily_reward_for_miner.clone(), + new_rewards_allowance_dhx_remaining_today.clone(), + miner_public_key.clone(), + ); + } else { + log::error!("Insufficient remaining rewards allowance to pay daily reward to miner"); + return Err(DispatchError::Other("Insufficient remaining rewards allowance to pay daily reward to miner")); + } + + let rewards_allowance_dhx_remaining_today; + let _rewards_allowance_dhx_remaining_today = Self::convert_u128_to_balance(rewards_allowance_dhx_remaining_today_as_u128.clone()); + match _rewards_allowance_dhx_remaining_today { + Err(_e) => { + log::error!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); + return Err(DispatchError::Other("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today")); + }, + Ok(ref x) => { + rewards_allowance_dhx_remaining_today = x; + } + } + + // println!("[distributed] block: {:#?}, date_start: {:#?} ", block_number, start_of_requested_date_millis); + + Self::deposit_event(Event::DistributedRewardsAllowanceDHXForDateRemaining( + start_of_requested_date_millis.clone(), + rewards_allowance_dhx_remaining_today.clone(), + )); + + // FIXME - previously when we distributed all rewards for a given date + // we used `RewardsAllowanceDHXForDateRemainingDistributed` to record whether all the rewards for + // that date had been distributed. + // + // but now registered_dhx_miners claim their rewards for a given date + + // we should only run `RewardsAllowanceDHXForDateRemainingDistributed` after all + // the registered_dhx_miners that were stored under + // a given date as the key for RewardsAccumulatedDHXForMinerForDate have been flagged as having been paid. + // so since there may be some leftover rewards that don't get distributed for a given day due to rounding, + // we can't say its all distributed when `rewards_allowance_dhx_remaining_today` is 0. + // we now have a StorageMap RewardsAllowanceDHXForMinerForDateRemainingDistributed, that uses the same + // date and miner_public_key as the key, and stores a flag of whether they have been paid for that date + // already as a value, so they can't claim more than once for the same day + + // TODO - we won't use this yet. we could use it but we'll need to use `RewardsEligibleMinersForDate`, + // which is where we store the registered_dhx_miners that are deemed eligible for rewards on a given date, + // and also record which of those registered miners we've already distributed rewards to + // using `RewardsAllowanceDHXForMinerForDateRemainingDistributed` and when there are 0 left to distribute to, + // then we'd run this, but it doesn't seem that important to know // >::insert( // start_of_requested_date_millis.clone(), // true // ); - // // println!("[distributed] block: {:#?}, miner_count: {:#?}, date_start: {:#?} ", block_number, miner_count, start_of_requested_date_millis); - - // Self::deposit_event(Event::DistributedRewardsAllowanceDHXForDateRemaining( - // start_of_requested_date_millis.clone(), - // rewards_allowance_dhx_remaining_today.clone(), - // )); - - // return 0; - + // Return a successful DispatchResultWithPostInfo + Ok(()) } // Off-chain workers diff --git a/pallets/mining/rewards-allowance/src/mock.rs b/pallets/mining/rewards-allowance/src/mock.rs index 2fd42384e..da0ccd486 100644 --- a/pallets/mining/rewards-allowance/src/mock.rs +++ b/pallets/mining/rewards-allowance/src/mock.rs @@ -528,6 +528,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { rewards_allowance_dhx_daily: FIVE_THOUSAND_DHX, // 5000 DHX rewards_allowance_dhx_for_date_remaining: Default::default(), rewards_allowance_dhx_for_date_remaining_distributed: Default::default(), + rewards_allowance_dhx_for_miner_for_date_remaining_distributed: Default::default(), rewards_multiplier_paused: false, rewards_multiplier_reset: false, rewards_multiplier_default_change: 10u32, @@ -545,6 +546,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // get_account_id_from_seed::("Charlie"), // ], registered_dhx_miners: Default::default(), + rewards_eligible_miners_for_date: Default::default(), rewards_aggregated_dhx_for_all_miners_for_date: Default::default(), rewards_accumulated_dhx_for_miner_for_date: Default::default(), min_bonded_dhx_daily: TEN_DHX, // 10 DHX From 28e69554d22d297c56deda4a4d36af2f3f1e9a3f Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 2 Dec 2021 08:27:45 +0100 Subject: [PATCH 24/37] fix --- pallets/mining/rewards-allowance/src/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 2426193d0..240a8d799 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -483,7 +483,7 @@ pub mod pallet { pub rewards_aggregated_dhx_for_all_miners_for_date: Vec<(Date, BalanceOf)>, pub rewards_accumulated_dhx_for_miner_for_date: Vec<((Date, Vec), BalanceOf)>, pub registered_dhx_miners: Vec>, - pub rewards_eligible_miners_for_date: Vec>>, + pub rewards_eligible_miners_for_date: Vec<(Date, Vec>)>, pub min_bonded_dhx_daily: BalanceOf, pub min_bonded_dhx_daily_default: BalanceOf, pub min_mpower_daily: u128, @@ -1591,8 +1591,11 @@ pub mod pallet { return; } - let new_rewards_eligible_miners_for_date = rewards_eligible_miners_for_date.push(miner_public_key.clone()); - >::insert(start_of_requested_date_millis.clone(), new_rewards_eligible_miners_for_date.clone()); + rewards_eligible_miners_for_date.push(miner_public_key.clone()); + >::insert( + start_of_requested_date_millis.clone(), + rewards_eligible_miners_for_date.clone(), + ); // println!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); // if last miner being iterated then reset for next day From d4280c85aa4a7e1fe9346078c0fca87892a09491 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 2 Dec 2021 21:00:14 +0100 Subject: [PATCH 25/37] wip --- pallets/mining/rewards-allowance/src/lib.rs | 378 ++++++++++++++---- pallets/mining/rewards-allowance/src/tests.rs | 3 +- 2 files changed, 303 insertions(+), 78 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 240a8d799..91a7f63b1 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -245,6 +245,14 @@ pub mod pallet { pub received_at_block_number: X, } + #[cfg_attr(feature = "std", derive(Debug))] + #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)] + pub struct FetchedMPowerForAccountsForDatePayload { + pub start_of_requested_date_millis: U, + pub all_miner_public_keys_fetched: V, + pub total_mpower_fetched: W, + } + type MPowerPayloadData = MPowerPayload< Vec, // ::AccountId, u128, @@ -252,6 +260,12 @@ pub mod pallet { ::BlockNumber, >; + type FetchedMPowerForAccountsForDatePayloadData = FetchedMPowerForAccountsForDatePayload< + Date, + Vec>, + u128, + >; + // type MPowerAccountDataType = MPowerAccountData< // ::AccountId, // u128, @@ -454,6 +468,17 @@ pub mod pallet { u128, // mPower >; + /// Recently submitted finished fetching mPower data. + #[pallet::storage] + #[pallet::getter(fn finished_fetching_mpower_for_accounts_for_date)] + pub(super) type FinishedFetchingMPowerForAccountsForDate = StorageMap<_, Blake2_128Concat, + Date, // converted to start of date + ( + Vec>, + u128, // mPower + ), + >; + /// Defines the block when next unsigned transaction will be accepted. /// /// To prevent spam of unsigned (and unpayed!) transactions on the network, @@ -679,6 +704,10 @@ pub mod pallet { /// Event generated when new mPower data is accepted to contribute to the rewards allowance. /// \[start_date_requested, registered_dhx_miner_account_id, mpower\] NewMPowerForAccountForDate(Date, Vec, u128), + + /// Event generated when new finished fetching mPower data is stored. + /// \[start_date_requested, all_miner_public_keys_fetched, total_mpower_fetched\] + NewFinishedFetchingMPowerForAccountsForDate(Date, Vec>, u128), } // Errors inform users that something went wrong should be descriptive and have helpful documentation @@ -705,6 +734,16 @@ pub mod pallet { /// be cases where some blocks are skipped, or for some the worker runs twice (re-orgs), /// so the code should be able to handle that. /// You can use `Local Storage` API to coordinate runs of the worker. + /// + /// https://paritytech.github.io/substrate/master/frame_support/traits/trait.OffchainWorker.html + /// https://paritytech.github.io/substrate/master/frame_support/traits/trait.Hooks.html + /// + /// Implementing this trait on a module allows you to perform long-running tasks that make + /// (by default) validators generate transactions that feed results of those long-running + /// computations back on chain. + /// NOTE: This function runs off-chain, so it can access the block state, but cannot preform + /// any alterations. More specifically alterations are not forbidden, but they are not persisted + /// in any way after the worker has finished. fn offchain_worker(block_number: T::BlockNumber) { // Note that having logs compiled to WASM may cause the size of the blob to increase // significantly. You can use `RuntimeDebug` custom derive to hide details of the types @@ -728,6 +767,9 @@ pub mod pallet { return; } + // TODO - this timestamp section is duplicated in the on_initialize function, + // so move it into its owh private function + // Anything that needs to be done at the start of the block. let timestamp: ::Moment = >::get(); log::info!("block_number: {:?}", block_number.clone()); @@ -766,6 +808,121 @@ pub mod pallet { log::info!("start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); // println!("start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); + // TODO - fetch the mpower from off-chain and store it with `set_mpower_of_account_for_date` + // but only for the reg_dhx_miners + // so we can iterate through the miners and retrieve the mPower of each miner for the current date with + // `MPowerForAccountForDate` + // and check if mPower for current miner being iterated is greather than the min. mPower that is required. + + // after fetching the mpower values store by sending an unsigned transactions + let should_send = Self::choose_transaction_type(block_number.clone()); + let mut res; + let mut mpower_data_vec = vec![]; + match should_send { + TransactionType::Raw => { + let _mpower_res = Self::fetch_mpower_process(block_number.clone(), start_of_requested_date_millis.clone()); + match _mpower_res.clone() { + Err(e) => { + log::error!("offchain_workers error fetching mpower: {}", e); + return; + }, + Ok(x) => { + mpower_data_vec = x; + } + } + }, + TransactionType::None => { + log::error!("offchain_workers error unknown transaction type"); + return; + }, + }; + + // TODO - remove all the fetched accounts from vector that aren't in the list of + // reg_dhx_miners, since we add the list of registered dhx miners from a signed account to + // and use it incase the API endpoint is compromised by hackers and fake accounts and mpower data are provided + + // TODO - change reg_dhx_miners functionality so it may be stored via an extrinsic function + // and voted on by governance, and so it just includes a list of account addresses that we check against. + // if the list needs to be changed then just call it and add all of them again once approved. + + res = Self::store_mpower_raw_unsigned(block_number.clone(), start_of_requested_date_millis.clone(), mpower_data_vec.clone()); + if let Err(e) = res { + log::error!("offchain_workers error storing mpower: {}", e); + } + + let mut all_miner_public_keys_fetched = vec![]; + let mut total_mpower_fetched = 0u128; + for (index, mpower_data_item) in mpower_data_vec.iter().enumerate() { + all_miner_public_keys_fetched.push(mpower_data_item.account_id_registered_dhx_miner.clone()); + total_mpower_fetched.checked_add(mpower_data_item.mpower_registered_dhx_miner.clone()); + } + + let fetched_mpower_data: FetchedMPowerForAccountsForDatePayloadData = FetchedMPowerForAccountsForDatePayload { + start_of_requested_date_millis: start_of_requested_date_millis.clone(), + all_miner_public_keys_fetched: all_miner_public_keys_fetched.clone(), + total_mpower_fetched: total_mpower_fetched.clone(), + }; + + res = Self::store_finished_fetching_mpower_raw_unsigned( + block_number.clone(), + fetched_mpower_data.clone() + ); + if let Err(e) = res { + log::error!("offchain_workers error storing finished fetching mpower: {}", e); + } + + return; + } + + // `on_initialize` is executed at the beginning of the block before any extrinsic are + // dispatched. + // + // This function must return the weight consumed by `on_initialize` and `on_finalize`. + // TODO - update with the weight consumed + fn on_initialize(block_number: T::BlockNumber) -> Weight { + let should_process_block = Self::should_process_block(block_number.clone()); + if should_process_block == true { + return 0; + } + + // Anything that needs to be done at the start of the block. + let timestamp: ::Moment = >::get(); + log::info!("block_number: {:?}", block_number.clone()); + log::info!("timestamp: {:?}", timestamp.clone()); + let requested_date_as_u64; + let _requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()); + match _requested_date_as_u64 { + Err(_e) => { + log::error!("Unable to convert Moment to u64 in millis for timestamp"); + return 0; + }, + Ok(ref x) => { + requested_date_as_u64 = x; + } + } + log::info!("requested_date_as_u64: {:?}", requested_date_as_u64.clone()); + // println!("requested_date_as_u64: {:?}", requested_date_as_u64.clone()); + + // do not run when block number is 1, which is when timestamp is 0 because this + // timestamp corresponds to 1970-01-01 + if requested_date_as_u64.clone() == 0u64 { + return 0; + } + + let start_of_requested_date_millis; + let _start_of_requested_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(requested_date_as_u64.clone()); + match _start_of_requested_date_millis { + Err(_e) => { + log::error!("Unable to convert u64 in milliseconds to start_of_requested_date_millis"); + return 0; + }, + Ok(ref x) => { + start_of_requested_date_millis = x; + } + } + log::info!("start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); + // println!("start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); + // https://substrate.dev/rustdocs/latest/frame_support/storage/trait.StorageMap.html let contains_key = >::contains_key(&start_of_requested_date_millis); log::info!("contains_key for date: {:?}, {:?}", start_of_requested_date_millis.clone(), contains_key.clone()); @@ -778,7 +935,7 @@ pub mod pallet { rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; } else { log::error!("Unable to get rewards_allowance_dhx_daily"); - return; + return 0; } // Update storage. Use RewardsAllowanceDHXDaily as fallback incase not previously set prior to block @@ -843,7 +1000,7 @@ pub mod pallet { match _min_bonded_dhx_daily_default { Err(_e) => { log::error!("Unable to retrieve any min. bonded DHX daily default as BalanceOf and u128"); - return; + return 0; }, Ok(ref x) => { min_bonded_dhx_daily_default = x.0; @@ -940,7 +1097,7 @@ pub mod pallet { match _new_rm_current_period_days_remaining { None => { log::error!("Unable to subtract one from rm_current_period_days_remaining due to StorageOverflow"); - return; + return 0; }, Some(x) => { new_rm_current_period_days_remaining = x; @@ -970,7 +1127,7 @@ pub mod pallet { match _min_bonded_dhx_daily { Err(_e) => { log::error!("Unable to retrieve any min. bonded DHX daily as BalanceOf and u128"); - return; + return 0; }, Ok(ref x) => { min_bonded_dhx_daily = x.0; @@ -984,7 +1141,7 @@ pub mod pallet { rewards_multipler_operation = _rewards_multipler_operation; } else { log::error!("Unable to retrieve rewards_multipler_operation"); - return; + return 0; } let mut new_min_bonded_dhx_daily_u128 = 0u128; // initialize @@ -998,7 +1155,7 @@ pub mod pallet { rm_next_change_u128_short = _rm_next_change_u128_short; } else { log::error!("Unable to convert u32 to u128"); - return; + return 0; } let ONE = 1000000000000000000u128; @@ -1008,7 +1165,7 @@ pub mod pallet { match _rm_next_change_as_fixedu128 { None => { log::error!("Unable to mult rm_next_change by ONE due to StorageOverflow"); - return; + return 0; }, Some(x) => { rm_next_change_as_fixedu128 = x; @@ -1031,7 +1188,7 @@ pub mod pallet { match _new_min_bonded_dhx_daily_u128 { None => { log::error!("Unable to add min_bonded_dhx_daily_u128 with rm_next_change_u128 due to StorageOverflow"); - return; + return 0; }, Some(x) => { new_min_bonded_dhx_daily_u128 = x; @@ -1039,7 +1196,7 @@ pub mod pallet { } } else { log::error!("Unsupported rewards_multipler_operation value"); - return; + return 0; } // println!("new_min_bonded_dhx_daily_u128 {:?}", new_min_bonded_dhx_daily_u128); @@ -1049,7 +1206,7 @@ pub mod pallet { match _new_min_bonded_dhx_daily { Err(_e) => { log::error!("Unable to convert u128 to balance for new_min_bonded_dhx_daily"); - return; + return 0; }, Ok(ref x) => { new_min_bonded_dhx_daily = x; @@ -1101,7 +1258,7 @@ pub mod pallet { match _new_min_bonded_dhx_daily { Err(_e) => { log::error!("Unable to convert u128 to balance for new_min_bonded_dhx_daily"); - return; + return 0; }, Ok(ref x) => { new_min_bonded_dhx_daily = x; @@ -1120,54 +1277,30 @@ pub mod pallet { reg_dhx_miners = _reg_dhx_miners; } else { log::error!("Unable to retrieve any registered DHX Miners"); - return; + return 0; } if reg_dhx_miners.len() == 0 { log::error!("Registered DHX Miners has no elements"); - return; + return 0; }; - // TODO - fetch the mpower from off-chain and store it with `set_mpower_of_account_for_date` - // but only for the reg_dhx_miners - // so we can iterate through the miners and retrieve the mPower of each miner for the current date with - // `MPowerForAccountForDate` - // and check if mPower for current miner being iterated is greather than the min. mPower that is required. - - // after fetching the mpower values store by sending an unsigned transactions - let should_send = Self::choose_transaction_type(block_number.clone()); - let mut res; - let mut mpower_data_vec = vec![]; - match should_send { - TransactionType::Raw => { - let _mpower_res = Self::fetch_mpower_process(block_number.clone(), start_of_requested_date_millis.clone()); - match _mpower_res.clone() { - Err(e) => { - log::error!("offchain_workers error fetching mpower: {}", e); - return; - }, - Ok(x) => { - mpower_data_vec = x; - } - } - }, - TransactionType::None => { - log::error!("offchain_workers error unknown transaction type"); - return; - }, - }; + // TODO - uncomment this - // TODO - remove all the fetched accounts from vector that aren't in the list of - // reg_dhx_miners, since we add the list of registered dhx miners from a signed account to - // and use it incase the API endpoint is compromised by hackers and fake accounts and mpower data are provided + // // only continue with aggregating and accumulating rewards and using mPower data that + // // was fetched offchain when the unsigned tx + // // from offchain_workers that indicates we have finished fetching mpower data for the + // // day has been finished + // let data_finished_fetching_for_date = + // >::get(start_of_requested_date_millis.clone()); - // TODO - change reg_dhx_miners functionality so it may be stored via an extrinsic function - // and voted on by governance, and so it just includes a list of account addresses that we check against. - // if the list needs to be changed then just call it and add all of them again once approved. - - res = Self::store_mpower_raw_unsigned(block_number.clone(), start_of_requested_date_millis.clone(), mpower_data_vec.clone()); - if let Err(e) = res { - log::error!("offchain_workers error storing mpower: {}", e); - } + // match data_finished_fetching_for_date { + // None => { + // log::warn!("Skipping this block as we have not yet finished fetching mpower data for today from offchain workers {:?}", start_of_requested_date_millis.clone()); + // return 0; + // }, + // Some(x) => { + // } + // } let mut miner_count = 0; @@ -1207,7 +1340,7 @@ pub mod pallet { match _miner_account_id.clone() { Err(_e) => { log::error!("Unable to decode miner_public_key"); - return; + return 0; }, Ok(x) => { miner_account_id = x; @@ -1224,7 +1357,7 @@ pub mod pallet { match _locks_first_amount_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128"); - return; + return 0; }, Ok(x) => { locks_first_amount_as_u128 = x; @@ -1263,7 +1396,7 @@ pub mod pallet { match _bonded_dhx_current_u128 { Err(_e) => { log::error!("Unable to set_bonded_dhx_of_account_for_date"); - return; + return 0; }, Ok(ref x) => { bonded_dhx_current_u128 = x; @@ -1276,7 +1409,7 @@ pub mod pallet { match _min_bonded_dhx_daily { Err(_e) => { log::error!("Unable to retrieve any min. bonded DHX daily as BalanceOf and u128"); - return; + return 0; }, Ok(ref x) => { min_bonded_dhx_daily = x.0; @@ -1305,6 +1438,15 @@ pub mod pallet { // mPower that is required let mut mpower_current_u128: u128 = 0u128; let _mpower_current_u128 = >::get((start_of_requested_date_millis.clone(), miner_public_key.clone())); + match _mpower_current_u128 { + None => { + log::error!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); + // println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); + }, + Some(x) => { + mpower_current_u128 = x; + } + } // // FIXME - this is temporary // let _mpower_data = ( // Some(0u128), @@ -1342,7 +1484,7 @@ pub mod pallet { cooling_off_period_days = _cooling_off_period_days; } else { log::error!("Unable to retrieve cooling off period days"); - return; + return 0; } let mut cooling_off_period_days_remaining = ( @@ -1406,7 +1548,7 @@ pub mod pallet { match _new_cooling_off_period_days_remaining { None => { log::error!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); - return; + return 0; }, Some(x) => { new_cooling_off_period_days_remaining = x; @@ -1480,7 +1622,7 @@ pub mod pallet { match _daily_reward_for_miner_as_u128 { None => { log::error!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); - return; + return 0; }, Some(x) => { daily_reward_for_miner_as_u128 = x; @@ -1506,7 +1648,7 @@ pub mod pallet { match _daily_reward_for_miner { Err(_e) => { log::error!("Unable to convert u128 to balance for daily_reward_for_miner"); - return; + return 0; }, Ok(ref x) => { daily_reward_for_miner = x; @@ -1526,7 +1668,7 @@ pub mod pallet { match _rewards_aggregated_dhx_daily_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); - return; + return 0; }, Ok(x) => { rewards_aggregated_dhx_daily_as_u128 = x; @@ -1540,7 +1682,7 @@ pub mod pallet { match _new_rewards_aggregated_dhx_daily_as_u128 { None => { log::error!("Unable to add daily_reward_for_miner to rewards_aggregated_dhx_daily due to StorageOverflow"); - return; + return 0; }, Some(x) => { new_rewards_aggregated_dhx_daily_as_u128 = x; @@ -1555,7 +1697,7 @@ pub mod pallet { match _new_rewards_aggregated_dhx_daily { Err(_e) => { log::error!("Unable to convert u128 to balance for new_rewards_aggregated_dhx_daily"); - return; + return 0; }, Ok(ref x) => { new_rewards_aggregated_dhx_daily = x; @@ -1588,7 +1730,7 @@ pub mod pallet { rewards_eligible_miners_for_date = _rewards_eligible_miners_for_date; } else { log::error!("Unable to retrieve rewards_eligible_miners_for_date"); - return; + return 0; } rewards_eligible_miners_for_date.push(miner_public_key.clone()); @@ -1656,7 +1798,7 @@ pub mod pallet { match _new_cooling_off_period_days_remaining { None => { log::error!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); - return; + return 0; }, Some(x) => { new_cooling_off_period_days_remaining = x; @@ -1704,18 +1846,6 @@ pub mod pallet { log::info!("Finished initial loop of registered miners"); // println!("Finished initial loop of registered miners"); - } - - // `on_initialize` is executed at the beginning of the block before any extrinsic are - // dispatched. - // - // This function must return the weight consumed by `on_initialize` and `on_finalize`. - // TODO - update with the weight consumed - fn on_initialize(block_number: T::BlockNumber) -> Weight { - let should_process_block = Self::should_process_block(block_number.clone()); - if should_process_block == true { - return 0; - } return 0; } @@ -1991,6 +2121,8 @@ pub mod pallet { Ok(()) } + // TODO - add change_finished_fetching_mpower_for_accounts_for_date + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] pub fn claim_rewards_of_account_for_date(origin: OriginFor, start_of_requested_date_millis: Date) -> DispatchResult { let _sender = ensure_signed(origin)?; @@ -2491,6 +2623,22 @@ pub mod pallet { >::put(current_block + T::UnsignedInterval::get()); Ok(().into()) } + + #[pallet::weight(0)] + pub fn submit_finished_fetching_mpower_unsigned( + origin: OriginFor, + _block_number: T::BlockNumber, + fetched_mpower_data: FetchedMPowerForAccountsForDatePayloadData, + ) -> DispatchResultWithPostInfo { + // This ensures that the function can only be called via unsigned transaction. + ensure_none(origin)?; + // Add the data on-chain, but mark it as coming from an empty address. + Self::add_finished_fetching_mpower(Default::default(), fetched_mpower_data.clone()); + // now increment the block number at which we expect next unsigned transaction. + let current_block = >::block_number(); + >::put(current_block + T::UnsignedInterval::get()); + Ok(().into()) + } } #[pallet::validate_unsigned] @@ -2792,6 +2940,47 @@ pub mod pallet { Ok(mpower_current_u128.clone()) } + pub fn set_finished_fetching_mpower_for_accounts_for_date(all_miner_public_keys_fetched: Vec>, start_of_requested_date_millis: Date, total_mpower_fetched: u128) -> Result { + + // check if the new total_mpower_fetched value differs from the value that is already in storage + // for the given key, and only insert if it is different + let data_finished_fetching_for_date = >::get(start_of_requested_date_millis.clone()); + + match data_finished_fetching_for_date { + None => { + }, + Some(x) => { + log::warn!("Existing storage value of finished fetching for date of data retrieved from API"); + return Err(DispatchError::Other("Existing storage value of finished fetching for date of data retrieved from API")); + } + } + + // Update storage. Override the default that may have been set in on_initialize + >::insert( + start_of_requested_date_millis.clone(), + ( + all_miner_public_keys_fetched.clone(), + total_mpower_fetched.clone(), + ) + ); + + log::info!("Added FinishedFetchingMPowerForAccountsForDate {:?} {:?} {:?}", + start_of_requested_date_millis.clone(), + all_miner_public_keys_fetched.clone(), + total_mpower_fetched.clone(), + ); + + // Emit an event. + Self::deposit_event(Event::NewFinishedFetchingMPowerForAccountsForDate( + start_of_requested_date_millis.clone(), + all_miner_public_keys_fetched.clone(), + total_mpower_fetched.clone(), + )); + + // Return a successful DispatchResultWithPostInfo + Ok(total_mpower_fetched.clone()) + } + fn get_min_bonded_dhx_daily() -> Result<(BalanceOf, u128), DispatchError> { let mut min_bonded_dhx_daily: BalanceOf = 10u32.into(); // initialize let mut min_bonded_dhx_daily_u128: u128 = TEN; @@ -2982,6 +3171,27 @@ pub mod pallet { Ok(()) } + /// A helper function to send a raw unsigned transaction to store finished fetching mpower data for use in on_initialize + fn store_finished_fetching_mpower_raw_unsigned(block_number: T::BlockNumber, fetched_mpower_data: FetchedMPowerForAccountsForDatePayloadData) -> Result<(), &'static str> { + // Received mpower data is wrapped into a call to `submit_finished_fetching_mpower_unsigned` public function of this + // pallet. This means that the transaction, when executed, will simply call that function + // passing `fetched_mpower_data` as an argument. + let call = Call::submit_finished_fetching_mpower_unsigned(block_number.clone(), fetched_mpower_data.clone()); + + // Now let's create a transaction out of this call and submit it to the pool. + // Here we showcase two ways to send an unsigned transaction / unsigned payload (raw) + // + // TODO - By default unsigned transactions are disallowed, so we need to whitelist this case + // by writing `UnsignedValidator`. Note that it's EXTREMELY important to carefuly + // implement unsigned validation logic, as any mistakes can lead to opening DoS or spam + // attack vectors. See validation logic docs for more details. + // + SubmitTransaction::>::submit_unsigned_transaction(call.into()) + .map_err(|()| "Unable to submit unsigned transaction.")?; + + Ok(()) + } + /// Fetch current mPower and return the result. fn fetch_mpower(block_number: T::BlockNumber, start_of_requested_date_millis: Date) -> Result>, http::Error> { // We want to keep the offchain worker execution time reasonable, so we set a hard-coded @@ -3195,6 +3405,20 @@ pub mod pallet { Some(mpower_data_vec.clone()) } + /// Add new finished fetching mPower on-chain. + fn add_finished_fetching_mpower(account_id: T::AccountId, fetched_mpower_data: FetchedMPowerForAccountsForDatePayloadData) -> Option { + // note: AccountId as Vec is [0, 0, ... 0] since its an unsigned transaction + log::info!("Processing finished fetching mPower for account for date into storage: {:?}", fetched_mpower_data.start_of_requested_date_millis.clone()); + + Self::set_finished_fetching_mpower_for_accounts_for_date( + fetched_mpower_data.all_miner_public_keys_fetched.clone(), + fetched_mpower_data.start_of_requested_date_millis.clone(), + fetched_mpower_data.total_mpower_fetched.clone(), + ); + + Some(fetched_mpower_data.clone()) + } + /// Calculation based on mPower. fn average_mpower() -> Option { // let mpowers = >::get(); diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 9d6502ffe..aeefb76f6 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -4,7 +4,7 @@ pub use mock::{INIT_DAO_BALANCE_DHX, TOTAL_SUPPLY_DHX, TEN_DHX, FIVE_THOUSAND_DH use codec::Encode; use frame_support::{assert_noop, assert_ok, weights::{DispatchClass, DispatchInfo, GetDispatchInfo}, - traits::{OnFinalize, OnInitialize}, + traits::{OnFinalize, OnInitialize, OffchainWorker}, }; use frame_system::{self, AccountInfo, EventRecord, Phase, RawOrigin}; use pallet_balances::{self, BalanceLock, Reasons}; @@ -41,6 +41,7 @@ fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_ Timestamp::set_timestamp(1630049371000u64); MiningRewardsAllowanceTestModule::on_initialize(1); + MiningRewardsAllowanceTestModule::offchain_worker(1); // FIXME - why doesn't this work and use the defaults that we have set in the genesis config? // i've had to add a function `set_rewards_allowance_dhx_daily` to set this instead From 3076edabf5e43ff07a56acdeeb2c4a322a1454c1 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 9 Dec 2021 07:15:32 +0100 Subject: [PATCH 26/37] wip --- pallets/mining/rewards-allowance/src/lib.rs | 437 +++++++++++------- pallets/mining/rewards-allowance/src/tests.rs | 295 ++++++++---- 2 files changed, 458 insertions(+), 274 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 91a7f63b1..eef1935c4 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -479,14 +479,19 @@ pub mod pallet { ), >; - /// Defines the block when next unsigned transaction will be accepted. + /// Defines the block when next unsigned transaction (specifically for fetching the mPower) will be accepted. /// /// To prevent spam of unsigned (and unpayed!) transactions on the network, /// we only allow one transaction every `T::UnsignedInterval` blocks. /// This storage entry defines when new transaction is going to be accepted. #[pallet::storage] - #[pallet::getter(fn next_unsigned_at)] - pub(super) type NextUnsignedAt = StorageValue<_, T::BlockNumber, ValueQuery>; + #[pallet::getter(fn next_unsigned_at_for_fetched_mpower)] + pub(super) type NextUnsignedAtForFetchedMPower = StorageValue<_, T::BlockNumber, ValueQuery>; + + /// Defines the block when next unsigned transaction (specifically for finishing fetching the mPower) will be accepted. + #[pallet::storage] + #[pallet::getter(fn next_unsigned_at_for_finished_fetching_mpower)] + pub(super) type NextUnsignedAtForFinishedFetchingMPower = StorageValue<_, T::BlockNumber, ValueQuery>; // The genesis config type. #[pallet::genesis_config] @@ -745,6 +750,8 @@ pub mod pallet { /// any alterations. More specifically alterations are not forbidden, but they are not persisted /// in any way after the worker has finished. fn offchain_worker(block_number: T::BlockNumber) { + log::info!("offchain_worker: {:?}", block_number.clone()); + // println!("offchain_worker: {:?}", block_number.clone()); // Note that having logs compiled to WASM may cause the size of the blob to increase // significantly. You can use `RuntimeDebug` custom derive to hide details of the types // in WASM. The `sp-api` crate also provides a feature `disable-logging` to disable @@ -757,11 +764,6 @@ pub mod pallet { // let parent_hash = >::block_hash(block_number - 1u32.into()); // log::debug!("offchain_workers current block: {:?} (parent hash: {:?})", block_number, parent_hash); - // Call a helper function that reads storage entries of the current state average_mpower - // and performs a calculation. - // let average_mpower: Option = Self::average_mpower(); - // log::debug!("offchain_workers average_mpower: {:?}", average_mpower); - let should_process_block = Self::should_process_block(block_number.clone()); if should_process_block == false { return; @@ -772,21 +774,21 @@ pub mod pallet { // Anything that needs to be done at the start of the block. let timestamp: ::Moment = >::get(); - log::info!("block_number: {:?}", block_number.clone()); - log::info!("timestamp: {:?}", timestamp.clone()); + log::info!("offchain_worker - block_number: {:?}", block_number.clone()); + log::info!("offchain_worker - timestamp: {:?}", timestamp.clone()); let requested_date_as_u64; let _requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()); match _requested_date_as_u64 { Err(_e) => { - log::error!("Unable to convert Moment to u64 in millis for timestamp"); + log::error!("offchain_worker - Unable to convert Moment to u64 in millis for timestamp"); return; }, Ok(ref x) => { requested_date_as_u64 = x; } } - log::info!("requested_date_as_u64: {:?}", requested_date_as_u64.clone()); - // println!("requested_date_as_u64: {:?}", requested_date_as_u64.clone()); + log::info!("offchain_worker - requested_date_as_u64: {:?}", requested_date_as_u64.clone()); + // println!("offchain_worker - requested_date_as_u64: {:?}", requested_date_as_u64.clone()); // do not run when block number is 1, which is when timestamp is 0 because this // timestamp corresponds to 1970-01-01 @@ -798,15 +800,15 @@ pub mod pallet { let _start_of_requested_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(requested_date_as_u64.clone()); match _start_of_requested_date_millis { Err(_e) => { - log::error!("Unable to convert u64 in milliseconds to start_of_requested_date_millis"); + log::error!("offchain_worker - Unable to convert u64 in milliseconds to start_of_requested_date_millis"); return; }, Ok(ref x) => { start_of_requested_date_millis = x; } } - log::info!("start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); - // println!("start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); + log::info!("offchain_worker - start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); + // println!("offchain_worker - start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); // TODO - fetch the mpower from off-chain and store it with `set_mpower_of_account_for_date` // but only for the reg_dhx_miners @@ -816,14 +818,13 @@ pub mod pallet { // after fetching the mpower values store by sending an unsigned transactions let should_send = Self::choose_transaction_type(block_number.clone()); - let mut res; let mut mpower_data_vec = vec![]; match should_send { TransactionType::Raw => { let _mpower_res = Self::fetch_mpower_process(block_number.clone(), start_of_requested_date_millis.clone()); match _mpower_res.clone() { Err(e) => { - log::error!("offchain_workers error fetching mpower: {}", e); + log::error!("offchain_worker - offchain_workers error fetching mpower: {}", e); return; }, Ok(x) => { @@ -832,7 +833,7 @@ pub mod pallet { } }, TransactionType::None => { - log::error!("offchain_workers error unknown transaction type"); + log::error!("offchain_worker - offchain_workers error unknown transaction type"); return; }, }; @@ -845,17 +846,29 @@ pub mod pallet { // and voted on by governance, and so it just includes a list of account addresses that we check against. // if the list needs to be changed then just call it and add all of them again once approved. - res = Self::store_mpower_raw_unsigned(block_number.clone(), start_of_requested_date_millis.clone(), mpower_data_vec.clone()); - if let Err(e) = res { - log::error!("offchain_workers error storing mpower: {}", e); - } - + // TODO - verify these fetched public keys correspond to registered dhx miners, + // and if not we should only store mpower data corresponding to those that are let mut all_miner_public_keys_fetched = vec![]; let mut total_mpower_fetched = 0u128; for (index, mpower_data_item) in mpower_data_vec.iter().enumerate() { + log::info!("offchain_worker - mpower_data_vec {:?}, {:?}", index.clone(), mpower_data_item.account_id_registered_dhx_miner.clone()); + log::info!("offchain_worker - mpower_data_vec {:?}, {:?}", index.clone(), mpower_data_item.mpower_registered_dhx_miner.clone()); all_miner_public_keys_fetched.push(mpower_data_item.account_id_registered_dhx_miner.clone()); - total_mpower_fetched.checked_add(mpower_data_item.mpower_registered_dhx_miner.clone()); + + let new_total_mpower_fetched = total_mpower_fetched.clone(); + let _total_mpower_fetched = + new_total_mpower_fetched.checked_add(mpower_data_item.mpower_registered_dhx_miner.clone()); + match _total_mpower_fetched { + None => { + log::error!("Unable to add mpower_data_item.mpower_registered_dhx_miner with total_mpower_fetched due to StorageOverflow"); + return; + }, + Some(x) => { + total_mpower_fetched = x; + } + } } + log::info!("offchain_worker - total_mpower_fetched {:?}, {:?}", total_mpower_fetched.clone(), block_number.clone()); let fetched_mpower_data: FetchedMPowerForAccountsForDatePayloadData = FetchedMPowerForAccountsForDatePayload { start_of_requested_date_millis: start_of_requested_date_millis.clone(), @@ -863,12 +876,23 @@ pub mod pallet { total_mpower_fetched: total_mpower_fetched.clone(), }; - res = Self::store_finished_fetching_mpower_raw_unsigned( + let res_store_mpower = Self::store_mpower_raw_unsigned( + block_number.clone(), + start_of_requested_date_millis.clone(), + mpower_data_vec.clone() + ); + log::info!("offchain_worker - finished store_mpower_raw_unsigned at block: {:?}", block_number.clone()); + if let Err(e) = res_store_mpower { + log::error!("offchain_worker - offchain_workers error storing mpower: {}", e); + } + + let res_store_finished = Self::store_finished_fetching_mpower_raw_unsigned( block_number.clone(), fetched_mpower_data.clone() ); - if let Err(e) = res { - log::error!("offchain_workers error storing finished fetching mpower: {}", e); + log::info!("offchain_worker - finished store_finished_fetching_mpower_raw_unsigned at block: {:?}", block_number.clone()); + if let Err(e) = res_store_finished { + log::error!("offchain_worker - offchain_workers error storing finished fetching mpower: {}", e); } return; @@ -881,14 +905,16 @@ pub mod pallet { // TODO - update with the weight consumed fn on_initialize(block_number: T::BlockNumber) -> Weight { let should_process_block = Self::should_process_block(block_number.clone()); - if should_process_block == true { + if should_process_block == false { return 0; } // Anything that needs to be done at the start of the block. let timestamp: ::Moment = >::get(); log::info!("block_number: {:?}", block_number.clone()); + // println!("block_number: {:?}", block_number.clone()); log::info!("timestamp: {:?}", timestamp.clone()); + // println!("timestamp: {:?}", timestamp.clone()); let requested_date_as_u64; let _requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()); match _requested_date_as_u64 { @@ -1270,17 +1296,18 @@ pub mod pallet { } } } - // we only check accounts that have registered that they want to participate in DHX Mining let reg_dhx_miners; if let Some(_reg_dhx_miners) = >::get() { reg_dhx_miners = _reg_dhx_miners; } else { log::error!("Unable to retrieve any registered DHX Miners"); + // println!("Unable to retrieve any registered DHX Miners"); return 0; } if reg_dhx_miners.len() == 0 { log::error!("Registered DHX Miners has no elements"); + // println!("Unable to retrieve any registered DHX Miners"); return 0; }; @@ -1307,7 +1334,9 @@ pub mod pallet { for (index, miner_public_key) in reg_dhx_miners.iter().enumerate() { miner_count += 1; log::info!("miner_count {:#?}", miner_count); + // println!("miner_count {:#?}", miner_count); log::info!("miner_public_key {:?}", miner_public_key); + // println!("miner_public_key {:?}", miner_public_key); // let locks_until_block_for_account = >::locks(miner_public_key.clone()); // // NOTE - I fixed the following error by using `.into_inner()` after asking the community here and getting a // // response in Substrate Builders weekly meeting https://matrix.to/#/!HzySYSaIhtyWrwiwEV:matrix.org/$163243681163543vyfkW:matrix.org?via=matrix.parity.io&via=matrix.org&via=corepaper.org @@ -1340,6 +1369,7 @@ pub mod pallet { match _miner_account_id.clone() { Err(_e) => { log::error!("Unable to decode miner_public_key"); + // println!("Unable to decode miner_public_key"); return 0; }, Ok(x) => { @@ -1387,6 +1417,7 @@ pub mod pallet { // let miner_public_key = miner.clone().encode(); log::info!("Public key {:?}", miner_public_key); + // println!("Public key {:?}", miner_public_key); let bonded_dhx_current_u128; let _bonded_dhx_current_u128 = Self::set_bonded_dhx_of_account_for_date( @@ -2111,11 +2142,20 @@ pub mod pallet { mpower_current_u128.clone(), ); - Self::set_mpower_of_account_for_date( + let _set_mpower = Self::set_mpower_of_account_for_date( account_id.clone(), start_of_requested_date_millis.clone(), mpower_current_u128.clone(), ); + match _set_mpower.clone() { + Err(_e) => { + log::warn!("Unable to change mpower using set_mpower_of_account_for_date"); + return Err(DispatchError::Other("Unable to change mpower using set_mpower_of_account_for_date")); + }, + Ok(x) => { + log::info!("changed mpower using set_mpower_of_account_for_date to: {:?} {:?}", account_id.clone(), x); + } + } // Return a successful DispatchResultWithPostInfo Ok(()) @@ -2608,19 +2648,22 @@ pub mod pallet { /// they don't charge fees, we still don't want a single block to contain unlimited /// number of such transactions. #[pallet::weight(0)] - pub fn submit_mpower_unsigned( + pub fn submit_fetched_mpower_unsigned( origin: OriginFor, _block_number: T::BlockNumber, start_of_requested_date_millis: Date, mpower_payload_vec: Vec>, ) -> DispatchResultWithPostInfo { + log::info!("submit_fetched_mpower_unsigned"); // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; // Add the mpower vec on-chain, but mark it as coming from an empty address. Self::add_mpower(Default::default(), start_of_requested_date_millis.clone(), mpower_payload_vec.clone()); - // now increment the block number at which we expect next unsigned transaction. + log::info!("finished submit_fetched_mpower_unsigned"); + // now increment the block number at which we expect next unsigned transaction + // that is specifically for fetching mpower. let current_block = >::block_number(); - >::put(current_block + T::UnsignedInterval::get()); + >::put(current_block + T::UnsignedInterval::get()); Ok(().into()) } @@ -2630,13 +2673,15 @@ pub mod pallet { _block_number: T::BlockNumber, fetched_mpower_data: FetchedMPowerForAccountsForDatePayloadData, ) -> DispatchResultWithPostInfo { + log::info!("submit_finished_fetching_mpower_unsigned"); // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; // Add the data on-chain, but mark it as coming from an empty address. Self::add_finished_fetching_mpower(Default::default(), fetched_mpower_data.clone()); - // now increment the block number at which we expect next unsigned transaction. + // now increment the block number at which we expect next unsigned transaction + // that is specifically for having "finished" fetching mpower. let current_block = >::block_number(); - >::put(current_block + T::UnsignedInterval::get()); + >::put(current_block + T::UnsignedInterval::get()); Ok(().into()) } } @@ -2651,10 +2696,15 @@ pub mod pallet { /// here we make sure that some particular calls (the ones produced by offchain worker) /// are being whitelisted and marked as valid. fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { - if let Call::submit_mpower_unsigned(block_number, start_of_requested_date_millis, new_mpower_data_vec) = call { - Self::validate_transaction_parameters(block_number, start_of_requested_date_millis, new_mpower_data_vec) - } else { - InvalidTransaction::Call.into() + if let Call::submit_fetched_mpower_unsigned(block_number, start_of_requested_date_millis, new_mpower_data_vec) = call { + log::info!("validate_unsigned submit_fetched_mpower_unsigned"); + return Self::validate_transaction_parameters_for_fetched_mpower(block_number, start_of_requested_date_millis, new_mpower_data_vec); + } else if let Call::submit_finished_fetching_mpower_unsigned(block_number, fetched_mpower_data) = call { + log::info!("validate_unsigned validate_transaction_parameters_for_fetched_mpower"); + return Self::validate_transaction_parameters_for_finished_fetching_mpower(block_number, fetched_mpower_data); + } else { + log::info!("validate_unsigned invalid"); + return InvalidTransaction::Call.into(); } } } @@ -2895,6 +2945,7 @@ pub mod pallet { } pub fn set_mpower_of_account_for_date(account_public_key: Vec, start_of_requested_date_millis: Date, mpower: u128) -> Result { + log::info!("set_mpower_of_account_for_date: {:?} {:?} {:?}", account_public_key.clone(), start_of_requested_date_millis.clone(), mpower.clone()); let mpower_current_u128 = mpower.clone(); // check if the new mpower value differs from the value that is already in storage @@ -2905,11 +2956,13 @@ pub mod pallet { account_public_key.clone(), ) ); + log::info!("existing mpower_for_account_for_date {:?}", mpower_for_account_for_date.clone()); match mpower_for_account_for_date { None => { + log::info!("Adding new storage value of mPower for account for date of data retrieved from API {:?}", mpower_current_u128.clone()); }, Some(x) => { - log::warn!("Existing storage value of mPower for account for date of data retrieved from API"); + log::warn!("Existing storage value of mPower for account for date of data retrieved from API {:?}", x); return Err(DispatchError::Other("Existing storage value of mPower for account for date of data retrieved from API")); } } @@ -2941,7 +2994,7 @@ pub mod pallet { } pub fn set_finished_fetching_mpower_for_accounts_for_date(all_miner_public_keys_fetched: Vec>, start_of_requested_date_millis: Date, total_mpower_fetched: u128) -> Result { - + log::info!("set_finished_fetching_mpower_for_accounts_for_date"); // check if the new total_mpower_fetched value differs from the value that is already in storage // for the given key, and only insert if it is different let data_finished_fetching_for_date = >::get(start_of_requested_date_millis.clone()); @@ -3138,8 +3191,8 @@ pub mod pallet { fn fetch_mpower_process(block_number: T::BlockNumber, start_of_requested_date_millis: Date) -> Result>, &'static str> { // Make sure we don't fetch the mpower if unsigned transaction is going to be rejected // anyway. - let next_unsigned_at = >::get(); - if next_unsigned_at > block_number { + let next_unsigned_at_for_fetched_mpower = >::get(); + if next_unsigned_at_for_fetched_mpower > block_number { return Err("Too early to send unsigned transaction") } @@ -3152,10 +3205,11 @@ pub mod pallet { /// A helper function to send a raw unsigned transaction to store the mpower data. fn store_mpower_raw_unsigned(block_number: T::BlockNumber, start_of_requested_date_millis: Date, mpower_data_vec: Vec>) -> Result<(), &'static str> { - // Received mpower data is wrapped into a call to `submit_mpower_unsigned` public function of this + log::info!("offchain_worker - store_mpower_raw_unsigned"); + // Received mpower data is wrapped into a call to `submit_fetched_mpower_unsigned` public function of this // pallet. This means that the transaction, when executed, will simply call that function // passing `mpower_data_vec` as an argument. - let call = Call::submit_mpower_unsigned(block_number.clone(), start_of_requested_date_millis.clone(), mpower_data_vec.clone()); + let call = Call::submit_fetched_mpower_unsigned(block_number.clone(), start_of_requested_date_millis.clone(), mpower_data_vec.clone()); // Now let's create a transaction out of this call and submit it to the pool. // Here we showcase two ways to send an unsigned transaction / unsigned payload (raw) @@ -3166,13 +3220,14 @@ pub mod pallet { // attack vectors. See validation logic docs for more details. // SubmitTransaction::>::submit_unsigned_transaction(call.into()) - .map_err(|()| "Unable to submit unsigned transaction.")?; + .map_err(|()| "Unable to submit unsigned transaction for submit_fetched_mpower.")?; Ok(()) } /// A helper function to send a raw unsigned transaction to store finished fetching mpower data for use in on_initialize fn store_finished_fetching_mpower_raw_unsigned(block_number: T::BlockNumber, fetched_mpower_data: FetchedMPowerForAccountsForDatePayloadData) -> Result<(), &'static str> { + log::info!("offchain_worker - store_finished_fetching_mpower_raw_unsigned"); // Received mpower data is wrapped into a call to `submit_finished_fetching_mpower_unsigned` public function of this // pallet. This means that the transaction, when executed, will simply call that function // passing `fetched_mpower_data` as an argument. @@ -3187,85 +3242,96 @@ pub mod pallet { // attack vectors. See validation logic docs for more details. // SubmitTransaction::>::submit_unsigned_transaction(call.into()) - .map_err(|()| "Unable to submit unsigned transaction.")?; + .map_err(|()| "Unable to submit unsigned transaction for submit_finished_fetching_mpower.")?; Ok(()) } /// Fetch current mPower and return the result. fn fetch_mpower(block_number: T::BlockNumber, start_of_requested_date_millis: Date) -> Result>, http::Error> { - // We want to keep the offchain worker execution time reasonable, so we set a hard-coded - // deadline to 2s to complete the external call. - // You can also wait idefinitely for the response, however you may still get a timeout - // coming from the host machine. - let deadline = sp_io::offchain::timestamp().add(Duration::from_millis(2_000)); - // Initiate an external HTTP GET request. - // This is using high-level wrappers from `sp_runtime`, for the low-level calls that - // you can find in `sp_io`. The API is trying to be similar to `reqwest`, but - // since we are running in a custom WASM execution environment we can't simply - // import the library here. - - // Example from Substrate - let request = - http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); - - // Example of request we may use - // let start_of_requested_date_millis = 1630195200000i64; - // let url = format!("https://api.datahighway.com/data/mpower-for-date?start_of_requested_date_millis={}", start_of_requested_date_millis); - // log::info!("Request URL: {}", url.clone()); + log::info!("offchain_worker - fetch_mpower"); + + // TODO - below is temporarily commented out whilst we are using mock API data + + // // We want to keep the offchain worker execution time reasonable, so we set a hard-coded + // // deadline to 2s to complete the external call. + // // You can also wait idefinitely for the response, however you may still get a timeout + // // coming from the host machine. + + // // Initiate an external HTTP GET request. + // // This is using high-level wrappers from `sp_runtime`, for the low-level calls that + // // you can find in `sp_io`. The API is trying to be similar to `reqwest`, but + // // since we are running in a custom WASM execution environment we can't simply + // // import the library here. + + // // Example from Substrate // let request = - // http::Request::get(&url); - - // We set the deadline for sending of the request, note that awaiting response can - // have a separate deadline. Next we send the request, before that it's also possible - // to alter request headers or stream body content in case of non-GET requests. - let pending = request.deadline(deadline).send().map_err(|_| http::Error::IoError)?; - - // The request is already being processed by the host, we are free to do anything - // else in the worker (we can send multiple concurrent requests too). - // At some point however we probably want to check the response though, - // so we can block current thread and wait for it to finish. - // Note that since the request is being driven by the host, we don't have to wait - // for the request to have it complete, we will just not read the response. - let response = pending.try_wait(deadline).map_err(|_| http::Error::DeadlineReached)??; - // Let's check the status code before we proceed to reading the response. - if response.code != 200 { - log::warn!("Unexpected status code: {}", response.code); - return Err(http::Error::Unknown) - } - - // Next we want to fully read the response body and collect it to a vector of bytes. - // Note that the return object allows you to read the body in chunks as well - // with a way to control the deadline. - let body = response.body().collect::>(); - - // Create a str slice from the body. - let body_str = sp_std::str::from_utf8(&body).map_err(|_| { - log::warn!("No UTF8 body"); - http::Error::Unknown - })?; - - log::info!("Received HTTP Body: {}", body_str.clone()); + // http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"); + + // // Example of request we may use + // // let start_of_requested_date_millis = 1630195200000i64; + // // let url = format!("https://api.datahighway.com/data/mpower-for-date?start_of_requested_date_millis={}", start_of_requested_date_millis); + // // log::info!("Request URL: {}", url.clone()); + // // let request = + // // http::Request::get(&url); + + // // We set the deadline for sending of the request, note that awaiting response can + // // have a separate deadline. Next we send the request, before that it's also possible + // // to alter request headers or stream body content in case of non-GET requests. + // let pending = request.deadline(deadline).send().map_err(|_| http::Error::IoError)?; + + // // The request is already being processed by the host, we are free to do anything + // // else in the worker (we can send multiple concurrent requests too). + // // At some point however we probably want to check the response though, + // // so we can block current thread and wait for it to finish. + // // Note that since the request is being driven by the host, we don't have to wait + // // for the request to have it complete, we will just not read the response. + // let response = pending.try_wait(deadline).map_err(|_| http::Error::DeadlineReached)??; + + // // Let's check the status code before we proceed to reading the response. + // if response.code != 200 { + // log::warn!("offchain_worker - Unexpected status code: {}", response.code); + // return Err(http::Error::Unknown) + // } + + // // Next we want to fully read the response body and collect it to a vector of bytes. + // // Note that the return object allows you to read the body in chunks as well + // // with a way to control the deadline. + // let body = response.body().collect::>(); + + // // Create a str slice from the body. + // let body_str = sp_std::str::from_utf8(&body).map_err(|_| { + // log::warn!("offchain_worker - No UTF8 body"); + // http::Error::Unknown + // })?; + + // log::info!("offchain_worker - Received HTTP Body: {}", body_str.clone()); // FIXME - replace the below hard-coded example in future with use of the response body // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d // Bob public key 0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48 + // Charlie public key 0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22 + // + // Note: we're not currently using the `start_of_requested_date_millis` that is in the hard-coded data below, + // and instead we're using the current date temporarily using + // `received_at_date: received_date_as_millis.clone(),` let mpower_data = r#"{ "data": [ { "acct_id": "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", "mpower": "11", "start_of_requested_date_millis": "1630195200000" }, - { "acct_id": "8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", "mpower": "12", "start_of_requested_date_millis": "1630195200000" } + { "acct_id": "8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", "mpower": "12", "start_of_requested_date_millis": "1630195200000" }, + { "acct_id": "90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22", "mpower": "13", "start_of_requested_date_millis": "1630195200000" } ] }"#; let mpower_data_vec = match Self::parse_mpower_data(mpower_data, block_number.clone()) { Some(data) => Ok(data), None => { - log::warn!("Unable to extract mpower data from the response: {:?}", body_str); + log::warn!("offchain_worker - Unable to extract mpower data from the response"); Err(http::Error::Unknown) }, }?; - // log::info!("Parsed mpower_data_vec: {:?}", mpower_data_vec); + // log::info!("offchain_worker - Parsed mpower_data_vec: {:?}", mpower_data_vec); Ok(mpower_data_vec) } @@ -3279,23 +3345,30 @@ pub mod pallet { let timestamp = >::get(); let received_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()).ok()?; - log::info!("received_date_as_u64: {:?}", received_date_as_u64.clone()); + log::info!("offchain_worker - received_date_as_u64: {:?}", received_date_as_u64.clone()); // TODO - parse for mPower data and replace hard-coded response with output let received_date_as_millis = Self::convert_u64_in_milliseconds_to_start_of_date(received_date_as_u64.clone()).ok()?; - let mpower_json_data = lite_json::parse_json(mpower_data_str); + let mpower_json_data = match lite_json::parse_json(mpower_data_str) { + Err(e) => { + log::error!("Couldn't parse JSON {:?}", e); + // println!("Couldn't parse JSON {:?}", e); + return None; + }, + Ok(data) => data, + }; // let mpower_json_data: MPowerJSONResponseData = match serde_json::from_str(mpower_data_str) { // Err(e) => { - // println!("Couldn't parse JSON :( {:?}", e); + // // println!("Couldn't parse JSON :( {:?}", e); // return None; // }, // Ok(data) => data, // }; - // log::info!("mpower_json_data{:?}", mpower_json_data); + // log::info!("offchain_worker - mpower_json_data{:#?}", mpower_json_data); let mut mpower_data_vec: Vec> = vec![]; - let mpower_array = match mpower_json_data.ok()? { + let mpower_array = match mpower_json_data { JsonValue::Object(obj) => { let (_, v) = obj.into_iter().find(|(k, _)| k.iter().copied().eq("data".chars()))?; match v { @@ -3329,29 +3402,29 @@ pub mod pallet { _ => return None, }; - log::info!("obj_mpower char {:?} {:?}", i, obj_mpower.clone()); + log::info!("offchain_worker - obj_mpower char {:?} {:?}", i, obj_mpower.clone()); // Convert from `Vec` to `Vec` since we do not use String in the runtime // e.g. converts from `['1', '2', '3']` to `123` let obj_acct_id_str_hex: Vec = obj_acct_id.iter().map(|c| *c as u8).collect::>(); let obj_mpower_str_hex: Vec = obj_mpower.iter().map(|c| *c as u8).collect::>(); - log::info!("obj_mpower_str_hex {:?} {:?}", i, obj_mpower_str_hex.clone()); + log::info!("offchain_worker - obj_mpower_str_hex {:?} {:?}", i, obj_mpower_str_hex.clone()); // Decode from hex ascii format let obj_acct_id_str = hex::decode(obj_acct_id_str_hex.clone()).ok()?; - log::info!("Decoded acct_id i public key hex as Vec {:?} {:?}", i, obj_acct_id_str.clone()); + log::info!("offchain_worker - Decoded acct_id i public key hex as Vec {:?} {:?}", i, obj_acct_id_str.clone()); let mpower_u128 = Self::convert_vec_u8_to_u128(&obj_mpower_str_hex).ok()?; - log::info!("mpower_u128 {:?} {:?}", i, mpower_u128.clone()); + log::info!("offchain_worker - mpower_u128 {:?} {:?}", i, mpower_u128.clone()); // let mut obj_mpower_as_u128 = 0u128; // initialize // if let Some(_obj_mpower_as_u128) = TryInto::::try_into(obj_mpower_str.clone()).ok() { // obj_mpower_as_u128 = _obj_mpower_as_u128; // } else { - // log::error!("Unable to convert Vec into u128"); + // log::error!("offchain_worker - Unable to convert Vec into u128"); // return None; // } - // log::info!("obj_mpower_as_u128 {:?} {:?}", i, obj_mpower_as_u128.clone()); + // log::info!("offchain_worker - obj_mpower_as_u128 {:?} {:?}", i, obj_mpower_as_u128.clone()); // Example only: // Alice public key 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d @@ -3359,7 +3432,7 @@ pub mod pallet { // Note: do not do `hex!["..."].encode(), since that will just encoding a vec, // which will include a length prefix, but we don't want that. // let example_acct_id_str: Vec = write_hex!["d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"].into(); - // log::info!("example_acct_id_str {:?}", example_acct_id_str); + // log::info!("offchain_worker - example_acct_id_str {:?}", example_acct_id_str); // let mpower_as_u128: u128 = obj_mpower.clone().parse().unwrap(); // convert from string to number @@ -3368,11 +3441,11 @@ pub mod pallet { // if let Some(_reg_dhx_miners) = >::get() { // reg_dhx_miners = _reg_dhx_miners; // } else { - // log::error!("Unable to retrieve any registered DHX Miners"); + // log::error!("offchain_worker - Unable to retrieve any registered DHX Miners"); // return None; // } // let first_reg_dhx_miner = ®_dhx_miners[0]; - // log::info!("first_reg_dhx_miner {:?}", first_reg_dhx_miner.encode()); + // log::info!("offchain_worker - first_reg_dhx_miner {:?}", first_reg_dhx_miner.encode()); let mpower_data_elem: MPowerPayloadData = MPowerPayload { account_id_registered_dhx_miner: obj_acct_id_str.clone(), @@ -3384,7 +3457,7 @@ pub mod pallet { mpower_data_vec.push(mpower_data_elem); } - // log::info!("mpower_data_vec {:?}", mpower_data_vec); + // log::info!("offchain_worker - mpower_data_vec {:?}", mpower_data_vec); Some(mpower_data_vec) } @@ -3392,14 +3465,26 @@ pub mod pallet { /// Add new mPower on-chain. fn add_mpower(account_id: T::AccountId, start_of_requested_date_millis: Date, mpower_data_vec: Vec>) -> Option>> { // note: AccountId as Vec is [0, 0, ... 0] since its an unsigned transaction - log::info!("Processing mPower for account for date into storage: {:?}", start_of_requested_date_millis.clone()); + log::info!("offchain_worker - Processing mPower for account for date into storage: {:?}", start_of_requested_date_millis.clone()); for (index, mpower_data_item) in mpower_data_vec.iter().enumerate() { - Self::set_mpower_of_account_for_date( + log::info!("offchain_worker - Processing mPower for account for date into storage - loop: {:?} {:?} {:?} {:?}", index.clone(), mpower_data_item.account_id_registered_dhx_miner.clone(), start_of_requested_date_millis.clone(), mpower_data_item.mpower_registered_dhx_miner.clone()); + + let _set_mpower = Self::set_mpower_of_account_for_date( mpower_data_item.account_id_registered_dhx_miner.clone(), start_of_requested_date_millis.clone(), mpower_data_item.mpower_registered_dhx_miner.clone(), ); + match _set_mpower.clone() { + Err(_e) => { + log::warn!("Unable to set_mpower_of_account_for_date"); + return None; + }, + Ok(x) => { + log::info!("set set_mpower_of_account_for_date to: {:?} {:?}", mpower_data_item.account_id_registered_dhx_miner.clone(), x); + continue; + } + } } Some(mpower_data_vec.clone()) @@ -3408,7 +3493,7 @@ pub mod pallet { /// Add new finished fetching mPower on-chain. fn add_finished_fetching_mpower(account_id: T::AccountId, fetched_mpower_data: FetchedMPowerForAccountsForDatePayloadData) -> Option { // note: AccountId as Vec is [0, 0, ... 0] since its an unsigned transaction - log::info!("Processing finished fetching mPower for account for date into storage: {:?}", fetched_mpower_data.start_of_requested_date_millis.clone()); + log::info!("offchain_worker - Processing finished fetching mPower for account for date into storage: {:?}", fetched_mpower_data.start_of_requested_date_millis.clone()); Self::set_finished_fetching_mpower_for_accounts_for_date( fetched_mpower_data.all_miner_public_keys_fetched.clone(), @@ -3419,80 +3504,80 @@ pub mod pallet { Some(fetched_mpower_data.clone()) } - /// Calculation based on mPower. - fn average_mpower() -> Option { - // let mpowers = >::get(); - - // TODO - implement what we need and replace hard-coded response with output + fn validate_transaction_parameters_for_finished_fetching_mpower( + block_number: &T::BlockNumber, + fetched_mpower_data: &FetchedMPowerForAccountsForDatePayloadData, + ) -> TransactionValidity { + // Now let's check if the transaction has any chance to succeed. + let next_unsigned_at_for_finished_fetching_mpower = >::get(); + log::info!("offchain_worker - validate_transaction_parameters_for_finished_fetching_mpower - block_number {:?}", block_number.clone()); + log::info!("offchain_worker - validate_transaction_parameters_for_finished_fetching_mpower - next_unsigned_at_for_finished_fetching_mpower {:?}", next_unsigned_at_for_finished_fetching_mpower.clone()); + // TODO - do we need to use a modified version of this at all? + if &next_unsigned_at_for_finished_fetching_mpower > block_number { + return InvalidTransaction::Stale.into() + } + // Let's make sure to reject transactions from the future. + let current_block = >::block_number(); + log::info!("offchain_worker - validate_transaction_parameters_for_finished_fetching_mpower - current_block {:?}", current_block.clone()); + if ¤t_block < block_number { + return InvalidTransaction::Future.into() + } - // if mpowers.is_empty() { - // None - // } else { - // Some(mpowers.iter().fold(0_u128, |a, b| a.saturating_add(*b)) / mpowers.len() as u128) - // } - None + // See Substrate client/transaction-pool for configuration details + ValidTransaction::with_tag_prefix("OffchainWorkerFinishedFetchingMPower") + .priority(T::UnsignedPriority::get().saturating_add(2u128 as _)) + .and_provides(next_unsigned_at_for_finished_fetching_mpower) + // TODO - do we need to use .and_requires() and provide the `previous_unsigned_at` + // to signify that we need the fetched_mpower unsigned tx to happen beforehand? + .longevity(5) + .propagate(true) + .build() } - fn validate_transaction_parameters( + fn validate_transaction_parameters_for_fetched_mpower( block_number: &T::BlockNumber, start_of_requested_date_millis: &Date, new_mpower_data: &Vec>, ) -> TransactionValidity { // Now let's check if the transaction has any chance to succeed. - let next_unsigned_at = >::get(); - if &next_unsigned_at > block_number { + let next_unsigned_at_for_fetched_mpower = >::get(); + log::info!("offchain_worker - validate_transaction_parameters_for_fetched_mpower - block_number {:?}", block_number.clone()); + log::info!("offchain_worker - validate_transaction_parameters_for_fetched_mpower - next_unsigned_at_for_fetched_mpower {:?}", next_unsigned_at_for_fetched_mpower.clone()); + if &next_unsigned_at_for_fetched_mpower > block_number { return InvalidTransaction::Stale.into() } // Let's make sure to reject transactions from the future. let current_block = >::block_number(); + log::info!("offchain_worker - validate_transaction_parameters_for_fetched_mpower - current_block {:?}", current_block.clone()); if ¤t_block < block_number { return InvalidTransaction::Future.into() } - // // We prioritize transactions that are more far away from current average. - // // - // // Note this doesn't make much sense when building an actual oracle, but this example - // // is here mostly to show off offchain workers capabilities, not about building an - // // oracle. - // let avg_mpower = Self::average_mpower() - // .map(|mpower| if &mpower > new_mpower { mpower - new_mpower } else { new_mpower - mpower }) - // .unwrap_or(0); - - // FIXME - - ValidTransaction::with_tag_prefix("MPowerOffchainWorker") - .priority(1) - .and_provides(next_unsigned_at) + // See Substrate client/transaction-pool for configuration details + ValidTransaction::with_tag_prefix("OffchainWorkerFetchedMPower") + // Set base priority and hope it's included before any other + // transactions in the pool + .priority(T::UnsignedPriority::get().saturating_add(1u128 as _)) + // This transaction does not require anything else to go before into the pool. + // In theory we could require `previous_unsigned_at` transaction to go first, + // but it's not necessary in our case. + //.and_requires() + // We set the `provides` tag to be the same as `next_unsigned_at_for_fetched_mpower`. This makes + // sure only one transaction produced after `next_unsigned_at_for_fetched_mpower` will ever + // get to the transaction pool and will end up in the block. + // We can still have multiple transactions compete for the same "spot", + // and the one with higher priority will replace other one in the pool. + .and_provides(next_unsigned_at_for_fetched_mpower) + // The transaction is only valid for next 5 blocks. After that it's + // going to be revalidated by the pool. .longevity(5) + // It's fine to propagate that transaction to other peers, which means it can be + // created even by nodes that don't produce blocks. + // Note that sometimes it's better to keep it for yourself (if you are the block + // producer), since for instance in some schemes others may copy your solution and + // claim a reward. .propagate(true) .build() - - // ValidTransaction::with_tag_prefix("MPowerOffchainWorker") - // // We set base priority to 2**20 and hope it's included before any other - // // transactions in the pool. Next we tweak the priority depending on how much - // // it differs from the current average. (the more it differs the more priority it - // // has). - // .priority(T::UnsignedPriority::get().saturating_add(avg_mpower as _)) - // // This transaction does not require anything else to go before into the pool. - // // In theory we could require `previous_unsigned_at` transaction to go first, - // // but it's not necessary in our case. - // //.and_requires() - // // We set the `provides` tag to be the same as `next_unsigned_at`. This makes - // // sure only one transaction produced after `next_unsigned_at` will ever - // // get to the transaction pool and will end up in the block. - // // We can still have multiple transactions compete for the same "spot", - // // and the one with higher priority will replace other one in the pool. - // .and_provides(next_unsigned_at) - // // The transaction is only valid for next 5 blocks. After that it's - // // going to be revalidated by the pool. - // .longevity(5) - // // It's fine to propagate that transaction to other peers, which means it can be - // // created even by nodes that don't produce blocks. - // // Note that sometimes it's better to keep it for yourself (if you are the block - // // producer), since for instance in some schemes others may copy your solution and - // // claim a reward. - // .propagate(true) - // .build() } // check that the current date start_of_current_date_millis is at least 7 days after the provided @@ -3543,7 +3628,7 @@ pub mod pallet { } // log::info!("period_millis_u64: {:?}", period_millis_u64.clone()); - // println!("period_millis_u64: {:?}", period_millis_u64.clone()); + // // println!("period_millis_u64: {:?}", period_millis_u64.clone()); if (period_millis_u64 >= challenge_period_millis.clone()) { is_more_than_challenge_period = true; } diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index aeefb76f6..acd6bdd4c 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -1,7 +1,10 @@ use super::{Call, Event, *}; use crate::{mock::*, Error}; pub use mock::{INIT_DAO_BALANCE_DHX, TOTAL_SUPPLY_DHX, TEN_DHX, FIVE_THOUSAND_DHX}; -use codec::Encode; +use codec::{ + Decode, + Encode, +}; use frame_support::{assert_noop, assert_ok, weights::{DispatchClass, DispatchInfo, GetDispatchInfo}, traits::{OnFinalize, OnInitialize, OffchainWorker}, @@ -25,14 +28,24 @@ const THIRTY_DHX: u128 = 30_000_000_000_000_000_000_u128; // 30 const TWENTY_DHX: u128 = 20_000_000_000_000_000_000_u128; // 20 const TWO_DHX: u128 = 2_000_000_000_000_000_000_u128; // 2 +// FIXME - do something like this so i can use constant in each unit test and replace all the duplication +// https://stackoverflow.com/a/58009990/3208553 +// const ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; +// const BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; +// const CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + #[test] // ignore this test until the FIXME is resolved #[ignore] fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_if_not_already_set_for_today() { new_test_ext().execute_with(|| { + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( Origin::root(), - vec![vec![3], vec![2], vec![1]], + vec![CHARLIE_PUBLIC_KEY, BOB_PUBLIC_KEY, ALICE_PUBLIC_KEY], )); // 27th August 2021 @ ~7am is 1630049371000 @@ -40,8 +53,9 @@ fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_ // 27th August 2021 @ 12am is 1630022400000 (start of day) Timestamp::set_timestamp(1630049371000u64); - MiningRewardsAllowanceTestModule::on_initialize(1); - MiningRewardsAllowanceTestModule::offchain_worker(1); + // Note: we start at block 2 since we early exit from block 1 because the timestamp is yet + MiningRewardsAllowanceTestModule::on_initialize(2); + // MiningRewardsAllowanceTestModule::offchain_worker(2); // FIXME - why doesn't this work and use the defaults that we have set in the genesis config? // i've had to add a function `set_rewards_allowance_dhx_daily` to set this instead @@ -289,7 +303,8 @@ fn it_allows_us_to_retrieve_genesis_value_for_min_mpower_daily() { new_test_ext().execute_with(|| { // FIXME - why doesn't it set the values we added in the chain_spec.rs at genesis // https://matrix.to/#/!HzySYSaIhtyWrwiwEV:matrix.org/$163424903366086IiiUH:matrix.org?via=matrix.parity.io&via=corepaper.org&via=matrix.org - MiningRewardsAllowanceTestModule::on_initialize(1); + // Note: we start at block 2 since we early exit from block 1 because the timestamp is yet + MiningRewardsAllowanceTestModule::on_initialize(2); assert_eq!(MiningRewardsAllowanceTestModule::min_mpower_daily(), Some(5u128)); }); } @@ -325,9 +340,13 @@ fn it_checks_if_is_more_than_challenge_period() { } fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( Origin::root(), - vec![vec![3], vec![2], vec![1]], + vec![CHARLIE_PUBLIC_KEY.clone(), BOB_PUBLIC_KEY.clone(), ALICE_PUBLIC_KEY.clone()], )); assert_ok!(MiningRewardsAllowanceTestModule::set_cooling_off_period_days( @@ -339,19 +358,19 @@ fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: FIVE_THOUSAND_DHX, )); - assert_eq!(MiningRewardsAllowanceTestModule::registered_dhx_miners(), Some(vec![vec![1], vec![2], vec![3]])); + assert_eq!(MiningRewardsAllowanceTestModule::registered_dhx_miners(), Some(vec![ALICE_PUBLIC_KEY, BOB_PUBLIC_KEY, CHARLIE_PUBLIC_KEY])); assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days(), Some(1)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_daily(), Some(FIVE_THOUSAND_DHX)); check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone()); - // check that rewards multiplier increases by multiplier every period days and that days total and remaining are reset - check_rewards_double_each_multiplier_period(amount_mpower_each_miner.clone()); + // // check that rewards multiplier increases by multiplier every period days and that days total and remaining are reset + // check_rewards_double_each_multiplier_period(amount_mpower_each_miner.clone()); - // check that after the multiplier doubles, they are no longer eligible to receive the rewards - // if they have the same amount bonded (since they’d then need twice the amount bonded as ratio changes from 10:1 to 20:1), - // even if they have sufficient mpower - check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_bonded(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); + // // check that after the multiplier doubles, they are no longer eligible to receive the rewards + // // if they have the same amount bonded (since they’d then need twice the amount bonded as ratio changes from 10:1 to 20:1), + // // even if they have sufficient mpower + // check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_bonded(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); } fn setup_min_mpower_daily(min_mpower_daily: u128) { @@ -364,9 +383,13 @@ fn setup_min_mpower_daily(min_mpower_daily: u128) { // we have to get their mpower the day before we check if they are eligible incase there are delays in getting the off-chain data fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, start_date: i64) { - let account_1_public_key = vec![1]; - let account_2_public_key = vec![2]; - let account_3_public_key = vec![3]; + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; + let account_2_public_key = BOB_PUBLIC_KEY; + let account_3_public_key = CHARLIE_PUBLIC_KEY; // https://aws1.discourse-cdn.com/business5/uploads/rust_lang/original/3X/9/0/909baa7e3d9569489b07c791ca76f2223bd7bac2.webp assert_ok!(MiningRewardsAllowanceTestModule::change_mpower_of_account_for_date(Origin::root(), account_1_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); @@ -387,6 +410,18 @@ fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, start_date: i64) } fn setup_bonding(amount_bonded_each_miner: u128, min_bonding_dhx_daily: u128) -> u32 { + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; + let account_2_public_key = BOB_PUBLIC_KEY; + let account_3_public_key = CHARLIE_PUBLIC_KEY; + + let account_1_account_id: u64 = Decode::decode(&mut account_1_public_key.as_slice().clone()).ok().unwrap(); + let account_2_account_id: u64 = Decode::decode(&mut account_2_public_key.as_slice().clone()).ok().unwrap(); + let account_3_account_id: u64 = Decode::decode(&mut account_3_public_key.as_slice().clone()).ok().unwrap(); + assert_ok!(MiningRewardsAllowanceTestModule::set_min_bonded_dhx_daily( Origin::root(), min_bonding_dhx_daily.clone(), @@ -401,15 +436,15 @@ fn setup_bonding(amount_bonded_each_miner: u128, min_bonding_dhx_daily: u128) -> // in this test we'll test that it distributes rewards when each of their account balances are very large // (i.e. a third of the total supply) ONE_THIRD_OF_TOTAL_SUPPLY_DHX - assert_ok!(Balances::set_balance(Origin::root(), 1, amount_bonded_each_miner, 0)); - assert_ok!(Balances::set_balance(Origin::root(), 2, amount_bonded_each_miner, 0)); - assert_ok!(Balances::set_balance(Origin::root(), 3, amount_bonded_each_miner, 0)); + assert_ok!(Balances::set_balance(Origin::root(), account_1_account_id.clone(), amount_bonded_each_miner, 0)); + assert_ok!(Balances::set_balance(Origin::root(), account_2_account_id.clone(), amount_bonded_each_miner, 0)); + assert_ok!(Balances::set_balance(Origin::root(), account_3_account_id.clone(), amount_bonded_each_miner, 0)); - assert_eq!(Balances::free_balance(&1), amount_bonded_each_miner); - assert_eq!(Balances::free_balance(&2), amount_bonded_each_miner); - assert_eq!(Balances::free_balance(&3), amount_bonded_each_miner); + assert_eq!(Balances::free_balance(&account_1_account_id.clone()), amount_bonded_each_miner); + assert_eq!(Balances::free_balance(&account_2_account_id.clone()), amount_bonded_each_miner); + assert_eq!(Balances::free_balance(&account_3_account_id.clone()), amount_bonded_each_miner); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::reserved_balance(&account_1_account_id.clone()), 0); let pre_image_hash = BlakeTwo256::hash(b"test"); // params: end block, proposal hash, threshold, delay @@ -446,10 +481,22 @@ fn setup_treasury_balance() { } fn bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner: u128, referendum_index: u32) { + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; + let account_2_public_key = BOB_PUBLIC_KEY; + let account_3_public_key = CHARLIE_PUBLIC_KEY; + + let account_1_account_id: u64 = Decode::decode(&mut account_1_public_key.as_slice().clone()).ok().unwrap(); + let account_2_account_id: u64 = Decode::decode(&mut account_2_public_key.as_slice().clone()).ok().unwrap(); + let account_3_account_id: u64 = Decode::decode(&mut account_3_public_key.as_slice().clone()).ok().unwrap(); + // we're actually bonding with their entire account balance - let b1 = Balances::free_balance(&1); - let b2 = Balances::free_balance(&2); - let b3 = Balances::free_balance(&3); + let b1 = Balances::free_balance(&account_1_account_id.clone()); + let b2 = Balances::free_balance(&account_2_account_id.clone()); + let b3 = Balances::free_balance(&account_3_account_id.clone()); // lock the whole balance of account 1, 2, and 3 in voting let v1a1 = AccountVote::Standard { vote: AYE, balance: b1.clone() }; @@ -457,25 +504,25 @@ fn bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner: u128, refe let v1a3 = AccountVote::Standard { vote: AYE, balance: b3.clone() }; // vote on referenda using time-lock voting with a conviction to scale the vote power // note: second parameter is the referendum index being voted on - assert_ok!(Democracy::vote(Origin::signed(1), referendum_index, v1a1)); - assert_ok!(Democracy::vote(Origin::signed(2), referendum_index, v1a2)); - assert_ok!(Democracy::vote(Origin::signed(3), referendum_index, v1a3)); + assert_ok!(Democracy::vote(Origin::signed(account_1_account_id.clone()), referendum_index, v1a1)); + assert_ok!(Democracy::vote(Origin::signed(account_2_account_id.clone()), referendum_index, v1a2)); + assert_ok!(Democracy::vote(Origin::signed(account_3_account_id.clone()), referendum_index, v1a3)); - assert_eq!(Balances::locks(1)[0], + assert_eq!(Balances::locks(account_1_account_id.clone())[0], BalanceLock { id: [100, 101, 109, 111, 99, 114, 97, 99], amount: b1.clone(), reasons: Reasons::Misc } ); - assert_eq!(Balances::locks(2)[0], + assert_eq!(Balances::locks(account_2_account_id.clone())[0], BalanceLock { id: [100, 101, 109, 111, 99, 114, 97, 99], amount: b2.clone(), reasons: Reasons::Misc } ); - assert_eq!(Balances::locks(3)[0], + assert_eq!(Balances::locks(account_3_account_id.clone())[0], BalanceLock { id: [100, 101, 109, 111, 99, 114, 97, 99], amount: b3.clone(), @@ -485,31 +532,54 @@ fn bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner: u128, refe } fn unbond_each_miner_by_removing_their_referendum_vote(referendum_index: u32) { + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; + let account_2_public_key = BOB_PUBLIC_KEY; + let account_3_public_key = CHARLIE_PUBLIC_KEY; + + let account_1_account_id: u64 = Decode::decode(&mut account_1_public_key.as_slice().clone()).ok().unwrap(); + let account_2_account_id: u64 = Decode::decode(&mut account_2_public_key.as_slice().clone()).ok().unwrap(); + let account_3_account_id: u64 = Decode::decode(&mut account_3_public_key.as_slice().clone()).ok().unwrap(); + // remove the votes and then unlock for each account // note: `remove_vote` must be done before `unlock` - assert_ok!(Democracy::remove_vote(Origin::signed(1), referendum_index)); - assert_ok!(Democracy::remove_vote(Origin::signed(2), referendum_index)); - assert_ok!(Democracy::remove_vote(Origin::signed(3), referendum_index)); + assert_ok!(Democracy::remove_vote(Origin::signed(account_1_account_id.clone()), referendum_index)); + assert_ok!(Democracy::remove_vote(Origin::signed(account_2_account_id.clone()), referendum_index)); + assert_ok!(Democracy::remove_vote(Origin::signed(account_3_account_id.clone()), referendum_index)); // we removed their votes assert_eq!(Democracy::referendum_status(referendum_index).unwrap().tally, Tally { ayes: 0, nays: 0, turnout: 0 }); - assert_ok!(Democracy::unlock(Origin::signed(1), 1)); - assert_ok!(Democracy::unlock(Origin::signed(2), 2)); - assert_ok!(Democracy::unlock(Origin::signed(3), 3)); + assert_ok!(Democracy::unlock(Origin::signed(account_1_account_id.clone()), account_1_account_id.clone())); + assert_ok!(Democracy::unlock(Origin::signed(account_2_account_id.clone()), account_1_account_id.clone())); + assert_ok!(Democracy::unlock(Origin::signed(account_3_account_id.clone()), account_1_account_id.clone())); // check that all accounts are unlocked - assert_eq!(Balances::locks(1), vec![]); - assert_eq!(Balances::locks(2), vec![]); - assert_eq!(Balances::locks(3), vec![]); + assert_eq!(Balances::locks(account_1_account_id.clone()), vec![]); + assert_eq!(Balances::locks(account_2_account_id.clone()), vec![]); + assert_eq!(Balances::locks(account_3_account_id.clone()), vec![]); } fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128) { - let account_1_public_key = vec![1]; - let account_2_public_key = vec![2]; - let account_3_public_key = vec![3]; + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; + let account_2_public_key = BOB_PUBLIC_KEY; + let account_3_public_key = CHARLIE_PUBLIC_KEY; + + let account_1_account_id: u64 = Decode::decode(&mut account_1_public_key.as_slice().clone()).ok().unwrap(); + let account_2_account_id: u64 = Decode::decode(&mut account_2_public_key.as_slice().clone()).ok().unwrap(); + let account_3_account_id: u64 = Decode::decode(&mut account_3_public_key.as_slice().clone()).ok().unwrap(); // since the timestamp is 0 (corresponds to 1970-01-01) at block number #1, we early exit from on_initialize in // that block in the implementation and do not set any storage values associated with the date until block #2. // in the tests we could set the timestamp before we run on_initialize(1), but that wouldn't reflect reality. + + // Note: we early exit from on_initialize and on_finalize in the the implementation since timestamp is 0 + // Timestamp::set_timestamp(0u64); MiningRewardsAllowanceTestModule::on_initialize(1); // IMPORTANT: if we don't set the mpower for each miner for the current date beforehand, we won't be able to accumulate their rewards @@ -559,51 +629,60 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount // a day before we start the new multiplier period and change from 10:1 to 20:1 since no more days remaining assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1630195200000, 2u32, 0u32))); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_1_public_key.clone())), Some(amount_bonded_each_miner)); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); - assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_3_public_key.clone())), Some(amount_bonded_each_miner)); - - // i.e. for example, if locked is 25_133_000_000_000_000_000_000u128 (NORMAL_AMOUNT), which is 25,133 DHX, - // then with 10:1 each of the 3x accounts get 2513.3 DHX, which is ~7538.9 DHX combined - // or 33_333_333_333_000_000_000_000_000u128 (LARGE_AMOUNT_DHX), - // but the results are rounded to the nearest integer so it would be 2513 DHX, not 2513.3 DHX - if amount_bonded_each_miner.clone() == NORMAL_AMOUNT { - assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(7_539_000_000_000_000_000_000u128)); - - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); - } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { - assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(9_999_999_000_000_000_000_000_000u128)); - - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); - } - - assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); - - change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); - - // 30th August 2021 @ ~7am is 1630306800000 - // 30th August 2021 @ 12am is 1630281600000 (start of day) - Timestamp::set_timestamp(1630306800000u64); - MiningRewardsAllowanceTestModule::on_initialize(5); - - // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded - // amount below the min. bonded DHX daily amount - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); - // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX - assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); - // the change between each multiplier period is 10 unless a user sets it to a different value - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); - // start of new multiplier period - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); + // assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_1_public_key.clone())), Some(amount_bonded_each_miner)); + // assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); + // assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_3_public_key.clone())), Some(amount_bonded_each_miner)); + + // // i.e. for example, if locked is 25_133_000_000_000_000_000_000u128 (NORMAL_AMOUNT), which is 25,133 DHX, + // // then with 10:1 each of the 3x accounts get 2513.3 DHX, which is ~7538.9 DHX combined + // // or 33_333_333_333_000_000_000_000_000u128 (LARGE_AMOUNT_DHX), + // // but the results are rounded to the nearest integer so it would be 2513 DHX, not 2513.3 DHX + // if amount_bonded_each_miner.clone() == NORMAL_AMOUNT { + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(7_539_000_000_000_000_000_000u128)); + + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); + // } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(9_999_999_000_000_000_000_000_000u128)); + + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); + // } + + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); + + // change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); + + // // 30th August 2021 @ ~7am is 1630306800000 + // // 30th August 2021 @ 12am is 1630281600000 (start of day) + // Timestamp::set_timestamp(1630306800000u64); + // MiningRewardsAllowanceTestModule::on_initialize(5); + + // // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded + // // amount below the min. bonded DHX daily amount + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); + // // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX + // assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); + // // the change between each multiplier period is 10 unless a user sets it to a different value + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); + // // start of new multiplier period + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); + + + + + + + + + // Note - these are just notes. no further action required // Note - why is this 2u128 instead of reset back to say 5000u128 DHX (unless set do different value?? @@ -622,9 +701,13 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount } fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { - let account_1_public_key = vec![1]; - let account_2_public_key = vec![2]; - let account_3_public_key = vec![3]; + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; + let account_2_public_key = BOB_PUBLIC_KEY; + let account_3_public_key = CHARLIE_PUBLIC_KEY; change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630368000000i64); @@ -661,9 +744,13 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { } fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_bonded(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - let account_1_public_key = vec![1]; - let account_2_public_key = vec![2]; - let account_3_public_key = vec![3]; + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; + let account_2_public_key = BOB_PUBLIC_KEY; + let account_3_public_key = CHARLIE_PUBLIC_KEY; change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630627200000i64); @@ -723,7 +810,11 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b } fn check_cooling_off_period_starts_again_if_sufficient_bonded_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - let account_1_public_key = vec![1]; + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner, referendum_index); @@ -743,7 +834,11 @@ fn check_cooling_off_period_starts_again_if_sufficient_bonded_again(amount_bonde } fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_mpower(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - let account_1_public_key = vec![1]; + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; // no mpower to check they'll be ineligible for rewards change_mpower_for_each_miner(0u128, 1630886400000i64); @@ -769,7 +864,11 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_m } fn check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - let account_1_public_key = vec![1]; + let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; + let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; + let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; + + let account_1_public_key = ALICE_PUBLIC_KEY; // reset mpower to what it was change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1631059200000i64); From d99afd428cc2554cf6c9e18765ac3699e400fbee Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 9 Dec 2021 07:23:31 +0100 Subject: [PATCH 27/37] wip --- pallets/mining/rewards-allowance/src/tests.rs | 112 +++++------------- 1 file changed, 32 insertions(+), 80 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index acd6bdd4c..01e2688b4 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -28,24 +28,20 @@ const THIRTY_DHX: u128 = 30_000_000_000_000_000_000_u128; // 30 const TWENTY_DHX: u128 = 20_000_000_000_000_000_000_u128; // 20 const TWO_DHX: u128 = 2_000_000_000_000_000_000_u128; // 2 -// FIXME - do something like this so i can use constant in each unit test and replace all the duplication -// https://stackoverflow.com/a/58009990/3208553 -// const ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; -// const BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; -// const CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; +// TODO - try doing the following if necessary https://stackoverflow.com/a/58009990/3208553 +// Note: we have to use `&[u8] = &` instead of `Vec = vec!` otherwise we get error `allocations are not allowed in constants` +const ALICE_PUBLIC_KEY: &[u8] = &[212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; +const BOB_PUBLIC_KEY: &[u8] = &[142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; +const CHARLIE_PUBLIC_KEY: &[u8] = &[144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; #[test] // ignore this test until the FIXME is resolved #[ignore] fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_if_not_already_set_for_today() { new_test_ext().execute_with(|| { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( Origin::root(), - vec![CHARLIE_PUBLIC_KEY, BOB_PUBLIC_KEY, ALICE_PUBLIC_KEY], + vec![CHARLIE_PUBLIC_KEY.into(), BOB_PUBLIC_KEY.into(), ALICE_PUBLIC_KEY.into()], )); // 27th August 2021 @ ~7am is 1630049371000 @@ -340,13 +336,9 @@ fn it_checks_if_is_more_than_challenge_period() { } fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( Origin::root(), - vec![CHARLIE_PUBLIC_KEY.clone(), BOB_PUBLIC_KEY.clone(), ALICE_PUBLIC_KEY.clone()], + vec![CHARLIE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), ALICE_PUBLIC_KEY.clone().into()], )); assert_ok!(MiningRewardsAllowanceTestModule::set_cooling_off_period_days( @@ -358,7 +350,7 @@ fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: FIVE_THOUSAND_DHX, )); - assert_eq!(MiningRewardsAllowanceTestModule::registered_dhx_miners(), Some(vec![ALICE_PUBLIC_KEY, BOB_PUBLIC_KEY, CHARLIE_PUBLIC_KEY])); + assert_eq!(MiningRewardsAllowanceTestModule::registered_dhx_miners(), Some(vec![ALICE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), CHARLIE_PUBLIC_KEY.clone().into()])); assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days(), Some(1)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_daily(), Some(FIVE_THOUSAND_DHX)); @@ -383,13 +375,9 @@ fn setup_min_mpower_daily(min_mpower_daily: u128) { // we have to get their mpower the day before we check if they are eligible incase there are delays in getting the off-chain data fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, start_date: i64) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; - let account_2_public_key = BOB_PUBLIC_KEY; - let account_3_public_key = CHARLIE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); + let account_2_public_key: Vec = BOB_PUBLIC_KEY.clone().into(); + let account_3_public_key: Vec = CHARLIE_PUBLIC_KEY.clone().into(); // https://aws1.discourse-cdn.com/business5/uploads/rust_lang/original/3X/9/0/909baa7e3d9569489b07c791ca76f2223bd7bac2.webp assert_ok!(MiningRewardsAllowanceTestModule::change_mpower_of_account_for_date(Origin::root(), account_1_public_key.clone(), start_date.clone(), amount_mpower_each_miner.clone())); @@ -410,13 +398,9 @@ fn change_mpower_for_each_miner(amount_mpower_each_miner: u128, start_date: i64) } fn setup_bonding(amount_bonded_each_miner: u128, min_bonding_dhx_daily: u128) -> u32 { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; - let account_2_public_key = BOB_PUBLIC_KEY; - let account_3_public_key = CHARLIE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); + let account_2_public_key: Vec = BOB_PUBLIC_KEY.clone().into(); + let account_3_public_key: Vec = CHARLIE_PUBLIC_KEY.clone().into(); let account_1_account_id: u64 = Decode::decode(&mut account_1_public_key.as_slice().clone()).ok().unwrap(); let account_2_account_id: u64 = Decode::decode(&mut account_2_public_key.as_slice().clone()).ok().unwrap(); @@ -481,13 +465,9 @@ fn setup_treasury_balance() { } fn bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner: u128, referendum_index: u32) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; - let account_2_public_key = BOB_PUBLIC_KEY; - let account_3_public_key = CHARLIE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); + let account_2_public_key: Vec = BOB_PUBLIC_KEY.clone().into(); + let account_3_public_key: Vec = CHARLIE_PUBLIC_KEY.clone().into(); let account_1_account_id: u64 = Decode::decode(&mut account_1_public_key.as_slice().clone()).ok().unwrap(); let account_2_account_id: u64 = Decode::decode(&mut account_2_public_key.as_slice().clone()).ok().unwrap(); @@ -532,13 +512,9 @@ fn bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner: u128, refe } fn unbond_each_miner_by_removing_their_referendum_vote(referendum_index: u32) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; - let account_2_public_key = BOB_PUBLIC_KEY; - let account_3_public_key = CHARLIE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); + let account_2_public_key: Vec = BOB_PUBLIC_KEY.clone().into(); + let account_3_public_key: Vec = CHARLIE_PUBLIC_KEY.clone().into(); let account_1_account_id: u64 = Decode::decode(&mut account_1_public_key.as_slice().clone()).ok().unwrap(); let account_2_account_id: u64 = Decode::decode(&mut account_2_public_key.as_slice().clone()).ok().unwrap(); @@ -562,13 +538,9 @@ fn unbond_each_miner_by_removing_their_referendum_vote(referendum_index: u32) { } fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; - let account_2_public_key = BOB_PUBLIC_KEY; - let account_3_public_key = CHARLIE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); + let account_2_public_key: Vec = BOB_PUBLIC_KEY.clone().into(); + let account_3_public_key: Vec = CHARLIE_PUBLIC_KEY.clone().into(); let account_1_account_id: u64 = Decode::decode(&mut account_1_public_key.as_slice().clone()).ok().unwrap(); let account_2_account_id: u64 = Decode::decode(&mut account_2_public_key.as_slice().clone()).ok().unwrap(); @@ -701,13 +673,9 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount } fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; - let account_2_public_key = BOB_PUBLIC_KEY; - let account_3_public_key = CHARLIE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); + let account_2_public_key: Vec = BOB_PUBLIC_KEY.clone().into(); + let account_3_public_key: Vec = CHARLIE_PUBLIC_KEY.clone().into(); change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630368000000i64); @@ -744,13 +712,9 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { } fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_bonded(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; - let account_2_public_key = BOB_PUBLIC_KEY; - let account_3_public_key = CHARLIE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); + let account_2_public_key: Vec = BOB_PUBLIC_KEY.clone().into(); + let account_3_public_key: Vec = CHARLIE_PUBLIC_KEY.clone().into(); change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630627200000i64); @@ -810,11 +774,7 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b } fn check_cooling_off_period_starts_again_if_sufficient_bonded_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner, referendum_index); @@ -834,11 +794,7 @@ fn check_cooling_off_period_starts_again_if_sufficient_bonded_again(amount_bonde } fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_mpower(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); // no mpower to check they'll be ineligible for rewards change_mpower_for_each_miner(0u128, 1630886400000i64); @@ -864,11 +820,7 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_m } fn check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - let ALICE_PUBLIC_KEY: Vec = vec![212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]; - let BOB_PUBLIC_KEY: Vec = vec![142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72]; - let CHARLIE_PUBLIC_KEY: Vec = vec![144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; - - let account_1_public_key = ALICE_PUBLIC_KEY; + let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); // reset mpower to what it was change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1631059200000i64); From cce66c09af6d5c6cbb0bcfad4bd7ce73ea3e4f42 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 9 Dec 2021 07:40:43 +0100 Subject: [PATCH 28/37] fix linting from past couple of commits --- pallets/mining/rewards-allowance/src/lib.rs | 42 ++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index eef1935c4..785ee0fd8 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -881,22 +881,22 @@ pub mod pallet { start_of_requested_date_millis.clone(), mpower_data_vec.clone() ); - log::info!("offchain_worker - finished store_mpower_raw_unsigned at block: {:?}", block_number.clone()); + log::info!("offchain_worker - finished store_mpower_raw_unsigned at block: {:?}", block_number.clone()); if let Err(e) = res_store_mpower { - log::error!("offchain_worker - offchain_workers error storing mpower: {}", e); - } + log::error!("offchain_worker - offchain_workers error storing mpower: {}", e); + } let res_store_finished = Self::store_finished_fetching_mpower_raw_unsigned( block_number.clone(), fetched_mpower_data.clone() ); log::info!("offchain_worker - finished store_finished_fetching_mpower_raw_unsigned at block: {:?}", block_number.clone()); - if let Err(e) = res_store_finished { - log::error!("offchain_worker - offchain_workers error storing finished fetching mpower: {}", e); - } + if let Err(e) = res_store_finished { + log::error!("offchain_worker - offchain_workers error storing finished fetching mpower: {}", e); + } return; - } + } // `on_initialize` is executed at the beginning of the block before any extrinsic are // dispatched. @@ -2686,28 +2686,28 @@ pub mod pallet { } } - #[pallet::validate_unsigned] - impl ValidateUnsigned for Pallet { - type Call = Call; + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; - /// Validate unsigned call to this module. - /// - /// By default unsigned transactions are disallowed, but implementing the validator - /// here we make sure that some particular calls (the ones produced by offchain worker) - /// are being whitelisted and marked as valid. - fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { + /// Validate unsigned call to this module. + /// + /// By default unsigned transactions are disallowed, but implementing the validator + /// here we make sure that some particular calls (the ones produced by offchain worker) + /// are being whitelisted and marked as valid. + fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { if let Call::submit_fetched_mpower_unsigned(block_number, start_of_requested_date_millis, new_mpower_data_vec) = call { - log::info!("validate_unsigned submit_fetched_mpower_unsigned"); + log::info!("validate_unsigned submit_fetched_mpower_unsigned"); return Self::validate_transaction_parameters_for_fetched_mpower(block_number, start_of_requested_date_millis, new_mpower_data_vec); } else if let Call::submit_finished_fetching_mpower_unsigned(block_number, fetched_mpower_data) = call { log::info!("validate_unsigned validate_transaction_parameters_for_fetched_mpower"); return Self::validate_transaction_parameters_for_finished_fetching_mpower(block_number, fetched_mpower_data); } else { log::info!("validate_unsigned invalid"); - return InvalidTransaction::Call.into(); - } - } - } + return InvalidTransaction::Call.into(); + } + } + } // Private functions From b75288c08221defe7aa7fc07db77c7b95a6b0a57 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 9 Dec 2021 12:09:42 +0100 Subject: [PATCH 29/37] wip - fix so not early exit if RewardsEligibleMinersForDate not exist --- pallets/mining/rewards-allowance/src/lib.rs | 17 +++++++++++++++-- pallets/mining/rewards-allowance/src/tests.rs | 4 ++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 785ee0fd8..2db82a809 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -1741,6 +1741,7 @@ pub mod pallet { new_rewards_aggregated_dhx_daily.clone(), ); log::info!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); + // println!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); // add to storage item that maps the date to the registered miner and the calculated reward // (prior to possibly reducing it so they get a proportion of the daily rewards that are available) @@ -1752,6 +1753,7 @@ pub mod pallet { daily_reward_for_miner.clone(), ); log::info!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); + // println!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); // Store a list of all the the registered_dhx_miners that are eligible for rewards on a given date // so we know they have been used as keys for other storage maps like `RewardsAccumulatedDHXForMinerForDate` @@ -1760,9 +1762,14 @@ pub mod pallet { if let Some(_rewards_eligible_miners_for_date) = >::get(start_of_requested_date_millis.clone()) { rewards_eligible_miners_for_date = _rewards_eligible_miners_for_date; } else { - log::error!("Unable to retrieve rewards_eligible_miners_for_date"); - return 0; + log::warn!("Unable to retrieve rewards_eligible_miners_for_date"); + // println!("Unable to retrieve rewards_eligible_miners_for_date"); } + log::info!("Retrieved existing rewards_eligible_miners_for_date {:?} {:?}", start_of_requested_date_millis.clone(), rewards_eligible_miners_for_date.clone()); + // println!("Retrieved existing rewards_eligible_miners_for_date {:?} {:?}", start_of_requested_date_millis.clone(), rewards_eligible_miners_for_date.clone()); + + log::warn!("Updating rewards_eligible_miners_for_date with miner {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone()); + // println!("Updating retrieve rewards_eligible_miners_for_date with miner {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone()); rewards_eligible_miners_for_date.push(miner_public_key.clone()); >::insert( @@ -1770,9 +1777,11 @@ pub mod pallet { rewards_eligible_miners_for_date.clone(), ); + log::info!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); // println!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); // if last miner being iterated then reset for next day if reg_dhx_miners.len() == miner_count { + log::info!("date: {:?}, rewards_allowance_dhx_daily: {:?}", start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); // println!("date: {:?}, rewards_allowance_dhx_daily: {:?}", start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); // reset to latest set by governance @@ -1800,6 +1809,7 @@ pub mod pallet { ); log::info!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_off_period_days.clone()); + // println!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_off_period_days.clone()); // if cooling_off_period_days_remaining.0 is not the start of the current date // (since if they just started un-bonding or just had less than min. mPower @@ -1829,6 +1839,8 @@ pub mod pallet { match _new_cooling_off_period_days_remaining { None => { log::error!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); + // println!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); + return 0; }, Some(x) => { @@ -1872,6 +1884,7 @@ pub mod pallet { ); log::info!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); + // println!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); } } diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 01e2688b4..ba9971f79 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -601,8 +601,8 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount // a day before we start the new multiplier period and change from 10:1 to 20:1 since no more days remaining assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1630195200000, 2u32, 0u32))); - // assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_1_public_key.clone())), Some(amount_bonded_each_miner)); - // assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_1_public_key.clone())), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); // assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_3_public_key.clone())), Some(amount_bonded_each_miner)); // // i.e. for example, if locked is 25_133_000_000_000_000_000_000u128 (NORMAL_AMOUNT), which is 25,133 DHX, From c0c8a048794b80a8a7ce2add3170d1f731652bbf Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 9 Dec 2021 12:26:14 +0100 Subject: [PATCH 30/37] wip - remove ignored tests, restore some more tests that work again now --- pallets/mining/rewards-allowance/src/tests.rs | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index ba9971f79..4c81a06b5 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -35,8 +35,6 @@ const BOB_PUBLIC_KEY: &[u8] = &[142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, const CHARLIE_PUBLIC_KEY: &[u8] = &[144, 181, 171, 32, 92, 105, 116, 201, 234, 132, 27, 230, 136, 134, 70, 51, 220, 156, 168, 163, 87, 132, 62, 234, 207, 35, 20, 100, 153, 101, 254, 34]; #[test] -// ignore this test until the FIXME is resolved -#[ignore] fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_if_not_already_set_for_today() { new_test_ext().execute_with(|| { assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( @@ -53,8 +51,7 @@ fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_ MiningRewardsAllowanceTestModule::on_initialize(2); // MiningRewardsAllowanceTestModule::offchain_worker(2); - // FIXME - why doesn't this work and use the defaults that we have set in the genesis config? - // i've had to add a function `set_rewards_allowance_dhx_daily` to set this instead + // This wasn't using the defaults set in genesis config previously because we weren't starting at block 2 assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_daily(), Some(FIVE_THOUSAND_DHX)); }) } @@ -294,11 +291,8 @@ fn it_sets_min_mpower_daily() { } #[test] -#[ignore] fn it_allows_us_to_retrieve_genesis_value_for_min_mpower_daily() { new_test_ext().execute_with(|| { - // FIXME - why doesn't it set the values we added in the chain_spec.rs at genesis - // https://matrix.to/#/!HzySYSaIhtyWrwiwEV:matrix.org/$163424903366086IiiUH:matrix.org?via=matrix.parity.io&via=corepaper.org&via=matrix.org // Note: we start at block 2 since we early exit from block 1 because the timestamp is yet MiningRewardsAllowanceTestModule::on_initialize(2); assert_eq!(MiningRewardsAllowanceTestModule::min_mpower_daily(), Some(5u128)); @@ -603,25 +597,25 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_1_public_key.clone())), Some(amount_bonded_each_miner)); assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); - // assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_3_public_key.clone())), Some(amount_bonded_each_miner)); - - // // i.e. for example, if locked is 25_133_000_000_000_000_000_000u128 (NORMAL_AMOUNT), which is 25,133 DHX, - // // then with 10:1 each of the 3x accounts get 2513.3 DHX, which is ~7538.9 DHX combined - // // or 33_333_333_333_000_000_000_000_000u128 (LARGE_AMOUNT_DHX), - // // but the results are rounded to the nearest integer so it would be 2513 DHX, not 2513.3 DHX - // if amount_bonded_each_miner.clone() == NORMAL_AMOUNT { - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(7_539_000_000_000_000_000_000u128)); - - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); - // } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(9_999_999_000_000_000_000_000_000u128)); - - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); - // } + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_3_public_key.clone())), Some(amount_bonded_each_miner)); + + // i.e. for example, if locked is 25_133_000_000_000_000_000_000u128 (NORMAL_AMOUNT), which is 25,133 DHX, + // then with 10:1 each of the 3x accounts get 2513.3 DHX, which is ~7538.9 DHX combined + // or 33_333_333_333_000_000_000_000_000u128 (LARGE_AMOUNT_DHX), + // but the results are rounded to the nearest integer so it would be 2513 DHX, not 2513.3 DHX + if amount_bonded_each_miner.clone() == NORMAL_AMOUNT { + assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(7_539_000_000_000_000_000_000u128)); + + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); + } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { + assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(9_999_999_000_000_000_000_000_000u128)); + + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); + } // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); From 0fbd3ecec49722b6d901f1a94a0544e97d4b044f Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 10 Dec 2021 09:22:01 +0100 Subject: [PATCH 31/37] all tests working again using off-chain workers now --- pallets/mining/rewards-allowance/src/lib.rs | 71 +++++++++++++++++- pallets/mining/rewards-allowance/src/tests.rs | 74 +++++++++++-------- 2 files changed, 109 insertions(+), 36 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 2db82a809..641776ecc 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -2177,9 +2177,22 @@ pub mod pallet { // TODO - add change_finished_fetching_mpower_for_accounts_for_date #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn claim_rewards_of_account_for_date(origin: OriginFor, start_of_requested_date_millis: Date) -> DispatchResult { + pub fn claim_rewards_of_account_for_date( + origin: OriginFor, + miner_public_key: Vec, // we need to ensure this is the same account as the origin + start_of_requested_date_millis: Date + ) -> DispatchResult { let _sender = ensure_signed(origin)?; - let miner_public_key = _sender.encode(); + + // FIXME - these need to be the same, or ideally we need to find out how to get the public key associated with the origin + // and not need to pass the miner_public_key as 2nd parameter at all. + // + // https://github.com/paritytech/subport/issues/290 + // assert_eq!(_sender.clone(), miner_public_key.clone()); + + log::info!("claim_rewards_of_account_for_date - miner_public_key: {:?} {:?}", miner_public_key.clone(), start_of_requested_date_millis.clone()); + // println!("claim_rewards_of_account_for_date - miner_public_key: {:?} {:?}", miner_public_key.clone(), start_of_requested_date_millis.clone()); + let block_number = >::block_number(); // check that the current date start_of_current_date_millis is at least 7 days after the provided start_of_requested_date_millis @@ -2205,10 +2218,14 @@ pub mod pallet { let _is_more_than_challenge_period = Self::is_more_than_challenge_period(start_of_requested_date_millis.clone()); match _is_more_than_challenge_period.clone() { Err(_e) => { - log::error!("{:?}", _e); + log::error!("Unable to claim until after waiting the challenge period {:?}", _e); + // println!("Unable to claim until after waiting the challenge period {:?}", _e); + return Err(_e); }, Ok(x) => { + log::info!("Proceeding since waited at least the challenge period"); + // println!("Proceeding since waited at least the challenge period"); is_more_than_challenge_period = x; } } @@ -2223,6 +2240,7 @@ pub mod pallet { rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; } else { log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet"); + // println!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet"); // Note: it would be an issue if we got past the first loop of looping through the registered miners // and still hadn't added to the aggregated rewards for the day return Err(DispatchError::Other("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet")); @@ -2231,6 +2249,7 @@ pub mod pallet { if rewards_aggregated_dhx_daily == 0u32.into() { log::error!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); + // println!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); return Err(DispatchError::Other("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards")); } @@ -2239,6 +2258,7 @@ pub mod pallet { match _rewards_aggregated_dhx_daily_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); + // println!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); return Err(DispatchError::Other("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128")); }, Ok(x) => { @@ -2246,6 +2266,7 @@ pub mod pallet { } } log::info!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); + // println!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); // TODO - we've done this twice, create a function to fetch it let rewards_allowance_dhx_daily; @@ -2253,6 +2274,7 @@ pub mod pallet { rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; } else { log::error!("Unable to get rewards_allowance_dhx_daily"); + // println!("Unable to get rewards_allowance_dhx_daily"); return Err(DispatchError::Other("Unable to get rewards_allowance_dhx_daily")); } @@ -2261,6 +2283,7 @@ pub mod pallet { match _rewards_allowance_dhx_daily_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); + // println!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); return Err(DispatchError::Other("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128")); }, Ok(x) => { @@ -2270,6 +2293,7 @@ pub mod pallet { if rewards_allowance_dhx_daily_u128 == 0u128 { log::error!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); + // println!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); return Err(DispatchError::Other("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards")); } @@ -2308,6 +2332,7 @@ pub mod pallet { manageable_rewards_allowance_dhx_daily_u128 = _manageable_rewards_allowance_dhx_daily_u128; } else { log::error!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); + // println!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); return Err(DispatchError::Other("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller")); } @@ -2317,6 +2342,7 @@ pub mod pallet { rewards_allowance_dhx_daily_u64 = _rewards_allowance_dhx_daily_u64; } else { log::error!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); + // println!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); return Err(DispatchError::Other("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128")); } @@ -2325,6 +2351,7 @@ pub mod pallet { manageable_rewards_aggregated_dhx_daily_as_u128 = _manageable_rewards_aggregated_dhx_daily_as_u128; } else { log::error!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); + // println!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); return Err(DispatchError::Other("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller")); } @@ -2334,6 +2361,7 @@ pub mod pallet { rewards_aggregated_dhx_daily_as_u64 = _rewards_aggregated_dhx_daily_as_u64; } else { log::error!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); + // println!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); return Err(DispatchError::Other("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128")); } @@ -2345,6 +2373,7 @@ pub mod pallet { match _distribution_multiplier_for_day_fixed128 { None => { log::error!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); + // println!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); return Err(DispatchError::Other("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128")); }, Some(x) => { @@ -2353,12 +2382,14 @@ pub mod pallet { } } log::info!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); + // println!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); + + log::info!("[multiplier] block: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); // println!("[multiplier] block: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); // Initialise outside the loop as we need this value after the loop after we finish iterating through all the miners let mut rewards_allowance_dhx_remaining_today_as_u128 = 0u128; - // only run the following once per day per miner until rewards_allowance_dhx_for_date_remaining is exhausted // but since we're giving each registered miner a proportion of the daily reward allowance // (if their aggregated rewards is above daily allowance) each proportion is rounded down, @@ -2377,6 +2408,7 @@ pub mod pallet { ); if is_already_distributed_to_miner == Some(true) { log::error!("Unable to distribute further rewards allowance to the registered dhx miner for this day"); + // println!("Unable to distribute further rewards allowance to the registered dhx miner for this day"); return Err(DispatchError::Other("Unable to distribute further rewards allowance to the registered dhx miner for this day")); } @@ -2392,6 +2424,7 @@ pub mod pallet { match _daily_reward_for_miner_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128 for daily_reward_for_miner_as_u128"); + // println!("Unable to distribute further rewards allowance to the registered dhx miner for this day"); return Err(DispatchError::Other("Unable to convert balance to u128 for daily_reward_for_miner_as_u128")); }, Ok(x) => { @@ -2402,9 +2435,11 @@ pub mod pallet { // If any of the miner's don't have a reward, we won't waste storing that, // so we want to move to the next miner in the loop log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); + // println!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); return Err(DispatchError::Other("Unable to retrieve reward balance for daily_reward_for_miner")); } log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); + // println!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); let mut manageable_daily_reward_for_miner_as_u128 = 0u128; if let Some(_manageable_daily_reward_for_miner_as_u128) = @@ -2412,6 +2447,7 @@ pub mod pallet { manageable_daily_reward_for_miner_as_u128 = _manageable_daily_reward_for_miner_as_u128; } else { log::error!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); + // println!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); return Err(DispatchError::Other("Unable to divide daily_reward_for_miner_as_u128 to make it smaller")); } @@ -2426,6 +2462,7 @@ pub mod pallet { match _proportion_of_daily_reward_for_miner_fixed128 { None => { log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); + // println!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); return Err(DispatchError::Other("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow")); }, Some(x) => { @@ -2433,6 +2470,7 @@ pub mod pallet { } } log::info!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); + // println!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); // round down to nearest integer. we need to round down, because if we round up then if there are // 3x registered miners with 5000 DHX rewards allowance per day then they would each get 1667 rewards, @@ -2447,9 +2485,11 @@ pub mod pallet { restored_proportion_of_daily_reward_for_miner_u128 = _restored_proportion_of_daily_reward_for_miner_u128; } else { log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); + // println!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); return Err(DispatchError::Other("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again")); } + log::info!("[rewards] block: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); // println!("[rewards] block: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); let treasury_account_id: T::AccountId = >::account_id(); @@ -2457,12 +2497,16 @@ pub mod pallet { log::info!("Treasury account id: {:?}", treasury_account_id.clone()); log::info!("Miner to receive reward: {:?}", miner_public_key.clone()); log::info!("Treasury balance max payout: {:?}", max_payout.clone()); + // println!("Treasury account id: {:?}", treasury_account_id.clone()); + // println!("Miner to receive reward: {:?}", miner_public_key.clone()); + // println!("Treasury balance max payout: {:?}", max_payout.clone()); let proportion_of_daily_reward_for_miner; let _proportion_of_daily_reward_for_miner = Self::convert_u128_to_balance(restored_proportion_of_daily_reward_for_miner_u128.clone()); match _proportion_of_daily_reward_for_miner { Err(_e) => { log::error!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); + // println!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); return Err(DispatchError::Other("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner")); }, Ok(ref x) => { @@ -2475,9 +2519,11 @@ pub mod pallet { max_payout_as_u128 = _max_payout_as_u128; } else { log::error!("Unable to convert Balance to u128 for max_payout"); + // println!("Unable to convert Balance to u128 for max_payout"); return Err(DispatchError::Other("Unable to convert Balance to u128 for max_payout")); } log::info!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); + // println!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); // TODO - rename `rewards_allowance_dhx_remaining_today` to // `rewards_allowance_dhx_remaining_for_date_rewards_being_claimed` @@ -2489,6 +2535,7 @@ pub mod pallet { match _rewards_allowance_dhx_remaining_today_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128"); + // println!("Unable to convert balance to u128"); return Err(DispatchError::Other("Unable to convert balance to u128")); }, Ok(x) => { @@ -2496,11 +2543,14 @@ pub mod pallet { } } log::info!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); + // println!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); } else { log::error!("Unable to retrieve balance from value provided."); + // println!("Unable to retrieve balance from value provided."); return Err(DispatchError::Other("Unable to retrieve balance from value provided.")); } + log::info!("[prepared-for-payment] block: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); // println!("[prepared-for-payment] block: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); // check if miner's reward is less than or equal to: rewards_allowance_dhx_daily_remaining @@ -2510,6 +2560,7 @@ pub mod pallet { { // pay the miner their daily reward info!("Paying the miner a proportion of the remaining daily reward allowance"); + // println!("Paying the miner a proportion of the remaining daily reward allowance"); let tx_result; let _tx_result = ::Currency::transfer( @@ -2528,8 +2579,10 @@ pub mod pallet { } } info!("Transfer to the miner tx_result: {:?}", tx_result.clone()); + // println!("Transfer to the miner tx_result: {:?}", tx_result.clone()); info!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); + // println!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); // TODO - move into function `reduce_rewards_allowance_dhx_for_date_remaining`? @@ -2540,6 +2593,7 @@ pub mod pallet { match _new_rewards_allowance_dhx_remaining_today_as_u128 { None => { log::error!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); + // println!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); return Err(DispatchError::Other("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow")); }, Some(x) => { @@ -2552,6 +2606,7 @@ pub mod pallet { match _new_rewards_allowance_dhx_remaining_today { Err(_e) => { log::error!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); + // println!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); return Err(DispatchError::Other("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today")); }, Ok(ref x) => { @@ -2565,6 +2620,7 @@ pub mod pallet { new_rewards_allowance_dhx_remaining_today.clone(), ); + log::info!("[paid] block: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); // println!("[paid] block: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); >::insert( @@ -2589,8 +2645,13 @@ pub mod pallet { new_rewards_allowance_dhx_remaining_today.clone(), miner_public_key.clone(), ); + // do not split this across multiple lines otherwise not as easy to find/replace `println` with `// println` when + // switching between running tests with `println` and building the code with `cargo build --release` that doesn't + // work with println + // println!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", start_of_requested_date_millis.clone(), proportion_of_daily_reward_for_miner.clone(), new_rewards_allowance_dhx_remaining_today.clone(), miner_public_key.clone()); } else { log::error!("Insufficient remaining rewards allowance to pay daily reward to miner"); + // println!("Insufficient remaining rewards allowance to pay daily reward to miner"); return Err(DispatchError::Other("Insufficient remaining rewards allowance to pay daily reward to miner")); } @@ -2599,6 +2660,7 @@ pub mod pallet { match _rewards_allowance_dhx_remaining_today { Err(_e) => { log::error!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); + // println!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); return Err(DispatchError::Other("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today")); }, Ok(ref x) => { @@ -2606,6 +2668,7 @@ pub mod pallet { } } + log::info!("[distributed] block: {:#?}, date_start: {:#?} ", block_number, start_of_requested_date_millis); // println!("[distributed] block: {:#?}, date_start: {:#?} ", block_number, start_of_requested_date_millis); Self::deposit_event(Event::DistributedRewardsAllowanceDHXForDateRemaining( diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 4c81a06b5..80e20a94d 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -157,6 +157,7 @@ fn setup_preimage() { assert_eq!(Balances::free_balance(1), 1_000_000_000_000_000); // register pre-image for upcoming proposal let encoded_proposal_preimage = vec![0; 500]; + // TODO - should this be account_1_account_id instead of `1`, and likewise in the rest of this test? match Democracy::note_preimage(Origin::signed(1), encoded_proposal_preimage.clone()) { Ok(_) => (), // Err(x) if x == Error::::DuplicatePreimage.into() => (), @@ -617,38 +618,52 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); } - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); - // assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); - - // change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); - - // // 30th August 2021 @ ~7am is 1630306800000 - // // 30th August 2021 @ 12am is 1630281600000 (start of day) - // Timestamp::set_timestamp(1630306800000u64); - // MiningRewardsAllowanceTestModule::on_initialize(5); - - // // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded - // // amount below the min. bonded DHX daily amount - // assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); - // // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX - // assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); - // // the change between each multiplier period is 10 unless a user sets it to a different value - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); - // // start of new multiplier period - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); - - + // we'll get all three of the registered dhx miners to claim their rewards + assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + Origin::signed(account_1_account_id.clone()), + account_1_public_key.clone(), + 1630195200000 + )); + assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + Origin::signed(account_2_account_id.clone()), + account_2_public_key.clone(), + 1630195200000 + )); + assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + Origin::signed(account_3_account_id.clone()), + account_3_public_key.clone(), + 1630195200000 + )); + // after all the registered dhx miners have claimed their rewards this is the amount that should be remaining from the allocated dhx for the date + assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); + // TODO - each registered dhx miner is claiming rewards now instead of the rewards being automatically distributed, + // see notes in the implementation lib.rs + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); + // 30th August 2021 @ ~7am is 1630306800000 + // 30th August 2021 @ 12am is 1630281600000 (start of day) + Timestamp::set_timestamp(1630306800000u64); + MiningRewardsAllowanceTestModule::on_initialize(5); + // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded + // amount below the min. bonded DHX daily amount + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); + // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX + assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); + // the change between each multiplier period is 10 unless a user sets it to a different value + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); + // start of new multiplier period + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); // Note - these are just notes. no further action required // Note - why is this 2u128 instead of reset back to say 5000u128 DHX (unless set do different value?? @@ -656,14 +671,9 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount // since distribution/claiming may not be done by a user each day // Update: it gets reset but difficult to add a test, have to run the logs with only one test running to see it gets accumulated/aggregated // to all miners each day over a few days - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630281600000), Some(FIVE_THOUSAND_DHX)); - // Note - why is this 'true' when the day just started and nothing has been distributed? - // Update: difficult to add a test, check it works using the logs. they will be claiming rewards anyway, so we need separate tests for that + assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630281600000), Some(FIVE_THOUSAND_DHX)); + // TODO - see other notes about status of using `rewards_allowance_dhx_for_date_remaining_distributed` in future. // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630281600000), Some(false)); - // Note - why haven't these been reset to 0u128 for the next day? - // Update: difficult to add a test to check they are reset before next day, just check it works using the logs. - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630281600000), Some(0u128)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630281600000, 1)), Some(0u128)); } fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { From 1171540be607a313b677c7f317e24fe4bc280417 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 10 Dec 2021 11:27:46 +0100 Subject: [PATCH 32/37] change to min. mpower of 1 --- node/src/chain_spec.rs | 8 +++---- pallets/mining/rewards-allowance/src/lib.rs | 24 +++++++++---------- pallets/mining/rewards-allowance/src/mock.rs | 4 ++-- pallets/mining/rewards-allowance/src/tests.rs | 8 +++---- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index ec306d7a3..c39b5ae78 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -947,8 +947,8 @@ fn testnet_genesis( rewards_accumulated_dhx_for_miner_for_date: Default::default(), min_bonded_dhx_daily: TEN, // 10 DHX min_bonded_dhx_daily_default: TEN, // 10 DHX - min_mpower_daily: 5u128, - min_mpower_daily_default: 5u128, + min_mpower_daily: 1u128, + min_mpower_daily_default: 1u128, challenge_period_days: 7u64, cooling_off_period_days: 7u32, cooling_off_period_days_remaining: vec![ @@ -1094,8 +1094,8 @@ fn mainnet_genesis( rewards_accumulated_dhx_for_miner_for_date: Default::default(), min_bonded_dhx_daily: TEN, // 10 DHX min_bonded_dhx_daily_default: TEN, // 10 DHX - min_mpower_daily: 5u128, - min_mpower_daily_default: 5u128, + min_mpower_daily: 1u128, + min_mpower_daily_default: 1u128, challenge_period_days: 7u64, cooling_off_period_days: 7u32, cooling_off_period_days_remaining: vec![ diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 641776ecc..86df1cff2 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -810,12 +810,6 @@ pub mod pallet { log::info!("offchain_worker - start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); // println!("offchain_worker - start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); - // TODO - fetch the mpower from off-chain and store it with `set_mpower_of_account_for_date` - // but only for the reg_dhx_miners - // so we can iterate through the miners and retrieve the mPower of each miner for the current date with - // `MPowerForAccountForDate` - // and check if mPower for current miner being iterated is greather than the min. mPower that is required. - // after fetching the mpower values store by sending an unsigned transactions let should_send = Self::choose_transaction_type(block_number.clone()); let mut mpower_data_vec = vec![]; @@ -1456,8 +1450,11 @@ pub mod pallet { // println!("is_bonding_min_dhx {:#?}", is_bonding_min_dhx); // println!("min_bonded_dhx_daily_u128 {:#?}", min_bonded_dhx_daily_u128); - // TODO - move this into off-chain workers function - let mut min_mpower_daily_u128: u128 = 5u128; + // the cooling-off period of 7 days and DHX Mining starts when they start bonding at least 10 DHX, + // but they don't necessarily have to have the min. 1 mPower yet, however you will only start earning + // dailing mining rewards when you have at least the min. 1 mPower (i.e. by locking at least 1 MXC or similar task) + // (so they could be DHX Mining and not getting any rewards until they do so) + let mut min_mpower_daily_u128: u128 = 1u128; if let Some(_min_mpower_daily_u128) = >::get() { min_mpower_daily_u128 = _min_mpower_daily_u128; } else { @@ -1465,8 +1462,7 @@ pub mod pallet { } // println!("min_mpower_daily_u128 {:#?}", min_mpower_daily_u128); - // TODO - fetch the mPower of the miner currently being iterated to check if it's greater than the min. - // mPower that is required + // fetch the mPower of the miner currently being iterated to check if it's greater than the min. mPower that is required let mut mpower_current_u128: u128 = 0u128; let _mpower_current_u128 = >::get((start_of_requested_date_millis.clone(), miner_public_key.clone())); match _mpower_current_u128 { @@ -1478,7 +1474,10 @@ pub mod pallet { mpower_current_u128 = x; } } - // // FIXME - this is temporary + // Note: this was the hard-code mPower data that may be used incase we just want to mock + // the storage value of mpower for the current miner being iterated if we retrieved it from offchain workers + // and stored their mpower on-chain using an unsigned transaction + // let _mpower_data = ( // Some(0u128), // start_of_requested_date_millis.clone(), @@ -1497,7 +1496,8 @@ pub mod pallet { // println!("mpower_current_u128 {:#?}, {:?}", mpower_current_u128, start_of_requested_date_millis.clone()); let mut has_min_mpower_daily = false; - if mpower_current_u128 >= min_mpower_daily_u128 { + // min. mpower daily must be greater than or equal to 1 otherwise they don't get any rewards + if mpower_current_u128 >= min_mpower_daily_u128 && min_mpower_daily_u128 >= 1u128 { has_min_mpower_daily = true; } log::info!("has_min_mpower_daily: {:?} {:?}", has_min_mpower_daily.clone(), miner_public_key.clone()); diff --git a/pallets/mining/rewards-allowance/src/mock.rs b/pallets/mining/rewards-allowance/src/mock.rs index da0ccd486..0a0dce389 100644 --- a/pallets/mining/rewards-allowance/src/mock.rs +++ b/pallets/mining/rewards-allowance/src/mock.rs @@ -551,8 +551,8 @@ pub fn new_test_ext() -> sp_io::TestExternalities { rewards_accumulated_dhx_for_miner_for_date: Default::default(), min_bonded_dhx_daily: TEN_DHX, // 10 DHX min_bonded_dhx_daily_default: TEN_DHX, // 10 DHX - min_mpower_daily: 5u128, - min_mpower_daily_default: 5u128, + min_mpower_daily: 1u128, + min_mpower_daily_default: 1u128, challenge_period_days: 7u64, cooling_off_period_days: 7u32, // Note: i'm not sure how to mock Alice, just set in implementation at genesis diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 80e20a94d..589b439b4 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -63,7 +63,7 @@ fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_ fn it_distributes_rewards_automatically_in_on_finalize_for_default_amount() { new_test_ext().execute_with(|| { let amount_mpower_each_miner = 5u128; - let min_mpower_daily = 5u128; + let min_mpower_daily = 1u128; setup_min_mpower_daily(min_mpower_daily); @@ -81,7 +81,7 @@ fn it_distributes_rewards_automatically_in_on_finalize_for_default_amount() { fn it_distributes_rewards_automatically_in_on_finalize_for_large_amount() { new_test_ext().execute_with(|| { let amount_mpower_each_miner = 5u128; - let min_mpower_daily = 5u128; + let min_mpower_daily = 1u128; setup_min_mpower_daily(min_mpower_daily); @@ -286,7 +286,7 @@ fn it_sets_min_mpower_daily() { new_test_ext().execute_with(|| { assert_ok!(MiningRewardsAllowanceTestModule::set_min_mpower_daily( Origin::root(), - 5u128, + 1u128, )); }); } @@ -296,7 +296,7 @@ fn it_allows_us_to_retrieve_genesis_value_for_min_mpower_daily() { new_test_ext().execute_with(|| { // Note: we start at block 2 since we early exit from block 1 because the timestamp is yet MiningRewardsAllowanceTestModule::on_initialize(2); - assert_eq!(MiningRewardsAllowanceTestModule::min_mpower_daily(), Some(5u128)); + assert_eq!(MiningRewardsAllowanceTestModule::min_mpower_daily(), Some(1u128)); }); } From 49c8908413d35e85f5430dc750a8d2191204c1c1 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 14 Dec 2021 01:40:44 +0100 Subject: [PATCH 33/37] wip --- pallets/mining/rewards-allowance/src/lib.rs | 328 +++++++++++------- pallets/mining/rewards-allowance/src/tests.rs | 134 +++---- 2 files changed, 264 insertions(+), 198 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 86df1cff2..501d4db1c 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -751,7 +751,7 @@ pub mod pallet { /// in any way after the worker has finished. fn offchain_worker(block_number: T::BlockNumber) { log::info!("offchain_worker: {:?}", block_number.clone()); - // println!("offchain_worker: {:?}", block_number.clone()); + println!("offchain_worker: {:?}", block_number.clone()); // Note that having logs compiled to WASM may cause the size of the blob to increase // significantly. You can use `RuntimeDebug` custom derive to hide details of the types // in WASM. The `sp-api` crate also provides a feature `disable-logging` to disable @@ -788,7 +788,7 @@ pub mod pallet { } } log::info!("offchain_worker - requested_date_as_u64: {:?}", requested_date_as_u64.clone()); - // println!("offchain_worker - requested_date_as_u64: {:?}", requested_date_as_u64.clone()); + println!("offchain_worker - requested_date_as_u64: {:?}", requested_date_as_u64.clone()); // do not run when block number is 1, which is when timestamp is 0 because this // timestamp corresponds to 1970-01-01 @@ -808,7 +808,7 @@ pub mod pallet { } } log::info!("offchain_worker - start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); - // println!("offchain_worker - start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); + println!("offchain_worker - start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); // after fetching the mpower values store by sending an unsigned transactions let should_send = Self::choose_transaction_type(block_number.clone()); @@ -906,9 +906,9 @@ pub mod pallet { // Anything that needs to be done at the start of the block. let timestamp: ::Moment = >::get(); log::info!("block_number: {:?}", block_number.clone()); - // println!("block_number: {:?}", block_number.clone()); + println!("block_number: {:?}", block_number.clone()); log::info!("timestamp: {:?}", timestamp.clone()); - // println!("timestamp: {:?}", timestamp.clone()); + println!("timestamp: {:?}", timestamp.clone()); let requested_date_as_u64; let _requested_date_as_u64 = Self::convert_moment_to_u64_in_milliseconds(timestamp.clone()); match _requested_date_as_u64 { @@ -921,7 +921,7 @@ pub mod pallet { } } log::info!("requested_date_as_u64: {:?}", requested_date_as_u64.clone()); - // println!("requested_date_as_u64: {:?}", requested_date_as_u64.clone()); + println!("requested_date_as_u64: {:?}", requested_date_as_u64.clone()); // do not run when block number is 1, which is when timestamp is 0 because this // timestamp corresponds to 1970-01-01 @@ -941,7 +941,7 @@ pub mod pallet { } } log::info!("start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); - // println!("start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); + println!("start_of_requested_date_millis: {:?}", start_of_requested_date_millis.clone()); // https://substrate.dev/rustdocs/latest/frame_support/storage/trait.StorageMap.html let contains_key = >::contains_key(&start_of_requested_date_millis); @@ -1027,7 +1027,7 @@ pub mod pallet { min_bonded_dhx_daily_default_u128 = x.1; } } - // println!("min_bonded_dhx_daily_default_u128: {:?}", min_bonded_dhx_daily_default_u128.clone()); + println!("min_bonded_dhx_daily_default_u128: {:?}", min_bonded_dhx_daily_default_u128.clone()); let mut min_mpower_daily_default: u128 = 5u128; if let Some(_min_mpower_daily_default) = >::get() { @@ -1035,7 +1035,7 @@ pub mod pallet { } else { log::info!("Unable to get min_mpower_daily_default"); } - // println!("min_mpower_daily_default {:?}", min_mpower_daily_default); + println!("min_mpower_daily_default {:?}", min_mpower_daily_default); let mut rm_current_period_days_remaining = ( 0.into(), @@ -1058,14 +1058,14 @@ pub mod pallet { log::info!("rm_next_period_days: {:?}", &rm_next_period_days); log::info!("rm_current_period_days_remaining: {:?}", &rm_current_period_days_remaining); - // println!("rm_paused: {:?}", &rm_paused); - // println!("rm_reset: {:?}", &rm_reset); - // println!("rm_default_change: {:?}", &rm_default_change); - // println!("rm_current_change: {:?}", &rm_current_change); - // println!("rm_next_change: {:?}", &rm_next_change); - // println!("rm_default_period_days: {:?}", &rm_default_period_days); - // println!("rm_next_period_days: {:?}", &rm_next_period_days); - // println!("rm_current_period_days_remaining: {:?}", &rm_current_period_days_remaining); + println!("rm_paused: {:?}", &rm_paused); + println!("rm_reset: {:?}", &rm_reset); + println!("rm_default_change: {:?}", &rm_default_change); + println!("rm_current_change: {:?}", &rm_current_change); + println!("rm_next_change: {:?}", &rm_next_change); + println!("rm_default_period_days: {:?}", &rm_default_period_days); + println!("rm_next_period_days: {:?}", &rm_next_period_days); + println!("rm_current_period_days_remaining: {:?}", &rm_current_period_days_remaining); // pause the process of automatically changing to the next period change and next period day // until unpaused again by governance @@ -1107,7 +1107,7 @@ pub mod pallet { if rm_current_period_days_remaining.1 != start_of_requested_date_millis.clone() { // if there are still days remaining in the countdown if rm_current_period_days_remaining.3 > 0u32 { - // println!("[reducing_multiplier_days] block: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, rm_current_period_days_remaining.0, rm_current_period_days_remaining.3); + println!("[reducing_multiplier_days] block: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, rm_current_period_days_remaining.0, rm_current_period_days_remaining.3); let old_rm_current_period_days_remaining = rm_current_period_days_remaining.3.clone(); // Subtract, handling overflow @@ -1136,7 +1136,7 @@ pub mod pallet { log::info!("Reduced RewardsMultiplierCurrentPeriodDaysRemaining {:?} {:?}", start_of_requested_date_millis.clone(), new_rm_current_period_days_remaining.clone()); } else { // if no more days remaining - // println!("[reducing_multiplier_days] no more remaining days"); + println!("[reducing_multiplier_days] no more remaining days"); // run an operation with the the next change and the current min bonded dhx daily to determine the // new min. bonded dhx daily for the next period @@ -1154,7 +1154,7 @@ pub mod pallet { min_bonded_dhx_daily_u128 = x.1; } } - // println!("min_bonded_dhx_daily_u128: {:?}", min_bonded_dhx_daily_u128.clone()); + println!("min_bonded_dhx_daily_u128: {:?}", min_bonded_dhx_daily_u128.clone()); let rewards_multipler_operation; if let Some(_rewards_multipler_operation) = >::get() { @@ -1166,7 +1166,7 @@ pub mod pallet { let mut new_min_bonded_dhx_daily_u128 = 0u128; // initialize - // println!("rewards_multipler_operation: {:?}", rewards_multipler_operation.clone()); + println!("rewards_multipler_operation: {:?}", rewards_multipler_operation.clone()); // prepare for 'add' operation @@ -1191,10 +1191,10 @@ pub mod pallet { rm_next_change_as_fixedu128 = x; } } - // println!("rm_next_change_as_fixedu128: {:?}", rm_next_change_as_fixedu128.clone()); + println!("rm_next_change_as_fixedu128: {:?}", rm_next_change_as_fixedu128.clone()); // round down the fixed point number to the nearest integer of type u128 let rm_next_change_u128: u128 = rm_next_change_as_fixedu128.floor().to_num::(); - // println!("rm_next_change_u128: {:?}", rm_next_change_as_fixedu128.clone()); + println!("rm_next_change_u128: {:?}", rm_next_change_as_fixedu128.clone()); // case of addition if rewards_multipler_operation == 1u8 { @@ -1219,7 +1219,7 @@ pub mod pallet { return 0; } - // println!("new_min_bonded_dhx_daily_u128 {:?}", new_min_bonded_dhx_daily_u128); + println!("new_min_bonded_dhx_daily_u128 {:?}", new_min_bonded_dhx_daily_u128); let new_min_bonded_dhx_daily; let _new_min_bonded_dhx_daily = Self::convert_u128_to_balance(new_min_bonded_dhx_daily_u128.clone()); @@ -1233,11 +1233,11 @@ pub mod pallet { } } log::info!("new_min_bonded_dhx_daily: {:?}", new_min_bonded_dhx_daily.clone()); - // println!("new_min_bonded_dhx_daily: {:?}", new_min_bonded_dhx_daily.clone()); + println!("new_min_bonded_dhx_daily: {:?}", new_min_bonded_dhx_daily.clone()); >::put(new_min_bonded_dhx_daily.clone()); log::info!("New MinBondedDHXDaily {:?} {:?}", start_of_requested_date_millis.clone(), new_min_bonded_dhx_daily_u128.clone()); - // println!("New MinBondedDHXDaily {:?} {:?}", start_of_requested_date_millis.clone(), new_min_bonded_dhx_daily_u128.clone()); + println!("New MinBondedDHXDaily {:?} {:?}", start_of_requested_date_millis.clone(), new_min_bonded_dhx_daily_u128.clone()); // FIXME - can we automatically change the next period days value to (~90 days depending on days in included months 28, 29, 30, or 31) // depending on the date? and do this from genesis too? @@ -1285,7 +1285,7 @@ pub mod pallet { } } log::info!("new_min_bonded_dhx_daily: {:?}", new_min_bonded_dhx_daily.clone()); - // println!("new_min_bonded_dhx_daily: {:?}", new_min_bonded_dhx_daily.clone()); + println!("new_min_bonded_dhx_daily: {:?}", new_min_bonded_dhx_daily.clone()); } } } @@ -1296,12 +1296,12 @@ pub mod pallet { reg_dhx_miners = _reg_dhx_miners; } else { log::error!("Unable to retrieve any registered DHX Miners"); - // println!("Unable to retrieve any registered DHX Miners"); + println!("Unable to retrieve any registered DHX Miners"); return 0; } if reg_dhx_miners.len() == 0 { log::error!("Registered DHX Miners has no elements"); - // println!("Unable to retrieve any registered DHX Miners"); + println!("Unable to retrieve any registered DHX Miners"); return 0; }; @@ -1328,9 +1328,9 @@ pub mod pallet { for (index, miner_public_key) in reg_dhx_miners.iter().enumerate() { miner_count += 1; log::info!("miner_count {:#?}", miner_count); - // println!("miner_count {:#?}", miner_count); + println!("miner_count {:#?}", miner_count); log::info!("miner_public_key {:?}", miner_public_key); - // println!("miner_public_key {:?}", miner_public_key); + println!("miner_public_key {:?}", miner_public_key); // let locks_until_block_for_account = >::locks(miner_public_key.clone()); // // NOTE - I fixed the following error by using `.into_inner()` after asking the community here and getting a // // response in Substrate Builders weekly meeting https://matrix.to/#/!HzySYSaIhtyWrwiwEV:matrix.org/$163243681163543vyfkW:matrix.org?via=matrix.parity.io&via=matrix.org&via=corepaper.org @@ -1363,7 +1363,7 @@ pub mod pallet { match _miner_account_id.clone() { Err(_e) => { log::error!("Unable to decode miner_public_key"); - // println!("Unable to decode miner_public_key"); + println!("Unable to decode miner_public_key"); return 0; }, Ok(x) => { @@ -1373,7 +1373,7 @@ pub mod pallet { let locked_vec = >::locks(miner_account_id.clone()).into_inner(); if locked_vec.len() != 0 { - // println!("locked_vec: {:?}", locked_vec); + println!("locked_vec: {:?}", locked_vec); let locks_first_amount: ::Balance = >::locks(miner_account_id.clone()).into_inner().clone()[0].amount; @@ -1389,7 +1389,7 @@ pub mod pallet { } } log::info!("locks_first_amount_as_u128: {:?}", locks_first_amount_as_u128.clone()); - // println!("locks_first_amount_as_u128 {:#?}", locks_first_amount_as_u128); + println!("locks_first_amount_as_u128 {:#?}", locks_first_amount_as_u128); // Example output below of vote with 9.9999 tokens on a referendum associated with a proposal // that was seconded @@ -1411,7 +1411,7 @@ pub mod pallet { // let miner_public_key = miner.clone().encode(); log::info!("Public key {:?}", miner_public_key); - // println!("Public key {:?}", miner_public_key); + println!("Public key {:?}", miner_public_key); let bonded_dhx_current_u128; let _bonded_dhx_current_u128 = Self::set_bonded_dhx_of_account_for_date( @@ -1447,8 +1447,8 @@ pub mod pallet { is_bonding_min_dhx = true; } log::info!("is_bonding_min_dhx: {:?} {:?}", is_bonding_min_dhx.clone(), miner_public_key.clone()); - // println!("is_bonding_min_dhx {:#?}", is_bonding_min_dhx); - // println!("min_bonded_dhx_daily_u128 {:#?}", min_bonded_dhx_daily_u128); + println!("is_bonding_min_dhx {:#?}", is_bonding_min_dhx); + println!("min_bonded_dhx_daily_u128 {:#?}", min_bonded_dhx_daily_u128); // the cooling-off period of 7 days and DHX Mining starts when they start bonding at least 10 DHX, // but they don't necessarily have to have the min. 1 mPower yet, however you will only start earning @@ -1460,7 +1460,7 @@ pub mod pallet { } else { log::error!("Unable to retrieve min. mPower daily as u128"); } - // println!("min_mpower_daily_u128 {:#?}", min_mpower_daily_u128); + println!("min_mpower_daily_u128 {:#?}", min_mpower_daily_u128); // fetch the mPower of the miner currently being iterated to check if it's greater than the min. mPower that is required let mut mpower_current_u128: u128 = 0u128; @@ -1468,7 +1468,7 @@ pub mod pallet { match _mpower_current_u128 { None => { log::error!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); - // println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); + println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); }, Some(x) => { mpower_current_u128 = x; @@ -1486,14 +1486,14 @@ pub mod pallet { // match _mpower_data.0 { // None => { // log::error!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); - // // println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); + // println!("Unable to get_mpower_of_account_for_date {:?}", start_of_requested_date_millis.clone()); // }, // Some(x) => { // mpower_current_u128 = x; // } // } log::info!("mpower_current_u128 {:#?}, {:?}", mpower_current_u128, start_of_requested_date_millis.clone()); - // println!("mpower_current_u128 {:#?}, {:?}", mpower_current_u128, start_of_requested_date_millis.clone()); + println!("mpower_current_u128 {:#?}, {:?}", mpower_current_u128, start_of_requested_date_millis.clone()); let mut has_min_mpower_daily = false; // min. mpower daily must be greater than or equal to 1 otherwise they don't get any rewards @@ -1501,7 +1501,7 @@ pub mod pallet { has_min_mpower_daily = true; } log::info!("has_min_mpower_daily: {:?} {:?}", has_min_mpower_daily.clone(), miner_public_key.clone()); - // println!("has_min_mpower_daily {:#?}", has_min_mpower_daily); + println!("has_min_mpower_daily {:#?}", has_min_mpower_daily); // TODO - after fetching their mPower from the off-chain workers function where we iterate through // the registered DHX miners too, we need to incorporate it @@ -1538,12 +1538,15 @@ pub mod pallet { // if cooling_off_period_days_remaining.2 is 0u32, it means we haven't recognised they that have the min. bonded yet (or unbonded), // they aren't currently bonding, they haven't started cooling off to start bonding, // or have already finished cooling down after bonding. - // so if we detect they are now bonding above the min. or have above the min. mPower then we should start at max. remaining days + // so if we detect they are now bonding above the min. then we should start at max. remaining days // before starting to decrement on subsequent blocks + // + // note: they don't have have the min. mpower yet to progress through the cooling period, but they won't be + // eligible for rewards on the days that they don't if cooling_off_period_days_remaining.2 == 0u32 && - is_bonding_min_dhx == true && - has_min_mpower_daily == true + is_bonding_min_dhx == true + // && has_min_mpower_daily == true { >::insert( miner_public_key.clone(), @@ -1555,17 +1558,20 @@ pub mod pallet { ); log::info!("Added CoolingOffPeriodDaysRemaining for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), cooling_off_period_days.clone()); // if cooling_off_period_days_remaining.0 is not the start of the current date - // (since if they just started with min. bonded dhx and min. mPower and we just set days remaining to 7, or we already decremented + // (since if they just started with min. bonded dhx and we just set days remaining to 7, or we already decremented // a miner's days remaining for the current date, then we want to wait until the next day until we // decrement another day). // if cooling_off_period_days_remaining.1 is Some(above 0), then decrement, but not eligible yet for rewards. + // + // note: they don't have have the min. mpower yet to progress through the cooling period, but they won't be + // eligible for rewards on the days that they don't } else if cooling_off_period_days_remaining.0 != start_of_requested_date_millis.clone() && cooling_off_period_days_remaining.1 > 0u32 && - is_bonding_min_dhx == true && - has_min_mpower_daily == true + is_bonding_min_dhx == true + // && has_min_mpower_daily == true { - // println!("[reducing_days] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); + println!("[reducing_days] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); let old_cooling_off_period_days_remaining = cooling_off_period_days_remaining.1.clone(); // we cannot do this because of error: cannot use the `?` operator in a method that returns `()` @@ -1602,15 +1608,18 @@ pub mod pallet { // if cooling_off_period_days_remaining.1 is Some(0), // and if cooling_off_period_days_remaining.2 is 1 // and then no more cooling off days, but don't decrement, - // and say they are eligible for reward payments + // and say they are eligible for reward payments (for days when they have sufficient mPower) + // + // note: they don't have have the min. mpower yet to progress through the cooling period, but they won't be + // eligible for rewards on the days that they don't } else if cooling_off_period_days_remaining.0 != start_of_requested_date_millis.clone() && cooling_off_period_days_remaining.1 == 0u32 && cooling_off_period_days_remaining.2 == 1u32 && - is_bonding_min_dhx == true && - has_min_mpower_daily == true + is_bonding_min_dhx == true + // && has_min_mpower_daily == true { - // println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); + println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); // we need to add that they are eligible for rewards on the current date too >::insert( @@ -1644,12 +1653,28 @@ pub mod pallet { // daily rewards into account since we want to split them fairly. // // assuming min_bonded_dhx_daily is 10u128, and they have that minimum of 10 DHX bonded (10u128) for - // the locks_first_amount_as_u128 value, then they are eligible for 1 DHX reward + // the locks_first_amount_as_u128 value, then they are eligible for 1 DHX reward if they have 1 mPower // + // Divide, handling overflow + let mut div_bonded_as_u128 = 0u128; + // note: this rounds down to the nearest integer + let _div_bonded_as_u128 = locks_first_amount_as_u128.clone().checked_div(min_bonded_dhx_daily_u128.clone()); + match _div_bonded_as_u128 { + None => { + log::error!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); + return 0; + }, + Some(x) => { + div_bonded_as_u128 = x; + } + } + log::info!("div_bonded_as_u128: {:?}", div_bonded_as_u128.clone()); + + // Multiply, handling overflow let mut daily_reward_for_miner_as_u128 = 0u128; // note: this rounds down to the nearest integer - let _daily_reward_for_miner_as_u128 = locks_first_amount_as_u128.clone().checked_div(min_bonded_dhx_daily_u128.clone()); + let _daily_reward_for_miner_as_u128 = mpower_current_u128.clone().checked_mul(div_bonded_as_u128.clone()); match _daily_reward_for_miner_as_u128 { None => { log::error!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); @@ -1660,7 +1685,7 @@ pub mod pallet { } } log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); - // println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} daily_reward_for_miner_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, daily_reward_for_miner_as_u128); + println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} daily_reward_for_miner_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, daily_reward_for_miner_as_u128); // if we have a rewards_aggregated_dhx_daily of 25.133 k DHX, then after the above manipulation // since we're dealing with a mixture of u128 and BalanceOf so the values are more readable in the UI. @@ -1721,7 +1746,7 @@ pub mod pallet { } log::info!("new_rewards_aggregated_dhx_daily_as_u128: {:?}", new_rewards_aggregated_dhx_daily_as_u128.clone()); - // println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} new_rewards_aggregated_dhx_daily_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_aggregated_dhx_daily_as_u128); + println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} new_rewards_aggregated_dhx_daily_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_aggregated_dhx_daily_as_u128); let new_rewards_aggregated_dhx_daily; let _new_rewards_aggregated_dhx_daily = Self::convert_u128_to_balance(new_rewards_aggregated_dhx_daily_as_u128.clone()); @@ -1741,7 +1766,7 @@ pub mod pallet { new_rewards_aggregated_dhx_daily.clone(), ); log::info!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); - // println!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); + println!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); // add to storage item that maps the date to the registered miner and the calculated reward // (prior to possibly reducing it so they get a proportion of the daily rewards that are available) @@ -1753,7 +1778,7 @@ pub mod pallet { daily_reward_for_miner.clone(), ); log::info!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); - // println!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); + println!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); // Store a list of all the the registered_dhx_miners that are eligible for rewards on a given date // so we know they have been used as keys for other storage maps like `RewardsAccumulatedDHXForMinerForDate` @@ -1763,13 +1788,13 @@ pub mod pallet { rewards_eligible_miners_for_date = _rewards_eligible_miners_for_date; } else { log::warn!("Unable to retrieve rewards_eligible_miners_for_date"); - // println!("Unable to retrieve rewards_eligible_miners_for_date"); + println!("Unable to retrieve rewards_eligible_miners_for_date"); } log::info!("Retrieved existing rewards_eligible_miners_for_date {:?} {:?}", start_of_requested_date_millis.clone(), rewards_eligible_miners_for_date.clone()); - // println!("Retrieved existing rewards_eligible_miners_for_date {:?} {:?}", start_of_requested_date_millis.clone(), rewards_eligible_miners_for_date.clone()); + println!("Retrieved existing rewards_eligible_miners_for_date {:?} {:?}", start_of_requested_date_millis.clone(), rewards_eligible_miners_for_date.clone()); log::warn!("Updating rewards_eligible_miners_for_date with miner {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone()); - // println!("Updating retrieve rewards_eligible_miners_for_date with miner {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone()); + println!("Updating retrieve rewards_eligible_miners_for_date with miner {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone()); rewards_eligible_miners_for_date.push(miner_public_key.clone()); >::insert( @@ -1778,25 +1803,26 @@ pub mod pallet { ); log::info!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); - // println!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); + println!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); // if last miner being iterated then reset for next day if reg_dhx_miners.len() == miner_count { log::info!("date: {:?}, rewards_allowance_dhx_daily: {:?}", start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); - // println!("date: {:?}, rewards_allowance_dhx_daily: {:?}", start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); + println!("date: {:?}, rewards_allowance_dhx_daily: {:?}", start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); // reset to latest set by governance >::insert(start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); }; - // if they stop bonding the min dhx or stop having min. mPower, and + // if they stop bonding the min dhx, and // if cooling_off_period_days_remaining.1 is Some(0), // and if cooling_off_period_days_remaining.2 is 1 (where they had just been bonding and getting rewards) - // so since we detected they are no longer bonding above the min. or have less than min. mPower + // so since we detected they are no longer bonding above the min. // then we should start at max. remaining days before starting to decrement on subsequent blocks } else if cooling_off_period_days_remaining.1 == 0u32 && cooling_off_period_days_remaining.2 == 1u32 && - (is_bonding_min_dhx == false || has_min_mpower_daily == false) + is_bonding_min_dhx == false + // (is_bonding_min_dhx == false || has_min_mpower_daily == false) { // Write the new value to storage >::insert( @@ -1809,10 +1835,10 @@ pub mod pallet { ); log::info!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_off_period_days.clone()); - // println!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_off_period_days.clone()); + println!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_off_period_days.clone()); // if cooling_off_period_days_remaining.0 is not the start of the current date - // (since if they just started un-bonding or just had less than min. mPower + // (since if they just started un-bonding // and we just set days remaining to 7, or we already decremented // a miner's days remaining for the current date, then we want to wait until the next day until we // decrement another day). @@ -1820,9 +1846,9 @@ pub mod pallet { // but not yet completely unbonded so cannot withdraw yet // note: we don't care if they stop bonding below the min. dhx or have less than min. mPower // during the cooling off period, - // as the user needs to learn that they should always been bonding the min. and have min. mPower to - // maintain rewards, otherwise they have to wait for entire cooling down period and - // then the cooling off period again. + // as the user needs to learn that they should always been bonding the min., otherwise they + // have to wait for entire cooling down period and then the cooling off period again. + // and they need to have the min. mPower to earn rewards // } else if cooling_off_period_days_remaining.0 != start_of_requested_date_millis.clone() && @@ -1839,7 +1865,7 @@ pub mod pallet { match _new_cooling_off_period_days_remaining { None => { log::error!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); - // println!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); + println!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); return 0; }, @@ -1858,7 +1884,7 @@ pub mod pallet { ), ); - // println!("[reduce] block: {:#?}, miner: {:#?}, date_start: {:#?} new_cooling_off_period_days_remaining: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_cooling_off_period_days_remaining); + println!("[reduce] block: {:#?}, miner: {:#?}, date_start: {:#?} new_cooling_off_period_days_remaining: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_cooling_off_period_days_remaining); log::info!("Unbonded miner. Reducing cooling down period dates remaining {:?} {:?}", miner_public_key.clone(), new_cooling_off_period_days_remaining.clone()); // if cooling_off_period_days_remaining.0 is not the start of the current date @@ -1884,12 +1910,14 @@ pub mod pallet { ); log::info!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); - // println!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); + println!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); } + + } log::info!("Finished initial loop of registered miners"); - // println!("Finished initial loop of registered miners"); + println!("Finished initial loop of registered miners"); return 0; } @@ -2191,7 +2219,7 @@ pub mod pallet { // assert_eq!(_sender.clone(), miner_public_key.clone()); log::info!("claim_rewards_of_account_for_date - miner_public_key: {:?} {:?}", miner_public_key.clone(), start_of_requested_date_millis.clone()); - // println!("claim_rewards_of_account_for_date - miner_public_key: {:?} {:?}", miner_public_key.clone(), start_of_requested_date_millis.clone()); + println!("claim_rewards_of_account_for_date - miner_public_key: {:?} {:?}", miner_public_key.clone(), start_of_requested_date_millis.clone()); let block_number = >::block_number(); @@ -2219,13 +2247,13 @@ pub mod pallet { match _is_more_than_challenge_period.clone() { Err(_e) => { log::error!("Unable to claim until after waiting the challenge period {:?}", _e); - // println!("Unable to claim until after waiting the challenge period {:?}", _e); + println!("Unable to claim until after waiting the challenge period {:?}", _e); return Err(_e); }, Ok(x) => { log::info!("Proceeding since waited at least the challenge period"); - // println!("Proceeding since waited at least the challenge period"); + println!("Proceeding since waited at least the challenge period"); is_more_than_challenge_period = x; } } @@ -2240,16 +2268,16 @@ pub mod pallet { rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; } else { log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet"); - // println!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet"); + println!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet"); // Note: it would be an issue if we got past the first loop of looping through the registered miners // and still hadn't added to the aggregated rewards for the day return Err(DispatchError::Other("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet")); } - // println!("[multiplier] block: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, start_of_requested_date_millis, rewards_aggregated_dhx_daily); + println!("[multiplier] block: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, start_of_requested_date_millis, rewards_aggregated_dhx_daily); if rewards_aggregated_dhx_daily == 0u32.into() { log::error!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); - // println!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); + println!("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards"); return Err(DispatchError::Other("rewards_aggregated_dhx_daily must be greater than 0 to distribute rewards")); } @@ -2258,7 +2286,7 @@ pub mod pallet { match _rewards_aggregated_dhx_daily_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); - // println!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); + println!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); return Err(DispatchError::Other("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128")); }, Ok(x) => { @@ -2266,7 +2294,7 @@ pub mod pallet { } } log::info!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); - // println!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); + println!("rewards_aggregated_dhx_daily_as_u128: {:?}", rewards_aggregated_dhx_daily_as_u128.clone()); // TODO - we've done this twice, create a function to fetch it let rewards_allowance_dhx_daily; @@ -2274,7 +2302,7 @@ pub mod pallet { rewards_allowance_dhx_daily = _rewards_allowance_dhx_daily; } else { log::error!("Unable to get rewards_allowance_dhx_daily"); - // println!("Unable to get rewards_allowance_dhx_daily"); + println!("Unable to get rewards_allowance_dhx_daily"); return Err(DispatchError::Other("Unable to get rewards_allowance_dhx_daily")); } @@ -2283,7 +2311,7 @@ pub mod pallet { match _rewards_allowance_dhx_daily_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); - // println!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); + println!("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128"); return Err(DispatchError::Other("Unable to convert balance to u128 for rewards_allowance_dhx_daily_u128")); }, Ok(x) => { @@ -2291,9 +2319,12 @@ pub mod pallet { } } + log::info!("rewards_allowance_dhx_daily_u128: {:?}", rewards_allowance_dhx_daily_u128.clone()); + println!("rewards_allowance_dhx_daily_u128: {:?}", rewards_allowance_dhx_daily_u128.clone()); + if rewards_allowance_dhx_daily_u128 == 0u128 { log::error!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); - // println!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); + println!("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards"); return Err(DispatchError::Other("rewards_allowance_dhx_daily must be greater than 0 to distribute rewards")); } @@ -2318,6 +2349,8 @@ pub mod pallet { let mut distribution_multiplier_for_day_fixed128 = FixedU128::from_num(1); // initialize if rewards_aggregated_dhx_daily_as_u128.clone() > rewards_allowance_dhx_daily_u128.clone() { + log::info!("rewards_aggregated_dhx_daily > rewards_allowance_dhx_daily"); + println!("rewards_aggregated_dhx_daily > rewards_allowance_dhx_daily"); // Divide, handling overflow // Note: If the rewards_allowance_dhx_daily_u128 is 5000 DHX, its 5000000000000000000000, @@ -2332,9 +2365,11 @@ pub mod pallet { manageable_rewards_allowance_dhx_daily_u128 = _manageable_rewards_allowance_dhx_daily_u128; } else { log::error!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); - // println!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); + println!("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller"); return Err(DispatchError::Other("Unable to divide rewards_allowance_dhx_daily_u128 to make it smaller")); } + log::info!("manageable_rewards_allowance_dhx_daily_u128: {:?}", manageable_rewards_allowance_dhx_daily_u128.clone()); + println!("manageable_rewards_allowance_dhx_daily_u128: {:?}", manageable_rewards_allowance_dhx_daily_u128.clone()); let mut rewards_allowance_dhx_daily_u64 = 0u64; if let Some(_rewards_allowance_dhx_daily_u64) = @@ -2342,18 +2377,22 @@ pub mod pallet { rewards_allowance_dhx_daily_u64 = _rewards_allowance_dhx_daily_u64; } else { log::error!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); - // println!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); + println!("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128"); return Err(DispatchError::Other("Unable to convert u128 to u64 for rewards_allowance_dhx_daily_u128")); } + log::info!("rewards_allowance_dhx_daily_u64: {:?}", rewards_allowance_dhx_daily_u64.clone()); + println!("rewards_allowance_dhx_daily_u64: {:?}", rewards_allowance_dhx_daily_u64.clone()); let mut manageable_rewards_aggregated_dhx_daily_as_u128 = 0u128; if let Some(_manageable_rewards_aggregated_dhx_daily_as_u128) = rewards_aggregated_dhx_daily_as_u128.clone().checked_div(1000000000000000000u128) { manageable_rewards_aggregated_dhx_daily_as_u128 = _manageable_rewards_aggregated_dhx_daily_as_u128; } else { log::error!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); - // println!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); + println!("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller"); return Err(DispatchError::Other("Unable to divide manageable_rewards_aggregated_dhx_daily_as_u128 to make it smaller")); } + log::info!("manageable_rewards_aggregated_dhx_daily_as_u128: {:?}", manageable_rewards_aggregated_dhx_daily_as_u128.clone()); + println!("manageable_rewards_aggregated_dhx_daily_as_u128: {:?}", manageable_rewards_aggregated_dhx_daily_as_u128.clone()); let mut rewards_aggregated_dhx_daily_as_u64 = 0u64; if let Some(_rewards_aggregated_dhx_daily_as_u64) = @@ -2361,9 +2400,11 @@ pub mod pallet { rewards_aggregated_dhx_daily_as_u64 = _rewards_aggregated_dhx_daily_as_u64; } else { log::error!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); - // println!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); + println!("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128"); return Err(DispatchError::Other("Unable to convert u128 to u64 for rewards_aggregated_dhx_daily_as_u128")); } + log::info!("rewards_aggregated_dhx_daily_as_u64: {:?}", rewards_aggregated_dhx_daily_as_u64.clone()); + println!("rewards_aggregated_dhx_daily_as_u64: {:?}", rewards_aggregated_dhx_daily_as_u64.clone()); // See https://github.com/ltfschoen/substrate-node-template/pull/6/commits/175ef4805d07093042431c5814dda52da1ebde18 let _fraction_distribution_multiplier_for_day_fixed128 = @@ -2373,19 +2414,22 @@ pub mod pallet { match _distribution_multiplier_for_day_fixed128 { None => { log::error!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); - // println!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); + println!("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128"); return Err(DispatchError::Other("Unable to divide rewards_allowance_dhx_daily_u128 due to StorageOverflow by rewards_aggregated_dhx_daily_as_u128")); }, Some(x) => { distribution_multiplier_for_day_fixed128 = x; } } + } else { + log::info!("rewards_aggregated_dhx_daily <= rewards_allowance_dhx_daily"); + println!("rewards_aggregated_dhx_daily <= rewards_allowance_dhx_daily"); } log::info!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); - // println!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); + println!("distribution_multiplier_for_day_fixed128 {:#?}", distribution_multiplier_for_day_fixed128); log::info!("[multiplier] block: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); - // println!("[multiplier] block: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); + println!("[multiplier] block: {:#?}, date_start: {:#?} distribution_multiplier_for_day_fixed128: {:#?}", block_number, start_of_requested_date_millis, distribution_multiplier_for_day_fixed128); // Initialise outside the loop as we need this value after the loop after we finish iterating through all the miners let mut rewards_allowance_dhx_remaining_today_as_u128 = 0u128; @@ -2406,9 +2450,12 @@ pub mod pallet { miner_public_key.clone(), ) ); + log::info!("is_already_distributed_to_miner {:#?}", is_already_distributed_to_miner); + println!("is_already_distributed_to_miner {:#?}", is_already_distributed_to_miner); + if is_already_distributed_to_miner == Some(true) { log::error!("Unable to distribute further rewards allowance to the registered dhx miner for this day"); - // println!("Unable to distribute further rewards allowance to the registered dhx miner for this day"); + println!("Unable to distribute further rewards allowance to the registered dhx miner for this day"); return Err(DispatchError::Other("Unable to distribute further rewards allowance to the registered dhx miner for this day")); } @@ -2424,7 +2471,7 @@ pub mod pallet { match _daily_reward_for_miner_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128 for daily_reward_for_miner_as_u128"); - // println!("Unable to distribute further rewards allowance to the registered dhx miner for this day"); + println!("Unable to distribute further rewards allowance to the registered dhx miner for this day"); return Err(DispatchError::Other("Unable to convert balance to u128 for daily_reward_for_miner_as_u128")); }, Ok(x) => { @@ -2435,11 +2482,11 @@ pub mod pallet { // If any of the miner's don't have a reward, we won't waste storing that, // so we want to move to the next miner in the loop log::error!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); - // println!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); + println!("Unable to retrieve reward balance for daily_reward_for_miner {:?}", miner_public_key.clone()); return Err(DispatchError::Other("Unable to retrieve reward balance for daily_reward_for_miner")); } log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); - // println!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); + println!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); let mut manageable_daily_reward_for_miner_as_u128 = 0u128; if let Some(_manageable_daily_reward_for_miner_as_u128) = @@ -2447,9 +2494,11 @@ pub mod pallet { manageable_daily_reward_for_miner_as_u128 = _manageable_daily_reward_for_miner_as_u128; } else { log::error!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); - // println!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); + println!("Unable to divide daily_reward_for_miner_as_u128 to make it smaller"); return Err(DispatchError::Other("Unable to divide daily_reward_for_miner_as_u128 to make it smaller")); } + log::info!("manageable_daily_reward_for_miner_as_u128 {:#?}", manageable_daily_reward_for_miner_as_u128); + println!("manageable_daily_reward_for_miner_as_u128 {:#?}", manageable_daily_reward_for_miner_as_u128); // Multiply, handling overflow // TODO - probably have to initialise below proportion_of_daily_reward_for_miner_fixed128 to 0u128, @@ -2462,7 +2511,7 @@ pub mod pallet { match _proportion_of_daily_reward_for_miner_fixed128 { None => { log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); - // println!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); + println!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow"); return Err(DispatchError::Other("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 with daily_reward_for_miner_as_u128 due to StorageOverflow")); }, Some(x) => { @@ -2470,13 +2519,16 @@ pub mod pallet { } } log::info!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); - // println!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); + println!("proportion_of_daily_reward_for_miner_fixed128: {:?}", proportion_of_daily_reward_for_miner_fixed128.clone()); // round down to nearest integer. we need to round down, because if we round up then if there are // 3x registered miners with 5000 DHX rewards allowance per day then they would each get 1667 rewards, // but there would only be 1666 remaining after the first two, so the last one would miss out. // so if we round down they each get 1666 DHX and there is 2 DHX from the daily allocation that doesn't get distributed at all. let proportion_of_daily_reward_for_miner_u128: u128 = proportion_of_daily_reward_for_miner_fixed128.floor().to_num::(); + log::info!("proportion_of_daily_reward_for_miner_u128: {:?}", proportion_of_daily_reward_for_miner_u128.clone()); + println!("proportion_of_daily_reward_for_miner_u128: {:?}", proportion_of_daily_reward_for_miner_u128.clone()); + // we lose some accuracy doing this conversion, but at least we split the bulk of the rewards proportionally and fairly let mut restored_proportion_of_daily_reward_for_miner_u128 = 0u128; @@ -2485,45 +2537,49 @@ pub mod pallet { restored_proportion_of_daily_reward_for_miner_u128 = _restored_proportion_of_daily_reward_for_miner_u128; } else { log::error!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); - // println!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); + println!("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again"); return Err(DispatchError::Other("Unable to multiply proportion_of_daily_reward_for_miner_fixed128 to restore it larger again")); } + log::info!("restored_proportion_of_daily_reward_for_miner_u128: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); + println!("restored_proportion_of_daily_reward_for_miner_u128: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); log::info!("[rewards] block: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); - // println!("[rewards] block: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); + println!("[rewards] block: {:#?}, date_start: {:#?} restored_proportion_of_daily_reward_for_miner_u128: {:#?}", block_number, start_of_requested_date_millis, restored_proportion_of_daily_reward_for_miner_u128); let treasury_account_id: T::AccountId = >::account_id(); let max_payout = pallet_balances::Pallet::::usable_balance(treasury_account_id.clone()); log::info!("Treasury account id: {:?}", treasury_account_id.clone()); log::info!("Miner to receive reward: {:?}", miner_public_key.clone()); log::info!("Treasury balance max payout: {:?}", max_payout.clone()); - // println!("Treasury account id: {:?}", treasury_account_id.clone()); - // println!("Miner to receive reward: {:?}", miner_public_key.clone()); - // println!("Treasury balance max payout: {:?}", max_payout.clone()); + println!("Treasury account id: {:?}", treasury_account_id.clone()); + println!("Miner to receive reward: {:?}", miner_public_key.clone()); + println!("Treasury balance max payout: {:?}", max_payout.clone()); let proportion_of_daily_reward_for_miner; let _proportion_of_daily_reward_for_miner = Self::convert_u128_to_balance(restored_proportion_of_daily_reward_for_miner_u128.clone()); match _proportion_of_daily_reward_for_miner { Err(_e) => { log::error!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); - // println!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); + println!("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner"); return Err(DispatchError::Other("Unable to convert u128 to balance for proportion_of_daily_reward_for_miner")); }, Ok(ref x) => { proportion_of_daily_reward_for_miner = x; } } + log::info!("proportion_of_daily_reward_for_miner: {:?}", proportion_of_daily_reward_for_miner.clone()); + println!("proportion_of_daily_reward_for_miner: {:?}", proportion_of_daily_reward_for_miner.clone()); let max_payout_as_u128; if let Some(_max_payout_as_u128) = TryInto::::try_into(max_payout).ok() { max_payout_as_u128 = _max_payout_as_u128; } else { log::error!("Unable to convert Balance to u128 for max_payout"); - // println!("Unable to convert Balance to u128 for max_payout"); + println!("Unable to convert Balance to u128 for max_payout"); return Err(DispatchError::Other("Unable to convert Balance to u128 for max_payout")); } log::info!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); - // println!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); + println!("max_payout_as_u128: {:?}", max_payout_as_u128.clone()); // TODO - rename `rewards_allowance_dhx_remaining_today` to // `rewards_allowance_dhx_remaining_for_date_rewards_being_claimed` @@ -2535,7 +2591,7 @@ pub mod pallet { match _rewards_allowance_dhx_remaining_today_as_u128.clone() { Err(_e) => { log::error!("Unable to convert balance to u128"); - // println!("Unable to convert balance to u128"); + println!("Unable to convert balance to u128"); return Err(DispatchError::Other("Unable to convert balance to u128")); }, Ok(x) => { @@ -2543,15 +2599,15 @@ pub mod pallet { } } log::info!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); - // println!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); + println!("rewards_allowance_dhx_remaining_today_as_u128: {:?}", rewards_allowance_dhx_remaining_today_as_u128.clone()); } else { log::error!("Unable to retrieve balance from value provided."); - // println!("Unable to retrieve balance from value provided."); + println!("Unable to retrieve balance from value provided."); return Err(DispatchError::Other("Unable to retrieve balance from value provided.")); } log::info!("[prepared-for-payment] block: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); - // println!("[prepared-for-payment] block: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); + println!("[prepared-for-payment] block: {:#?}, date_start: {:#?} max payout: {:#?}, rewards remaining today {:?}, restored_proportion_of_daily_reward_for_miner_u128 {:?}", block_number, start_of_requested_date_millis, max_payout_as_u128, rewards_allowance_dhx_remaining_today_as_u128, restored_proportion_of_daily_reward_for_miner_u128); // check if miner's reward is less than or equal to: rewards_allowance_dhx_daily_remaining if restored_proportion_of_daily_reward_for_miner_u128.clone() > 0u128 && @@ -2560,7 +2616,7 @@ pub mod pallet { { // pay the miner their daily reward info!("Paying the miner a proportion of the remaining daily reward allowance"); - // println!("Paying the miner a proportion of the remaining daily reward allowance"); + println!("Paying the miner a proportion of the remaining daily reward allowance"); let tx_result; let _tx_result = ::Currency::transfer( @@ -2579,10 +2635,10 @@ pub mod pallet { } } info!("Transfer to the miner tx_result: {:?}", tx_result.clone()); - // println!("Transfer to the miner tx_result: {:?}", tx_result.clone()); + println!("Transfer to the miner tx_result: {:?}", tx_result.clone()); info!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); - // println!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); + println!("Success paying the reward to the miner: {:?}", restored_proportion_of_daily_reward_for_miner_u128.clone()); // TODO - move into function `reduce_rewards_allowance_dhx_for_date_remaining`? @@ -2593,7 +2649,7 @@ pub mod pallet { match _new_rewards_allowance_dhx_remaining_today_as_u128 { None => { log::error!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); - // println!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); + println!("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow"); return Err(DispatchError::Other("Unable to subtract restored_proportion_of_daily_reward_for_miner_u128 from rewards_allowance_dhx_remaining_today due to StorageOverflow")); }, Some(x) => { @@ -2606,7 +2662,7 @@ pub mod pallet { match _new_rewards_allowance_dhx_remaining_today { Err(_e) => { log::error!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); - // println!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); + println!("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today"); return Err(DispatchError::Other("Unable to convert u128 to balance for new_rewards_allowance_dhx_remaining_today")); }, Ok(ref x) => { @@ -2621,7 +2677,7 @@ pub mod pallet { ); log::info!("[paid] block: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); - // println!("[paid] block: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); + println!("[paid] block: {:#?}, date_start: {:#?} new_rewards_allowance_dhx_remaining_today: {:#?}", block_number, start_of_requested_date_millis, new_rewards_allowance_dhx_remaining_today); >::insert( ( @@ -2645,13 +2701,13 @@ pub mod pallet { new_rewards_allowance_dhx_remaining_today.clone(), miner_public_key.clone(), ); - // do not split this across multiple lines otherwise not as easy to find/replace `println` with `// println` when + // do not split this across multiple lines otherwise not as easy to find/replace `println` with `println` when // switching between running tests with `println` and building the code with `cargo build --release` that doesn't // work with println - // println!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", start_of_requested_date_millis.clone(), proportion_of_daily_reward_for_miner.clone(), new_rewards_allowance_dhx_remaining_today.clone(), miner_public_key.clone()); + println!("TransferredRewardsAllowanceDHXToMinerForDate {:?} {:?} {:?} {:?}", start_of_requested_date_millis.clone(), proportion_of_daily_reward_for_miner.clone(), new_rewards_allowance_dhx_remaining_today.clone(), miner_public_key.clone()); } else { log::error!("Insufficient remaining rewards allowance to pay daily reward to miner"); - // println!("Insufficient remaining rewards allowance to pay daily reward to miner"); + println!("Insufficient remaining rewards allowance to pay daily reward to miner"); return Err(DispatchError::Other("Insufficient remaining rewards allowance to pay daily reward to miner")); } @@ -2660,16 +2716,18 @@ pub mod pallet { match _rewards_allowance_dhx_remaining_today { Err(_e) => { log::error!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); - // println!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); + println!("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today"); return Err(DispatchError::Other("Unable to convert u128 to balance for rewards_allowance_dhx_remaining_today")); }, Ok(ref x) => { rewards_allowance_dhx_remaining_today = x; } } + info!("rewards_allowance_dhx_remaining_today: {:?}", rewards_allowance_dhx_remaining_today.clone()); + println!("rewards_allowance_dhx_remaining_today: {:?}", rewards_allowance_dhx_remaining_today.clone()); log::info!("[distributed] block: {:#?}, date_start: {:#?} ", block_number, start_of_requested_date_millis); - // println!("[distributed] block: {:#?}, date_start: {:#?} ", block_number, start_of_requested_date_millis); + println!("[distributed] block: {:#?}, date_start: {:#?} ", block_number, start_of_requested_date_millis); Self::deposit_event(Event::DistributedRewardsAllowanceDHXForDateRemaining( start_of_requested_date_millis.clone(), @@ -3143,7 +3201,7 @@ pub mod pallet { min_bonded_dhx_daily_u128 = x.1; } } - // println!("Reset to the min. bonded DHX daily default"); + println!("Reset to the min. bonded DHX daily default"); } // Return a successful DispatchResultWithPostInfo Ok( @@ -3428,7 +3486,7 @@ pub mod pallet { let mpower_json_data = match lite_json::parse_json(mpower_data_str) { Err(e) => { log::error!("Couldn't parse JSON {:?}", e); - // println!("Couldn't parse JSON {:?}", e); + println!("Couldn't parse JSON {:?}", e); return None; }, Ok(data) => data, @@ -3436,7 +3494,7 @@ pub mod pallet { // let mpower_json_data: MPowerJSONResponseData = match serde_json::from_str(mpower_data_str) { // Err(e) => { - // // println!("Couldn't parse JSON :( {:?}", e); + // println!("Couldn't parse JSON :( {:?}", e); // return None; // }, // Ok(data) => data, @@ -3658,11 +3716,15 @@ pub mod pallet { // check that the current date start_of_current_date_millis is at least 7 days after the provided // start_of_requested_date_millis so there is sufficient time for the community to audit the reward eligibility. - // we could use `CoolingOffPeriodDays` for this, but probably better to call it a `ChallengePeriodDays` - // since it serves a different purpose (`CoolingOffPeriodDays` gives rewards for first 7 days after they - // start bonding in bulk on the 8th day, and then the next day after each day after that, whereas - // `ChallengePeriodDays` you can only claim each daily rewards manually 7 days after it, even for the first - // 7 days after they start bonding) + // + // `CoolingOffPeriodDays` gives rewards in bulk on the 8th day in bulk to cover the + // first say x (i.e. 7) days after they start bonding, and then on the next day after each day after that, and + // it is also used to track the unbonding period where if they stop bonding obviously they cannot be eligible + // for rewards and they have wait x (i.e. 7) days after unbonding before they can access the locked DHX tokens + // that they were bonding with, whereas: + // + // `ChallengePeriodDays` is used only to ensure you can only claim each daily rewards manually 7 days after being found eligible, + // even for the first 7 days after they start bonding) pub fn is_more_than_challenge_period(start_of_requested_date_millis: i64) -> Result { let current_timestamp = >::get(); let current_timestamp_as_u64 = Self::convert_moment_to_u64_in_milliseconds(current_timestamp.clone())?; @@ -3704,7 +3766,7 @@ pub mod pallet { } // log::info!("period_millis_u64: {:?}", period_millis_u64.clone()); - // // println!("period_millis_u64: {:?}", period_millis_u64.clone()); + // println!("period_millis_u64: {:?}", period_millis_u64.clone()); if (period_millis_u64 >= challenge_period_millis.clone()) { is_more_than_challenge_period = true; } diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 589b439b4..2751e4228 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -78,6 +78,7 @@ fn it_distributes_rewards_automatically_in_on_finalize_for_default_amount() { } #[test] +#[ignore] fn it_distributes_rewards_automatically_in_on_finalize_for_large_amount() { new_test_ext().execute_with(|| { let amount_mpower_each_miner = 5u128; @@ -605,75 +606,78 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount // or 33_333_333_333_000_000_000_000_000u128 (LARGE_AMOUNT_DHX), // but the results are rounded to the nearest integer so it would be 2513 DHX, not 2513.3 DHX if amount_bonded_each_miner.clone() == NORMAL_AMOUNT { - assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(7_539_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(37_695_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(2_513_000_000_000_000_000_000u128)); - } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { - assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(9_999_999_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + // } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { + assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(37_695_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(3_333_333_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); } - // we'll get all three of the registered dhx miners to claim their rewards - assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( - Origin::signed(account_1_account_id.clone()), - account_1_public_key.clone(), - 1630195200000 - )); - - assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( - Origin::signed(account_2_account_id.clone()), - account_2_public_key.clone(), - 1630195200000 - )); - - assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( - Origin::signed(account_3_account_id.clone()), - account_3_public_key.clone(), - 1630195200000 - )); - - // after all the registered dhx miners have claimed their rewards this is the amount that should be remaining from the allocated dhx for the date - assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); - // TODO - each registered dhx miner is claiming rewards now instead of the rewards being automatically distributed, - // see notes in the implementation lib.rs - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); - - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); - - change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); - - // 30th August 2021 @ ~7am is 1630306800000 - // 30th August 2021 @ 12am is 1630281600000 (start of day) - Timestamp::set_timestamp(1630306800000u64); - MiningRewardsAllowanceTestModule::on_initialize(5); - - // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded - // amount below the min. bonded DHX daily amount - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); - // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX - assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); - // the change between each multiplier period is 10 unless a user sets it to a different value - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); - // start of new multiplier period - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); - - // Note - these are just notes. no further action required - // Note - why is this 2u128 instead of reset back to say 5000u128 DHX (unless set do different value?? - // this should be reset after rewards aggregated/accumulated each day - // since distribution/claiming may not be done by a user each day - // Update: it gets reset but difficult to add a test, have to run the logs with only one test running to see it gets accumulated/aggregated - // to all miners each day over a few days - assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630281600000), Some(FIVE_THOUSAND_DHX)); - // TODO - see other notes about status of using `rewards_allowance_dhx_for_date_remaining_distributed` in future. - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630281600000), Some(false)); + // // we'll get all three of the registered dhx miners to claim their rewards + // assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + // Origin::signed(account_1_account_id.clone()), + // account_1_public_key.clone(), + // 1630195200000 + // )); + + // added this so logs appear so i can debug + assert_eq!(1, 0); + + // assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + // Origin::signed(account_2_account_id.clone()), + // account_2_public_key.clone(), + // 1630195200000 + // )); + + // assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + // Origin::signed(account_3_account_id.clone()), + // account_3_public_key.clone(), + // 1630195200000 + // )); + + // // after all the registered dhx miners have claimed their rewards this is the amount that should be remaining from the allocated dhx for the date + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); + // // TODO - each registered dhx miner is claiming rewards now instead of the rewards being automatically distributed, + // // see notes in the implementation lib.rs + // // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); + + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); + + // change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); + + // // 30th August 2021 @ ~7am is 1630306800000 + // // 30th August 2021 @ 12am is 1630281600000 (start of day) + // Timestamp::set_timestamp(1630306800000u64); + // MiningRewardsAllowanceTestModule::on_initialize(5); + + // // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded + // // amount below the min. bonded DHX daily amount + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); + // // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX + // assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); + // // the change between each multiplier period is 10 unless a user sets it to a different value + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); + // // start of new multiplier period + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); + + // // Note - these are just notes. no further action required + // // Note - why is this 2u128 instead of reset back to say 5000u128 DHX (unless set do different value?? + // // this should be reset after rewards aggregated/accumulated each day + // // since distribution/claiming may not be done by a user each day + // // Update: it gets reset but difficult to add a test, have to run the logs with only one test running to see it gets accumulated/aggregated + // // to all miners each day over a few days + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630281600000), Some(FIVE_THOUSAND_DHX)); + // // TODO - see other notes about status of using `rewards_allowance_dhx_for_date_remaining_distributed` in future. + // // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630281600000), Some(false)); } fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { From 897494a96bc9b8b86b1ad7d0e9d9f26992dc396a Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 20 Dec 2021 06:18:28 +0100 Subject: [PATCH 34/37] wip --- pallets/mining/rewards-allowance/src/lib.rs | 8 +- pallets/mining/rewards-allowance/src/tests.rs | 133 ++++++++++-------- 2 files changed, 77 insertions(+), 64 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 501d4db1c..71f7a3617 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -1619,6 +1619,7 @@ pub mod pallet { is_bonding_min_dhx == true // && has_min_mpower_daily == true { + log::info!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); // we need to add that they are eligible for rewards on the current date too @@ -1912,8 +1913,6 @@ pub mod pallet { log::info!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); println!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); } - - } log::info!("Finished initial loop of registered miners"); @@ -3715,9 +3714,10 @@ pub mod pallet { } // check that the current date start_of_current_date_millis is at least 7 days after the provided - // start_of_requested_date_millis so there is sufficient time for the community to audit the reward eligibility. + // start_of_requested_date_millis so there is sufficient time for the community to audit the reward eligibility, + // where the start_of_requested_date_millis refers to a past date the claimant believes they became eligible for rewards on. // - // `CoolingOffPeriodDays` gives rewards in bulk on the 8th day in bulk to cover the + // `CoolingOffPeriodDays` notifies when to give rewards in bulk (previously automatically, now by claiming) on the 8th day in bulk to cover the // first say x (i.e. 7) days after they start bonding, and then on the next day after each day after that, and // it is also used to track the unbonding period where if they stop bonding obviously they cannot be eligible // for rewards and they have wait x (i.e. 7) days after unbonding before they can access the locked DHX tokens diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 2751e4228..225e4f88b 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -60,7 +60,7 @@ fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_ // Note: if we remove `cooling_off_period_days_remaining.0 != start_of_requested_date_millis.clone() &&` // four times from the implementation, then all this happens on the same day so we'd need to use the // same timestamp for all the blocks and tests below. -fn it_distributes_rewards_automatically_in_on_finalize_for_default_amount() { +fn it_calcs_rewards_allowance_using_on_initialize_with_claim_using_extrinsic_for_default_amount() { new_test_ext().execute_with(|| { let amount_mpower_each_miner = 5u128; let min_mpower_daily = 1u128; @@ -78,8 +78,8 @@ fn it_distributes_rewards_automatically_in_on_finalize_for_default_amount() { } #[test] -#[ignore] -fn it_distributes_rewards_automatically_in_on_finalize_for_large_amount() { +// #[ignore] +fn it_calcs_rewards_allowance_using_on_initialize_with_claim_using_extrinsic_for_large_amount() { new_test_ext().execute_with(|| { let amount_mpower_each_miner = 5u128; let min_mpower_daily = 1u128; @@ -619,65 +619,78 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); } - // // we'll get all three of the registered dhx miners to claim their rewards - // assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( - // Origin::signed(account_1_account_id.clone()), - // account_1_public_key.clone(), - // 1630195200000 - // )); + // we can only claim the rewards for a date that was at least the challenge period (i.e. 7 days) prior to the current date + // when a user submits a request to claim rewards that were calculated that they were eligibible for on that prior date + + // 6th September 2021 @ 12am is 1630886400000 (start of day) + Timestamp::set_timestamp(1630886400000u64); + + assert_ok!(MiningRewardsAllowanceTestModule::set_challenge_period_days( + Origin::root(), + 7u64, + )); + + // try to claim rewards they were deemed eligible for back on the 29th Aug + + // we'll get all three of the registered dhx miners to claim their rewards + assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + Origin::signed(account_1_account_id.clone()), + account_1_public_key.clone(), + 1630195200000 + )); // added this so logs appear so i can debug - assert_eq!(1, 0); - - // assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( - // Origin::signed(account_2_account_id.clone()), - // account_2_public_key.clone(), - // 1630195200000 - // )); - - // assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( - // Origin::signed(account_3_account_id.clone()), - // account_3_public_key.clone(), - // 1630195200000 - // )); - - // // after all the registered dhx miners have claimed their rewards this is the amount that should be remaining from the allocated dhx for the date - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); - // // TODO - each registered dhx miner is claiming rewards now instead of the rewards being automatically distributed, - // // see notes in the implementation lib.rs - // // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); - - // assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); - - // change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); - - // // 30th August 2021 @ ~7am is 1630306800000 - // // 30th August 2021 @ 12am is 1630281600000 (start of day) - // Timestamp::set_timestamp(1630306800000u64); - // MiningRewardsAllowanceTestModule::on_initialize(5); - - // // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded - // // amount below the min. bonded DHX daily amount - // assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); - // // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX - // assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); - // // the change between each multiplier period is 10 unless a user sets it to a different value - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); - // // start of new multiplier period - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); - - // // Note - these are just notes. no further action required - // // Note - why is this 2u128 instead of reset back to say 5000u128 DHX (unless set do different value?? - // // this should be reset after rewards aggregated/accumulated each day - // // since distribution/claiming may not be done by a user each day - // // Update: it gets reset but difficult to add a test, have to run the logs with only one test running to see it gets accumulated/aggregated - // // to all miners each day over a few days - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630281600000), Some(FIVE_THOUSAND_DHX)); - // // TODO - see other notes about status of using `rewards_allowance_dhx_for_date_remaining_distributed` in future. - // // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630281600000), Some(false)); + // assert_eq!(1, 0); + + assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + Origin::signed(account_2_account_id.clone()), + account_2_public_key.clone(), + 1630195200000 + )); + + assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + Origin::signed(account_3_account_id.clone()), + account_3_public_key.clone(), + 1630195200000 + )); + + // after all the registered dhx miners have claimed their rewards this is the amount that should be remaining from the allocated dhx for the date + assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); + // TODO - each registered dhx miner is claiming rewards now instead of the rewards being automatically distributed, + // see notes in the implementation lib.rs + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); + + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); + + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); + + // 30th August 2021 @ ~7am is 1630306800000 + // 30th August 2021 @ 12am is 1630281600000 (start of day) + Timestamp::set_timestamp(1630306800000u64); + MiningRewardsAllowanceTestModule::on_initialize(5); + + // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded + // amount below the min. bonded DHX daily amount + assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); + // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX + assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); + // the change between each multiplier period is 10 unless a user sets it to a different value + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); + // start of new multiplier period + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); + + // Note - these are just notes. no further action required + // Note - why is this 2u128 instead of reset back to say 5000u128 DHX (unless set do different value?? + // this should be reset after rewards aggregated/accumulated each day + // since distribution/claiming may not be done by a user each day + // Update: it gets reset but difficult to add a test, have to run the logs with only one test running to see it gets accumulated/aggregated + // to all miners each day over a few days + assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630281600000), Some(FIVE_THOUSAND_DHX)); + // TODO - see other notes about status of using `rewards_allowance_dhx_for_date_remaining_distributed` in future. + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630281600000), Some(false)); } fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { From 7b8c7e0c02099c6cfd649b7c13eac2011dab8249 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 20 Dec 2021 12:26:00 +0100 Subject: [PATCH 35/37] wip --- node/src/chain_spec.rs | 12 +- pallets/mining/rewards-allowance/src/lib.rs | 683 ++++++++---------- pallets/mining/rewards-allowance/src/mock.rs | 6 +- pallets/mining/rewards-allowance/src/tests.rs | 212 ++++-- 4 files changed, 444 insertions(+), 469 deletions(-) diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index c39b5ae78..71292c861 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -950,8 +950,8 @@ fn testnet_genesis( min_mpower_daily: 1u128, min_mpower_daily_default: 1u128, challenge_period_days: 7u64, - cooling_off_period_days: 7u32, - cooling_off_period_days_remaining: vec![ + cooling_down_period_days: 7u32, + cooling_down_period_days_remaining: vec![ ( // get_account_id_from_seed::("Alice").encode(), // Alice @@ -959,7 +959,6 @@ fn testnet_genesis( ( 0, 7u32, - 0u32, ), ), ( @@ -968,7 +967,6 @@ fn testnet_genesis( ( 0, 7u32, - 0u32, ), ), ], @@ -1097,8 +1095,8 @@ fn mainnet_genesis( min_mpower_daily: 1u128, min_mpower_daily_default: 1u128, challenge_period_days: 7u64, - cooling_off_period_days: 7u32, - cooling_off_period_days_remaining: vec![ + cooling_down_period_days: 7u32, + cooling_down_period_days_remaining: vec![ ( // get_account_id_from_seed::("Alice").encode(), // Alice @@ -1106,7 +1104,6 @@ fn mainnet_genesis( ( 0, 7u32, - 0u32, ), ), ( @@ -1115,7 +1112,6 @@ fn mainnet_genesis( ( 0, 7u32, - 0u32, ), ), ], diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index 71f7a3617..d46be2906 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -430,28 +430,19 @@ pub mod pallet { pub(super) type ChallengePeriodDays = StorageValue<_, u64>; #[pallet::storage] - #[pallet::getter(fn cooling_off_period_days)] - pub(super) type CoolingOffPeriodDays = StorageValue<_, u32>; + #[pallet::getter(fn cooling_down_period_days)] + pub(super) type CoolingDownPeriodDays = StorageValue<_, u32>; #[pallet::storage] - #[pallet::getter(fn cooling_off_period_days_remaining)] - pub(super) type CoolingOffPeriodDaysRemaining = StorageMap<_, Blake2_128Concat, + #[pallet::getter(fn cooling_down_period_days_remaining)] + pub(super) type CoolingDownPeriodDaysRemaining = StorageMap<_, Blake2_128Concat, Vec, // public key of AccountId ( - // date when cooling off period started for a given miner, or the date when we last reduced their cooling off period. - // we do not reduce their cooling off period days remaining if we've already set this to a date that is the + // date when cooling down period started for a given miner, or the date when we last reduced their cooling down period. + // we do not reduce their cooling down period days remaining if we've already set this to a date that is the // current date for a miner (i.e. only reduce the days remaining once per day per miner) Date, u32, // days remaining - // 0: - // unbonded (i.e. never bonded, insufficient bonded, or finished cool-down period and no longer bonding) and - // insufficient mPower (i.e. less than min. mPower) - // 1: bonded/bonding/mPower (i.e. waiting in the cool-down period before start getting rewards or eligible for rewards) - // 2: unbonding (i.e. if they are bonding less than the threshold whilst getting rewards, - // or no longer have the min. mPower, then - // this unbonding starts and they must wait until it finishes, which is when this value - // would be set to 0u32, before bonding and then waiting for the cool-down period all over again) - u32, ), >; @@ -519,8 +510,8 @@ pub mod pallet { pub min_mpower_daily: u128, pub min_mpower_daily_default: u128, pub challenge_period_days: u64, - pub cooling_off_period_days: u32, - pub cooling_off_period_days_remaining: Vec<(Vec, (Date, u32, u32))>, + pub cooling_down_period_days: u32, + pub cooling_down_period_days_remaining: Vec<(Vec, (Date, u32))>, } // The default value for the genesis config type. @@ -558,16 +549,15 @@ pub mod pallet { min_mpower_daily: 5u128, min_mpower_daily_default: 5u128, challenge_period_days: Default::default(), - cooling_off_period_days: Default::default(), + cooling_down_period_days: Default::default(), // Note: this doesn't seem to work, even if it's just `vec![Default::default()]` it doesn't use - // the defaults in chain_spec.rs, so we set defaults later with `let mut cooling_off_period_days_remaining` - cooling_off_period_days_remaining: vec![ + // the defaults in chain_spec.rs, so we set defaults later with `let mut cooling_down_period_days_remaining` + cooling_down_period_days_remaining: vec![ ( Default::default(), ( Default::default(), Default::default(), - Default::default(), ), ), ] @@ -616,9 +606,9 @@ pub mod pallet { >::put(&self.min_mpower_daily); >::put(&self.min_mpower_daily_default); >::put(&self.challenge_period_days); - >::put(&self.cooling_off_period_days); - for (a, (b, c, d)) in &self.cooling_off_period_days_remaining { - >::insert(a, (b, c, d)); + >::put(&self.cooling_down_period_days); + for (a, (b, c)) in &self.cooling_down_period_days_remaining { + >::insert(a, (b, c)); } } } @@ -653,9 +643,9 @@ pub mod pallet { /// \[challenge_period_days\] SetChallengePeriodDaysStored(u64), - /// Storage of the default cooling off period in days - /// \[cooling_off_period_days\] - SetCoolingOffPeriodDaysStored(u32), + /// Storage of the default cooling down period in days + /// \[cooling_down_period_days\] + SetCoolingDownPeriodDaysStored(u32), /// Storage of the bonded DHX of an account on a specific date. /// \[date, amount_dhx_bonded, account_dhx_bonded\] @@ -1510,127 +1500,107 @@ pub mod pallet { // See Dhx-pop-mining-automatic.md in https://mxc.atlassian.net/browse/MMD-717 that explains off-chain worker // aspects - let cooling_off_period_days; - if let Some(_cooling_off_period_days) = >::get() { - cooling_off_period_days = _cooling_off_period_days; + let cooling_down_period_days; + if let Some(_cooling_down_period_days) = >::get() { + cooling_down_period_days = _cooling_down_period_days; } else { - log::error!("Unable to retrieve cooling off period days"); + log::error!("Unable to retrieve cooling down period days"); + println!("Unable to retrieve cooling down period days"); return 0; } - let mut cooling_off_period_days_remaining = ( + // fallback incase not already set + let mut cooling_down_period_days_remaining = ( start_of_requested_date_millis.clone(), - 7u32, 0u32, ); - if let Some(_cooling_off_period_days_remaining) = >::get(miner_public_key.clone()) { - // we do not change cooling_off_period_days_remaining.0 to the default value in the chain_spec.rs of 0, + if let Some(_cooling_down_period_days_remaining) = >::get(miner_public_key.clone()) { + // we do not change cooling_down_period_days_remaining.0 to the default value in the chain_spec.rs of 0, // instead we want to use today's date `start_of_requested_date_millis.clone()` by default, as we did above. - if _cooling_off_period_days_remaining.0 != 0 { - cooling_off_period_days_remaining.0 = _cooling_off_period_days_remaining.0; + if _cooling_down_period_days_remaining.0 != 0 { + cooling_down_period_days_remaining.0 = _cooling_down_period_days_remaining.0; } - cooling_off_period_days_remaining.1 = _cooling_off_period_days_remaining.1; - cooling_off_period_days_remaining.2 = _cooling_off_period_days_remaining.2; + cooling_down_period_days_remaining.1 = _cooling_down_period_days_remaining.1; } else { - log::info!("Unable to retrieve cooling off period days remaining for given miner, using default {:?}", miner_public_key.clone()); + log::info!("Unable to retrieve cooling down period days remaining for given miner, using default {:?}", miner_public_key.clone()); + println!("Unable to retrieve cooling down period days remaining for given miner, using default {:?}", miner_public_key.clone()); } - log::info!("cooling_off_period_days_remaining {:?} {:?} {:?}", start_of_requested_date_millis.clone(), cooling_off_period_days_remaining, miner_public_key.clone()); - // if cooling_off_period_days_remaining.2 is 0u32, it means we haven't recognised they that have the min. bonded yet (or unbonded), - // they aren't currently bonding, they haven't started cooling off to start bonding, - // or have already finished cooling down after bonding. - // so if we detect they are now bonding above the min. then we should start at max. remaining days - // before starting to decrement on subsequent blocks - // - // note: they don't have have the min. mpower yet to progress through the cooling period, but they won't be - // eligible for rewards on the days that they don't + + log::info!("cooling_down_period_days_remaining {:?} {:?} {:?}", start_of_requested_date_millis.clone(), cooling_down_period_days_remaining, miner_public_key.clone()); + println!("cooling_down_period_days_remaining {:?} {:?} {:?}", start_of_requested_date_millis.clone(), cooling_down_period_days_remaining, miner_public_key.clone()); + + // if they stop bonding the min dhx, and + // if cooling_down_period_days_remaining.1 is Some(0) + // so since we detected they are no longer bonding above the min. + // then we should start at max. remaining days before starting to decrement on subsequent blocks if - cooling_off_period_days_remaining.2 == 0u32 && - is_bonding_min_dhx == true - // && has_min_mpower_daily == true + cooling_down_period_days_remaining.1 == 0u32 && + is_bonding_min_dhx == false { - >::insert( + // Write the new value to storage + >::insert( miner_public_key.clone(), ( start_of_requested_date_millis.clone(), - cooling_off_period_days.clone(), - 1u32, // they are bonded again, waiting to start getting rewards + cooling_down_period_days.clone(), ), ); - log::info!("Added CoolingOffPeriodDaysRemaining for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), cooling_off_period_days.clone()); - // if cooling_off_period_days_remaining.0 is not the start of the current date - // (since if they just started with min. bonded dhx and we just set days remaining to 7, or we already decremented + + log::info!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_down_period_days.clone()); + println!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_down_period_days.clone()); + + // if cooling_down_period_days_remaining.0 is not the start of the current date + // (since if they just started un-bonding + // and we just set days remaining to 7, or we already decremented // a miner's days remaining for the current date, then we want to wait until the next day until we // decrement another day). - // if cooling_off_period_days_remaining.1 is Some(above 0), then decrement, but not eligible yet for rewards. - // - // note: they don't have have the min. mpower yet to progress through the cooling period, but they won't be - // eligible for rewards on the days that they don't + // if cooling_down_period_days_remaining.1 is Some(above 0), then decrement, + // but not yet completely unbonded so cannot claim rewards yet } else if - cooling_off_period_days_remaining.0 != start_of_requested_date_millis.clone() && - cooling_off_period_days_remaining.1 > 0u32 && - is_bonding_min_dhx == true - // && has_min_mpower_daily == true + cooling_down_period_days_remaining.0 != start_of_requested_date_millis.clone() && + cooling_down_period_days_remaining.1 > 0u32 && + is_bonding_min_dhx == false { - println!("[reducing_days] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); - let old_cooling_off_period_days_remaining = cooling_off_period_days_remaining.1.clone(); - - // we cannot do this because of error: cannot use the `?` operator in a method that returns `()` - // let new_cooling_off_period_days_remaining = - // old_cooling_off_period_days_remaining.checked_sub(One::one()).ok_or(Error::::StorageOverflow)?; + let old_cooling_down_period_days_remaining = cooling_down_period_days_remaining.1.clone(); // Subtract, handling overflow - let new_cooling_off_period_days_remaining; - let _new_cooling_off_period_days_remaining = - old_cooling_off_period_days_remaining.checked_sub(One::one()); - match _new_cooling_off_period_days_remaining { + let new_cooling_down_period_days_remaining; + let _new_cooling_down_period_days_remaining = + old_cooling_down_period_days_remaining.checked_sub(One::one()); + match _new_cooling_down_period_days_remaining { None => { - log::error!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); + log::error!("Unable to subtract one from cooling_down_period_days_remaining due to StorageOverflow"); + println!("Unable to subtract one from cooling_down_period_days_remaining due to StorageOverflow"); + return 0; }, Some(x) => { - new_cooling_off_period_days_remaining = x; + new_cooling_down_period_days_remaining = x; } } // Write the new value to storage - >::insert( + >::insert( miner_public_key.clone(), ( start_of_requested_date_millis.clone(), - new_cooling_off_period_days_remaining.clone(), - 1u32, // they are bonded again, waiting to start getting rewards + new_cooling_down_period_days_remaining.clone(), ), ); - log::info!("Reduced CoolingOffPeriodDaysRemaining for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_cooling_off_period_days_remaining.clone()); - // if cooling_off_period_days_remaining.0 is not the start of the current date - // (since if we decremented days remaining from 1 to 0 days left for a miner - // then we want to wait until the next day before we distribute the rewards to them) - // if cooling_off_period_days_remaining.1 is Some(0), - // and if cooling_off_period_days_remaining.2 is 1 - // and then no more cooling off days, but don't decrement, - // and say they are eligible for reward payments (for days when they have sufficient mPower) - // - // note: they don't have have the min. mpower yet to progress through the cooling period, but they won't be - // eligible for rewards on the days that they don't - } else if - cooling_off_period_days_remaining.0 != start_of_requested_date_millis.clone() && - cooling_off_period_days_remaining.1 == 0u32 && - cooling_off_period_days_remaining.2 == 1u32 && + + println!("[reduce] block: {:#?}, miner: {:#?}, date_start: {:#?} new_cooling_down_period_days_remaining: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_cooling_down_period_days_remaining); + log::info!("Unbonded miner. Reducing cooling down period dates remaining {:?} {:?}", miner_public_key.clone(), new_cooling_down_period_days_remaining.clone()); + } + + // to calculate eligible rewards allowance each day then just need to be: + // - bonding the min. dhx + // - not unbonded at any block on the day being processed (since otherwise they have to wait the unbonding period) + if + cooling_down_period_days_remaining.1 == 0u32 && is_bonding_min_dhx == true - // && has_min_mpower_daily == true { - log::info!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); - println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_off_period_days_remaining); - - // we need to add that they are eligible for rewards on the current date too - >::insert( - miner_public_key.clone(), - ( - start_of_requested_date_millis.clone(), - 0u32, - 1u32, - ), - ); + log::info!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_down_period_days_remaining); + println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} remain_days: {:#?}", block_number, miner_count, start_of_requested_date_millis, cooling_down_period_days_remaining); // only accumulate the DHX reward for each registered miner once per day // https://substrate.dev/rustdocs/latest/frame_support/storage/trait.StorageMap.html @@ -1643,280 +1613,32 @@ pub mod pallet { continue; } - // TODO - calculate the daily reward for the miner in DHX based on their mPower - // and add that to the new_rewards_aggregated_dhx_daily_as_u128 (which currently only - // includes the proportion of their reward based on their bonded DHX tokens) of all - // miner's for that day, and also add that to the accumulated rewards for that specific - // miner on that day. - - // calculate the daily reward for the miner in DHX based on their bonded DHX. - // it should be a proportion taking other eligible miner's who are eligible for - // daily rewards into account since we want to split them fairly. - // - // assuming min_bonded_dhx_daily is 10u128, and they have that minimum of 10 DHX bonded (10u128) for - // the locks_first_amount_as_u128 value, then they are eligible for 1 DHX reward if they have 1 mPower - // - - // Divide, handling overflow - let mut div_bonded_as_u128 = 0u128; - // note: this rounds down to the nearest integer - let _div_bonded_as_u128 = locks_first_amount_as_u128.clone().checked_div(min_bonded_dhx_daily_u128.clone()); - match _div_bonded_as_u128 { - None => { - log::error!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); - return 0; - }, - Some(x) => { - div_bonded_as_u128 = x; - } - } - log::info!("div_bonded_as_u128: {:?}", div_bonded_as_u128.clone()); - - // Multiply, handling overflow - let mut daily_reward_for_miner_as_u128 = 0u128; - // note: this rounds down to the nearest integer - let _daily_reward_for_miner_as_u128 = mpower_current_u128.clone().checked_mul(div_bonded_as_u128.clone()); - match _daily_reward_for_miner_as_u128 { - None => { - log::error!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); - return 0; - }, - Some(x) => { - daily_reward_for_miner_as_u128 = x; - } - } - log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); - println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} daily_reward_for_miner_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, daily_reward_for_miner_as_u128); - - // if we have a rewards_aggregated_dhx_daily of 25.133 k DHX, then after the above manipulation - // since we're dealing with a mixture of u128 and BalanceOf so the values are more readable in the UI. - // the reward will be represented as 2.5130 f DHX (where f is femto 10^-18, i.e. 0.000_000_000_000_002_513) - // so we need to multiply it by 1_000_000_000_000_000_000 to be represented in DHX instead of femto DHX - // before storing the value. we need to do the same for the rewards accumulated value before it is stored. - // daily_reward_for_miner_as_u128 = daily_reward_for_miner_as_u128; - if let Some(_daily_reward_for_miner_as_u128) = daily_reward_for_miner_as_u128.clone().checked_mul(1_000_000_000_000_000_000u128) { - daily_reward_for_miner_as_u128 = _daily_reward_for_miner_as_u128; - } else { - log::error!("Unable to multiply daily_reward_for_miner_as_u128"); - } - - let mut daily_reward_for_miner; - let _daily_reward_for_miner = Self::convert_u128_to_balance(daily_reward_for_miner_as_u128.clone()); - match _daily_reward_for_miner { - Err(_e) => { - log::error!("Unable to convert u128 to balance for daily_reward_for_miner"); - return 0; - }, - Ok(ref x) => { - daily_reward_for_miner = x; - } - } - log::info!("daily_reward_for_miner: {:?}", daily_reward_for_miner.clone()); - - let mut rewards_aggregated_dhx_daily: BalanceOf = 0u32.into(); // initialize - if let Some(_rewards_aggregated_dhx_daily) = >::get(&start_of_requested_date_millis) { - rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; - } else { - log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily"); - } - - let rewards_aggregated_dhx_daily_as_u128; - let _rewards_aggregated_dhx_daily_as_u128 = Self::convert_balance_to_u128(rewards_aggregated_dhx_daily.clone()); - match _rewards_aggregated_dhx_daily_as_u128.clone() { - Err(_e) => { - log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); - return 0; - }, - Ok(x) => { - rewards_aggregated_dhx_daily_as_u128 = x; - } - } - - // Add, handling overflow - let mut new_rewards_aggregated_dhx_daily_as_u128; - let _new_rewards_aggregated_dhx_daily_as_u128 = - rewards_aggregated_dhx_daily_as_u128.clone().checked_add(daily_reward_for_miner_as_u128.clone()); - match _new_rewards_aggregated_dhx_daily_as_u128 { - None => { - log::error!("Unable to add daily_reward_for_miner to rewards_aggregated_dhx_daily due to StorageOverflow"); - return 0; - }, - Some(x) => { - new_rewards_aggregated_dhx_daily_as_u128 = x; - } - } - - log::info!("new_rewards_aggregated_dhx_daily_as_u128: {:?}", new_rewards_aggregated_dhx_daily_as_u128.clone()); - println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} new_rewards_aggregated_dhx_daily_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_aggregated_dhx_daily_as_u128); - - let new_rewards_aggregated_dhx_daily; - let _new_rewards_aggregated_dhx_daily = Self::convert_u128_to_balance(new_rewards_aggregated_dhx_daily_as_u128.clone()); - match _new_rewards_aggregated_dhx_daily { - Err(_e) => { - log::error!("Unable to convert u128 to balance for new_rewards_aggregated_dhx_daily"); - return 0; - }, - Ok(ref x) => { - new_rewards_aggregated_dhx_daily = x; - } - } - - // add to storage item that accumulates total rewards for all registered miners for the day - >::insert( - start_of_requested_date_millis.clone(), - new_rewards_aggregated_dhx_daily.clone(), - ); - log::info!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); - println!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); - - // add to storage item that maps the date to the registered miner and the calculated reward - // (prior to possibly reducing it so they get a proportion of the daily rewards that are available) - >::insert( - ( - start_of_requested_date_millis.clone(), - miner_public_key.clone(), - ), - daily_reward_for_miner.clone(), - ); - log::info!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); - println!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); - - // Store a list of all the the registered_dhx_miners that are eligible for rewards on a given date - // so we know they have been used as keys for other storage maps like `RewardsAccumulatedDHXForMinerForDate` - // for future querying - let mut rewards_eligible_miners_for_date: Vec> = vec![]; // initialize - if let Some(_rewards_eligible_miners_for_date) = >::get(start_of_requested_date_millis.clone()) { - rewards_eligible_miners_for_date = _rewards_eligible_miners_for_date; - } else { - log::warn!("Unable to retrieve rewards_eligible_miners_for_date"); - println!("Unable to retrieve rewards_eligible_miners_for_date"); - } - log::info!("Retrieved existing rewards_eligible_miners_for_date {:?} {:?}", start_of_requested_date_millis.clone(), rewards_eligible_miners_for_date.clone()); - println!("Retrieved existing rewards_eligible_miners_for_date {:?} {:?}", start_of_requested_date_millis.clone(), rewards_eligible_miners_for_date.clone()); - - log::warn!("Updating rewards_eligible_miners_for_date with miner {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone()); - println!("Updating retrieve rewards_eligible_miners_for_date with miner {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone()); - - rewards_eligible_miners_for_date.push(miner_public_key.clone()); - >::insert( - start_of_requested_date_millis.clone(), - rewards_eligible_miners_for_date.clone(), - ); - - log::info!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); - println!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); - // if last miner being iterated then reset for next day - if reg_dhx_miners.len() == miner_count { - log::info!("date: {:?}, rewards_allowance_dhx_daily: {:?}", start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); - println!("date: {:?}, rewards_allowance_dhx_daily: {:?}", start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); - - // reset to latest set by governance - >::insert(start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); - }; - - // if they stop bonding the min dhx, and - // if cooling_off_period_days_remaining.1 is Some(0), - // and if cooling_off_period_days_remaining.2 is 1 (where they had just been bonding and getting rewards) - // so since we detected they are no longer bonding above the min. - // then we should start at max. remaining days before starting to decrement on subsequent blocks - } else if - cooling_off_period_days_remaining.1 == 0u32 && - cooling_off_period_days_remaining.2 == 1u32 && - is_bonding_min_dhx == false - // (is_bonding_min_dhx == false || has_min_mpower_daily == false) - { - // Write the new value to storage - >::insert( + let _result_calculate_rewards_eligibility = Self::calculate_rewards_eligibility_of_miner_for_day( miner_public_key.clone(), - ( - start_of_requested_date_millis.clone(), - cooling_off_period_days.clone(), - 2u32, // they have unbonded again, waiting to finish cooling down period - ), + start_of_requested_date_millis.clone(), + locks_first_amount_as_u128.clone(), + rewards_allowance_dhx_daily.clone(), + min_bonded_dhx_daily_u128.clone(), + mpower_current_u128.clone(), + block_number.clone(), + miner_count.clone(), + reg_dhx_miners.clone(), ); - - log::info!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_off_period_days.clone()); - println!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_off_period_days.clone()); - - // if cooling_off_period_days_remaining.0 is not the start of the current date - // (since if they just started un-bonding - // and we just set days remaining to 7, or we already decremented - // a miner's days remaining for the current date, then we want to wait until the next day until we - // decrement another day). - // if cooling_off_period_days_remaining.1 is Some(above 0), then decrement, - // but not yet completely unbonded so cannot withdraw yet - // note: we don't care if they stop bonding below the min. dhx or have less than min. mPower - // during the cooling off period, - // as the user needs to learn that they should always been bonding the min., otherwise they - // have to wait for entire cooling down period and then the cooling off period again. - // and they need to have the min. mPower to earn rewards - // - } else if - cooling_off_period_days_remaining.0 != start_of_requested_date_millis.clone() && - cooling_off_period_days_remaining.1 > 0u32 && - cooling_off_period_days_remaining.2 == 2u32 - // && is_bonding_min_dhx == false - { - let old_cooling_off_period_days_remaining = cooling_off_period_days_remaining.1.clone(); - - // Subtract, handling overflow - let new_cooling_off_period_days_remaining; - let _new_cooling_off_period_days_remaining = - old_cooling_off_period_days_remaining.checked_sub(One::one()); - match _new_cooling_off_period_days_remaining { - None => { - log::error!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); - println!("Unable to subtract one from cooling_off_period_days_remaining due to StorageOverflow"); - + match _result_calculate_rewards_eligibility { + Err(_e) => { return 0; }, - Some(x) => { - new_cooling_off_period_days_remaining = x; + Ok(ref x) => { } } - // Write the new value to storage - >::insert( - miner_public_key.clone(), - ( - start_of_requested_date_millis.clone(), - new_cooling_off_period_days_remaining.clone(), - 2u32, // they have unbonded or have less than min. mPower again, waiting to finish cooling down period - ), - ); - - println!("[reduce] block: {:#?}, miner: {:#?}, date_start: {:#?} new_cooling_off_period_days_remaining: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_cooling_off_period_days_remaining); - log::info!("Unbonded miner. Reducing cooling down period dates remaining {:?} {:?}", miner_public_key.clone(), new_cooling_off_period_days_remaining.clone()); - - // if cooling_off_period_days_remaining.0 is not the start of the current date - // (since if we decremented days remaining to from 1 to 0 days left for a miner - // then we want to wait until the next day before we set cooling_off_period_days_remaining.2 to 0u32 - // to allow them to be completely unbonded and withdraw). - // if cooling_off_period_days_remaining.1 is Some(0), do not subtract anymore, they are - // completely unbonded so can withdraw - } else if - cooling_off_period_days_remaining.0 != start_of_requested_date_millis.clone() && - cooling_off_period_days_remaining.1 == 0u32 && - cooling_off_period_days_remaining.2 == 2u32 - // && is_bonding_min_dhx == false - { - // Write the new value to storage - >::insert( - miner_public_key.clone(), - ( - start_of_requested_date_millis.clone(), - 0u32, - 0u32, // they are completely unbonded again - ), - ); - - log::info!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); - println!("Unbonded miner. Cooling down period finished so allow them to withdraw {:?}", miner_public_key.clone()); + log::info!("Finished calculating eligible rewards date_start: {:#?}", start_of_requested_date_millis); + println!("Finished calculating eligible rewards date_start: {:#?}", start_of_requested_date_millis); } } - log::info!("Finished initial loop of registered miners"); - println!("Finished initial loop of registered miners"); + log::info!("Finished loop of registered miners for block"); + println!("Finished loop of registered miners for block"); return 0; } @@ -1997,14 +1719,14 @@ pub mod pallet { // only modifiable by governance as root rather than just any user #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn set_cooling_off_period_days(origin: OriginFor, cooling_off_period_days: u32) -> DispatchResult { + pub fn set_cooling_down_period_days(origin: OriginFor, cooling_down_period_days: u32) -> DispatchResult { let _sender = ensure_root(origin)?; - >::put(&cooling_off_period_days.clone()); - log::info!("cooling_off_period_days: {:?}", &cooling_off_period_days); + >::put(&cooling_down_period_days.clone()); + log::info!("cooling_down_period_days: {:?}", &cooling_down_period_days); - Self::deposit_event(Event::SetCoolingOffPeriodDaysStored( - cooling_off_period_days.clone(), + Self::deposit_event(Event::SetCoolingDownPeriodDaysStored( + cooling_down_period_days.clone(), )); Ok(()) @@ -2224,8 +1946,8 @@ pub mod pallet { // check that the current date start_of_current_date_millis is at least 7 days after the provided start_of_requested_date_millis // so there is sufficient time for the community to audit the reward eligibility. - // we could use `CoolingOffPeriodDays` for this, but probably better to call it a `ChallengePeriodDays` - // since it serves a different purpose (`CoolingOffPeriodDays` gives rewards for first 7 days after they + // we could use `CoolingDownPeriodDays` for this, but probably better to call it a `ChallengePeriodDays` + // since it serves a different purpose (`CoolingDownPeriodDays` gives rewards for first 7 days after they // start bonding in bulk on the 8th day, and then the next day after each day after that, whereas // `ChallengePeriodDays` you can only claim each daily rewards manually 7 days after it, even for the first // 7 days after they start bonding) @@ -2266,11 +1988,11 @@ pub mod pallet { if let Some(_rewards_aggregated_dhx_daily) = >::get(&start_of_requested_date_millis) { rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; } else { - log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet"); - println!("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet"); + log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily. cooling down period or challenge period may not be finished yet"); + println!("Unable to retrieve balance for rewards_aggregated_dhx_daily. cooling down period or challenge period may not be finished yet"); // Note: it would be an issue if we got past the first loop of looping through the registered miners // and still hadn't added to the aggregated rewards for the day - return Err(DispatchError::Other("Unable to retrieve balance for rewards_aggregated_dhx_daily. Cooling off period or challenge period may not be finished yet")); + return Err(DispatchError::Other("Unable to retrieve balance for rewards_aggregated_dhx_daily. cooling down period or challenge period may not be finished yet")); } println!("[multiplier] block: {:#?}, date_start: {:#?} rewards_aggregated_dhx_daily: {:#?}", block_number, start_of_requested_date_millis, rewards_aggregated_dhx_daily); @@ -3261,6 +2983,199 @@ pub mod pallet { Ok(new_status.clone()) } + pub fn calculate_rewards_eligibility_of_miner_for_day( + miner_public_key: Vec, + start_of_requested_date_millis: i64, + locks_first_amount_as_u128: u128, + rewards_allowance_dhx_daily: BalanceOf, + min_bonded_dhx_daily_u128: u128, + mpower_current_u128: u128, + block_number: T::BlockNumber, + miner_count: usize, + reg_dhx_miners: Vec>, + ) -> Result<(), &'static str> { + log::info!("calculate_rewards_eligibility_of_miner_for_day"); + println!("calculate_rewards_eligibility_of_miner_for_day"); + + // TODO - calculate the daily reward for the miner in DHX based on their mPower + // and add that to the new_rewards_aggregated_dhx_daily_as_u128 (which currently only + // includes the proportion of their reward based on their bonded DHX tokens) of all + // miner's for that day, and also add that to the accumulated rewards for that specific + // miner on that day. + + // calculate the daily reward for the miner in DHX based on their bonded DHX. + // it should be a proportion taking other eligible miner's who are eligible for + // daily rewards into account since we want to split them fairly. + // + // assuming min_bonded_dhx_daily is 10u128, and they have that minimum of 10 DHX bonded (10u128) for + // the locks_first_amount_as_u128 value, then they are eligible for 1 DHX reward if they have 1 mPower + // + + // Divide, handling overflow + let mut div_bonded_as_u128 = 0u128; + // note: this rounds down to the nearest integer + let _div_bonded_as_u128 = locks_first_amount_as_u128.clone().checked_div(min_bonded_dhx_daily_u128.clone()); + match _div_bonded_as_u128 { + None => { + log::error!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); + println!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); + return Err("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); + }, + Some(x) => { + div_bonded_as_u128 = x; + } + } + log::info!("div_bonded_as_u128: {:?}", div_bonded_as_u128.clone()); + + // Multiply, handling overflow + let mut daily_reward_for_miner_as_u128 = 0u128; + // note: this rounds down to the nearest integer + let _daily_reward_for_miner_as_u128 = mpower_current_u128.clone().checked_mul(div_bonded_as_u128.clone()); + match _daily_reward_for_miner_as_u128 { + None => { + log::error!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); + println!("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); + return Err("Unable to divide min_bonded_dhx_daily from locks_first_amount_as_u128 due to StorageOverflow"); + }, + Some(x) => { + daily_reward_for_miner_as_u128 = x; + } + } + log::info!("daily_reward_for_miner_as_u128: {:?}", daily_reward_for_miner_as_u128.clone()); + println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} daily_reward_for_miner_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, daily_reward_for_miner_as_u128); + + // if we have a rewards_aggregated_dhx_daily of 25.133 k DHX, then after the above manipulation + // since we're dealing with a mixture of u128 and BalanceOf so the values are more readable in the UI. + // the reward will be represented as 2.5130 f DHX (where f is femto 10^-18, i.e. 0.000_000_000_000_002_513) + // so we need to multiply it by 1_000_000_000_000_000_000 to be represented in DHX instead of femto DHX + // before storing the value. we need to do the same for the rewards accumulated value before it is stored. + // daily_reward_for_miner_as_u128 = daily_reward_for_miner_as_u128; + if let Some(_daily_reward_for_miner_as_u128) = daily_reward_for_miner_as_u128.clone().checked_mul(1_000_000_000_000_000_000u128) { + daily_reward_for_miner_as_u128 = _daily_reward_for_miner_as_u128; + } else { + log::error!("Unable to multiply daily_reward_for_miner_as_u128"); + } + + let mut daily_reward_for_miner; + let _daily_reward_for_miner = Self::convert_u128_to_balance(daily_reward_for_miner_as_u128.clone()); + match _daily_reward_for_miner { + Err(_e) => { + log::error!("Unable to convert u128 to balance for daily_reward_for_miner"); + println!("Unable to convert u128 to balance for daily_reward_for_miner"); + return Err("Unable to convert u128 to balance for daily_reward_for_miner"); + }, + Ok(ref x) => { + daily_reward_for_miner = x; + } + } + log::info!("daily_reward_for_miner: {:?}", daily_reward_for_miner.clone()); + + let mut rewards_aggregated_dhx_daily: BalanceOf = 0u32.into(); // initialize + if let Some(_rewards_aggregated_dhx_daily) = >::get(&start_of_requested_date_millis) { + rewards_aggregated_dhx_daily = _rewards_aggregated_dhx_daily; + } else { + log::error!("Unable to retrieve balance for rewards_aggregated_dhx_daily"); + } + + let rewards_aggregated_dhx_daily_as_u128; + let _rewards_aggregated_dhx_daily_as_u128 = Self::convert_balance_to_u128(rewards_aggregated_dhx_daily.clone()); + match _rewards_aggregated_dhx_daily_as_u128.clone() { + Err(_e) => { + log::error!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); + println!("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); + return Err("Unable to convert balance to u128 for rewards_aggregated_dhx_daily_as_u128"); + }, + Ok(x) => { + rewards_aggregated_dhx_daily_as_u128 = x; + } + } + + // Add, handling overflow + let mut new_rewards_aggregated_dhx_daily_as_u128; + let _new_rewards_aggregated_dhx_daily_as_u128 = + rewards_aggregated_dhx_daily_as_u128.clone().checked_add(daily_reward_for_miner_as_u128.clone()); + match _new_rewards_aggregated_dhx_daily_as_u128 { + None => { + log::error!("Unable to add daily_reward_for_miner to rewards_aggregated_dhx_daily due to StorageOverflow"); + println!("Unable to add daily_reward_for_miner to rewards_aggregated_dhx_daily due to StorageOverflow"); + return Err("Unable to add daily_reward_for_miner to rewards_aggregated_dhx_daily due to StorageOverflow"); + }, + Some(x) => { + new_rewards_aggregated_dhx_daily_as_u128 = x; + } + } + + log::info!("new_rewards_aggregated_dhx_daily_as_u128: {:?}", new_rewards_aggregated_dhx_daily_as_u128.clone()); + println!("[eligible] block: {:#?}, miner: {:#?}, date_start: {:#?} new_rewards_aggregated_dhx_daily_as_u128: {:#?}", block_number, miner_count, start_of_requested_date_millis, new_rewards_aggregated_dhx_daily_as_u128); + + let new_rewards_aggregated_dhx_daily; + let _new_rewards_aggregated_dhx_daily = Self::convert_u128_to_balance(new_rewards_aggregated_dhx_daily_as_u128.clone()); + match _new_rewards_aggregated_dhx_daily { + Err(_e) => { + log::error!("Unable to convert u128 to balance for new_rewards_aggregated_dhx_daily"); + println!("Unable to convert u128 to balance for new_rewards_aggregated_dhx_daily"); + return Err("Unable to convert u128 to balance for new_rewards_aggregated_dhx_daily"); + }, + Ok(ref x) => { + new_rewards_aggregated_dhx_daily = x; + } + } + + // add to storage item that accumulates total rewards for all registered miners for the day + >::insert( + start_of_requested_date_millis.clone(), + new_rewards_aggregated_dhx_daily.clone(), + ); + log::info!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); + println!("Added RewardsAggregatedDHXForAllMinersForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), new_rewards_aggregated_dhx_daily.clone()); + + // add to storage item that maps the date to the registered miner and the calculated reward + // (prior to possibly reducing it so they get a proportion of the daily rewards that are available) + >::insert( + ( + start_of_requested_date_millis.clone(), + miner_public_key.clone(), + ), + daily_reward_for_miner.clone(), + ); + log::info!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); + println!("Added RewardsAccumulatedDHXForMinerForDate for miner {:?} {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone(), daily_reward_for_miner.clone()); + + // Store a list of all the the registered_dhx_miners that are eligible for rewards on a given date + // so we know they have been used as keys for other storage maps like `RewardsAccumulatedDHXForMinerForDate` + // for future querying + let mut rewards_eligible_miners_for_date: Vec> = vec![]; // initialize + if let Some(_rewards_eligible_miners_for_date) = >::get(start_of_requested_date_millis.clone()) { + rewards_eligible_miners_for_date = _rewards_eligible_miners_for_date; + } else { + log::warn!("Unable to retrieve rewards_eligible_miners_for_date"); + println!("Unable to retrieve rewards_eligible_miners_for_date"); + } + log::info!("Retrieved existing rewards_eligible_miners_for_date {:?} {:?}", start_of_requested_date_millis.clone(), rewards_eligible_miners_for_date.clone()); + println!("Retrieved existing rewards_eligible_miners_for_date {:?} {:?}", start_of_requested_date_millis.clone(), rewards_eligible_miners_for_date.clone()); + + log::warn!("Updating rewards_eligible_miners_for_date with miner {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone()); + println!("Updating retrieve rewards_eligible_miners_for_date with miner {:?} {:?}", start_of_requested_date_millis.clone(), miner_public_key.clone()); + + rewards_eligible_miners_for_date.push(miner_public_key.clone()); + >::insert( + start_of_requested_date_millis.clone(), + rewards_eligible_miners_for_date.clone(), + ); + log::info!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); + println!("date: {:?}, miner_count: {:?}, reg_dhx_miners.len: {:?}", start_of_requested_date_millis.clone(), miner_count.clone(), reg_dhx_miners.len()); + // if last miner being iterated then reset for next day + if reg_dhx_miners.len() == miner_count { + log::info!("date: {:?}, rewards_allowance_dhx_daily: {:?}", start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); + println!("date: {:?}, rewards_allowance_dhx_daily: {:?}", start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); + + // reset to latest set by governance + >::insert(start_of_requested_date_millis.clone(), rewards_allowance_dhx_daily.clone()); + }; + + Ok(()) + } + // Offchain workers /// Chooses which transaction type to send. @@ -3717,7 +3632,7 @@ pub mod pallet { // start_of_requested_date_millis so there is sufficient time for the community to audit the reward eligibility, // where the start_of_requested_date_millis refers to a past date the claimant believes they became eligible for rewards on. // - // `CoolingOffPeriodDays` notifies when to give rewards in bulk (previously automatically, now by claiming) on the 8th day in bulk to cover the + // `CoolingDownPeriodDays` notifies when to give rewards in bulk (previously automatically, now by claiming) on the 8th day in bulk to cover the // first say x (i.e. 7) days after they start bonding, and then on the next day after each day after that, and // it is also used to track the unbonding period where if they stop bonding obviously they cannot be eligible // for rewards and they have wait x (i.e. 7) days after unbonding before they can access the locked DHX tokens diff --git a/pallets/mining/rewards-allowance/src/mock.rs b/pallets/mining/rewards-allowance/src/mock.rs index 0a0dce389..592bdc09f 100644 --- a/pallets/mining/rewards-allowance/src/mock.rs +++ b/pallets/mining/rewards-allowance/src/mock.rs @@ -554,9 +554,9 @@ pub fn new_test_ext() -> sp_io::TestExternalities { min_mpower_daily: 1u128, min_mpower_daily_default: 1u128, challenge_period_days: 7u64, - cooling_off_period_days: 7u32, + cooling_down_period_days: 7u32, // Note: i'm not sure how to mock Alice, just set in implementation at genesis - // cooling_off_period_days_remaining: vec![ + // cooling_down_period_days_remaining: vec![ // ( // get_account_id_from_seed::("Alice"), // ( @@ -566,7 +566,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // ), // ), // ], - cooling_off_period_days_remaining: Default::default(), + cooling_down_period_days_remaining: Default::default(), }, &mut t ) diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 225e4f88b..a2f4c37e3 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -17,6 +17,7 @@ use sp_core::{ Hasher, // so we may use BlakeTwo256::hash }; use sp_runtime::{ + DispatchError, traits::{BlakeTwo256}, }; @@ -57,7 +58,7 @@ fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_ } #[test] -// Note: if we remove `cooling_off_period_days_remaining.0 != start_of_requested_date_millis.clone() &&` +// Note: if we remove `cooling_down_period_days_remaining.0 != start_of_requested_date_millis.clone() &&` // four times from the implementation, then all this happens on the same day so we'd need to use the // same timestamp for all the blocks and tests below. fn it_calcs_rewards_allowance_using_on_initialize_with_claim_using_extrinsic_for_default_amount() { @@ -337,9 +338,9 @@ fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: vec![CHARLIE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), ALICE_PUBLIC_KEY.clone().into()], )); - assert_ok!(MiningRewardsAllowanceTestModule::set_cooling_off_period_days( + assert_ok!(MiningRewardsAllowanceTestModule::set_cooling_down_period_days( Origin::root(), - 1_u32, // debug quickly for testing + 7_u32, // debug quickly for testing )); assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_allowance_dhx_daily( Origin::root(), @@ -347,10 +348,10 @@ fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: )); assert_eq!(MiningRewardsAllowanceTestModule::registered_dhx_miners(), Some(vec![ALICE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), CHARLIE_PUBLIC_KEY.clone().into()])); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days(), Some(1)); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days(), Some(7)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_daily(), Some(FIVE_THOUSAND_DHX)); - check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone()); + claim_eligible_rewards_after_challenge_period_if_suffient_bonded(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone()); // // check that rewards multiplier increases by multiplier every period days and that days total and remaining are reset // check_rewards_double_each_multiplier_period(amount_mpower_each_miner.clone()); @@ -445,12 +446,12 @@ fn setup_multiplier() { // since we don't want to wait so long to check that it changes each cycle in the tests assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_default_period_days( Origin::root(), - 2u32, + 90u32, )); assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_next_period_days( Origin::root(), - 2u32, + 90u32, )); } @@ -533,7 +534,7 @@ fn unbond_each_miner_by_removing_their_referendum_vote(referendum_index: u32) { assert_eq!(Balances::locks(account_3_account_id.clone()), vec![]); } -fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128) { +fn claim_eligible_rewards_after_challenge_period_if_suffient_bonded(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128) { let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); let account_2_public_key: Vec = BOB_PUBLIC_KEY.clone().into(); let account_3_public_key: Vec = CHARLIE_PUBLIC_KEY.clone().into(); @@ -560,7 +561,7 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount // 27th August 2021 @ 12am is 1630022400000 (start of day) Timestamp::set_timestamp(1630049371000u64); MiningRewardsAllowanceTestModule::on_initialize(2); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1630022400000, 2u32, 2u32))); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1630022400000, 90u32, 90u32))); // System::on_initialize(2); // System::on_finalize(2); // System::set_block_number(2); @@ -568,6 +569,29 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630022400000), Some(FIVE_THOUSAND_DHX)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630022400000), Some(false)); + // they have at least the min. bonded so they should be eligible for accumulating and aggregating rewards each day + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630022400000, account_1_public_key.clone())), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630022400000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); + assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630022400000, account_3_public_key.clone())), Some(amount_bonded_each_miner)); + + // i.e. for example, if locked is 25_133_000_000_000_000_000_000u128 (NORMAL_AMOUNT), which is 25,133 DHX, + // then with 10:1 each of the 3x accounts get 2513.3 DHX, which is ~7538.9 DHX combined + // or 33_333_333_333_000_000_000_000_000u128 (LARGE_AMOUNT_DHX), + // but the results are rounded to the nearest integer so it would be 2513 DHX, not 2513.3 DHX + if amount_bonded_each_miner.clone() == NORMAL_AMOUNT { + assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630022400000), Some(37_695_000_000_000_000_000_000u128)); + + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630022400000, account_1_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630022400000, account_2_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630022400000, account_3_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { + assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630022400000), Some(49_999_995_000_000_000_000_000_000u128)); + + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630022400000, account_1_public_key.clone())), Some(16_666_665_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630022400000, account_2_public_key.clone())), Some(16_666_665_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630022400000, account_3_public_key.clone())), Some(16_666_665_000_000_000_000_000_000u128)); + } + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1635379200000i64); // https://www.epochconverter.com/ @@ -576,10 +600,10 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount // 28th August 2021 @ 12am is 1635379200000 (start of day) Timestamp::set_timestamp(1635406274000u64); MiningRewardsAllowanceTestModule::on_initialize(3); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1635379200000, 2u32, 1u32))); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1635379200000, 90u32, 89u32))); // check that on_initialize has populated this storage value automatically for the start of the current date - // still cooling off so no rewards distributed on this date + // still cooling down so no rewards distributed on this date assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1635379200000), Some(FIVE_THOUSAND_DHX)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1635379200000), Some(false)); @@ -587,6 +611,24 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1635379200000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1635379200000, account_3_public_key.clone())), Some(amount_bonded_each_miner)); + // i.e. for example, if locked is 25_133_000_000_000_000_000_000u128 (NORMAL_AMOUNT), which is 25,133 DHX, + // then with 10:1 each of the 3x accounts get 2513.3 DHX, which is ~7538.9 DHX combined + // or 33_333_333_333_000_000_000_000_000u128 (LARGE_AMOUNT_DHX), + // but the results are rounded to the nearest integer so it would be 2513 DHX, not 2513.3 DHX + if amount_bonded_each_miner.clone() == NORMAL_AMOUNT { + assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1635379200000), Some(37_695_000_000_000_000_000_000u128)); + + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1635379200000, account_1_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1635379200000, account_2_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1635379200000, account_3_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { + assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1635379200000), Some(49_999_995_000_000_000_000_000_000u128)); + + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1635379200000, account_1_public_key.clone())), Some(16_666_665_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1635379200000, account_2_public_key.clone())), Some(16_666_665_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1635379200000, account_3_public_key.clone())), Some(16_666_665_000_000_000_000_000_000u128)); + } + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630195200000i64); // 29th August 2021 @ ~7am is 1630220400000 @@ -595,7 +637,7 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount MiningRewardsAllowanceTestModule::on_initialize(4); // a day before we start the new multiplier period and change from 10:1 to 20:1 since no more days remaining - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1630195200000, 2u32, 0u32))); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1630195200000, 90u32, 88u32))); assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_1_public_key.clone())), Some(amount_bonded_each_miner)); assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, account_2_public_key.clone())), Some(amount_bonded_each_miner)); @@ -611,25 +653,43 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); - // } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { - assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(37_695_000_000_000_000_000_000u128)); + } else if amount_bonded_each_miner.clone() == LARGE_AMOUNT_DHX { + assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630195200000), Some(49_999_995_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(12_565_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_1_public_key.clone())), Some(16_666_665_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_2_public_key.clone())), Some(16_666_665_000_000_000_000_000_000u128)); + assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630195200000, account_3_public_key.clone())), Some(16_666_665_000_000_000_000_000_000u128)); } - // we can only claim the rewards for a date that was at least the challenge period (i.e. 7 days) prior to the current date - // when a user submits a request to claim rewards that were calculated that they were eligibible for on that prior date + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); - // 6th September 2021 @ 12am is 1630886400000 (start of day) - Timestamp::set_timestamp(1630886400000u64); + // we can only claim the rewards for a date that was at least the challenge period (i.e. 7 days) prior to the current date + // when a user submits a request to claim rewards that were calculated that they were eligible for on that prior date assert_ok!(MiningRewardsAllowanceTestModule::set_challenge_period_days( Origin::root(), 7u64, )); + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630713600000i64); + // 4th September 2021 @ 12am is 1630713600000 (start of day) + Timestamp::set_timestamp(1630713600000u64); + + // try to claim rewards they were NOT eligible for yet on the 29th Aug because it is less than the challenge period ago + // i'll just try claiming the reward for one of the miners + assert_eq!( + MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + Origin::signed(account_1_account_id.clone()), + account_1_public_key.clone(), + 1630713600000 + ), + Err(DispatchError::Other("Unable to retrieve balance for rewards_aggregated_dhx_daily. cooling down period or challenge period may not be finished yet")) + ); + + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630886400000i64); + // 6th September 2021 @ 12am is 1630886400000 (start of day) + Timestamp::set_timestamp(1630886400000u64); + // try to claim rewards they were deemed eligible for back on the 29th Aug // we'll get all three of the registered dhx miners to claim their rewards @@ -639,8 +699,8 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount 1630195200000 )); - // added this so logs appear so i can debug - // assert_eq!(1, 0); + // // added this so logs appear so i can debug + // // assert_eq!(1, 0); assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( Origin::signed(account_2_account_id.clone()), @@ -656,41 +716,45 @@ fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount // after all the registered dhx miners have claimed their rewards this is the amount that should be remaining from the allocated dhx for the date assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); - // TODO - each registered dhx miner is claiming rewards now instead of the rewards being automatically distributed, - // see notes in the implementation lib.rs - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); - - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 1))); - - change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); - - // 30th August 2021 @ ~7am is 1630306800000 - // 30th August 2021 @ 12am is 1630281600000 (start of day) - Timestamp::set_timestamp(1630306800000u64); - MiningRewardsAllowanceTestModule::on_initialize(5); - - // we have finished the cooling off period and should now be distributing rewards each day unless they reduce their bonded - // amount below the min. bonded DHX daily amount - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 1))); - // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX - assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); - // the change between each multiplier period is 10 unless a user sets it to a different value - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); - // start of new multiplier period - assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); - - // Note - these are just notes. no further action required - // Note - why is this 2u128 instead of reset back to say 5000u128 DHX (unless set do different value?? - // this should be reset after rewards aggregated/accumulated each day - // since distribution/claiming may not be done by a user each day - // Update: it gets reset but difficult to add a test, have to run the logs with only one test running to see it gets accumulated/aggregated - // to all miners each day over a few days - assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630281600000), Some(FIVE_THOUSAND_DHX)); - // TODO - see other notes about status of using `rewards_allowance_dhx_for_date_remaining_distributed` in future. - // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630281600000), Some(false)); + // // TODO - each registered dhx miner is claiming rewards now instead of the rewards being automatically distributed, + // // see notes in the implementation lib.rs + // // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); + + + + // TODO - test the multiplier changing works. move the below into a separate test + + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0))); + + // change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); + + // // 30th August 2021 @ ~7am is 1630306800000 + // // 30th August 2021 @ 12am is 1630281600000 (start of day) + // Timestamp::set_timestamp(1630306800000u64); + // MiningRewardsAllowanceTestModule::on_initialize(5); + + // // we have finished the cooling down period and should now be distributing rewards each day unless they reduce their bonded + // // amount below the min. bonded DHX daily amount + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0))); + // // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX + // assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); + // // the change between each multiplier period is 10 unless a user sets it to a different value + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_change(), Some(10u32)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_next_period_days(), Some(2u32)); + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_total(), Some(2u32)); + // // start of new multiplier period + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); + + // // Note - these are just notes. no further action required + // // Note - why is this 2u128 instead of reset back to say 5000u128 DHX (unless set do different value?? + // // this should be reset after rewards aggregated/accumulated each day + // // since distribution/claiming may not be done by a user each day + // // Update: it gets reset but difficult to add a test, have to run the logs with only one test running to see it gets accumulated/aggregated + // // to all miners each day over a few days + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630281600000), Some(FIVE_THOUSAND_DHX)); + // // TODO - see other notes about status of using `rewards_allowance_dhx_for_date_remaining_distributed` in future. + // // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630281600000), Some(false)); } fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { @@ -704,8 +768,8 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { // 31th August 2021 @ 12am is 1630368000000 (start of day) Timestamp::set_timestamp(1630393200000u64); MiningRewardsAllowanceTestModule::on_initialize(6); - // cooling off period doesn't change again unless they unbond - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630368000000, 0, 1))); + // cooling down period doesn't change again unless they unbond + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630368000000, 0))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630368000000, 2u32, 1u32))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); @@ -715,7 +779,7 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { // 1st Sept 2021 @ 12am is 1630454400000 (start of day) Timestamp::set_timestamp(1630479600000u64); MiningRewardsAllowanceTestModule::on_initialize(7); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630454400000, 0, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630454400000, 0))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630454400000, 2u32, 0u32))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); @@ -725,7 +789,7 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { // 2nd Sept 2021 @ 12am is 1630540800000 (start of day) Timestamp::set_timestamp(1630566000000u64); MiningRewardsAllowanceTestModule::on_initialize(7); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630540800000, 0, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630540800000, 0))); // start of new multiplier period assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630540800000, 1630540800000, 2u32, 2u32))); // check that the min_bonded_dhx_daily doubled after 3 months (we're only doing it after 2 days in the tests though) from 20 DHX to 30 DHX @@ -762,9 +826,9 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b // IMPORTANT NOTE: The min. DHX bonded has increased from 10 (10:1) to 20 (20:1) in order to be eligible // for rewards, however none of the miner's increased their bonded DHX amount proportionally to still remain // eligible for rewards, so since having insufficient bonded DHX is the same as unbonding, we expect the - // cooling off period days remaining to change so they are now going through the unbonding cool down period, - // (which we also count using `cooling_off_period_days_remaining`) - // where they aren't eligble for rewards until they bond the new min. DHX so cooling off period starts and + // cooling down period days remaining to change so they are now going through the unbonding cool down period, + // (which we also count using `cooling_down_period_days_remaining`) + // where they aren't eligble for rewards until they bond the new min. DHX so cooling down period starts and // then they'd be eligible for rewards after waiting that period, but also note that if they don't bond the new min. // DHX and wait until the end of the cool down period then they'll be able to withdraw the amount they had bonded. // @@ -775,7 +839,7 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b // params: start of date, days remaining, bonding status // note: since they don't have the min. DHX bonded their bonding status changes to `2`, which is unbonding - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630713600000, 1, 2))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630713600000, 1))); assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, account_1_public_key.clone())), Some(0u128)); assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, account_2_public_key.clone())), Some(0u128)); @@ -791,10 +855,10 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630713600000), Some(FIVE_THOUSAND_DHX)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630713600000), Some(false)); - check_cooling_off_period_starts_again_if_sufficient_bonded_again(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); + check_cooling_down_period_starts_again_if_sufficient_bonded_again(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); } -fn check_cooling_off_period_starts_again_if_sufficient_bonded_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { +fn check_cooling_down_period_starts_again_if_sufficient_bonded_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner, referendum_index); @@ -809,7 +873,7 @@ fn check_cooling_off_period_starts_again_if_sufficient_bonded_again(amount_bonde // params: start of date, days remaining, bonding status // note: since they have the min. DHX bonded again their bonding status changes to `1`, which is bonding - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630800000000, 0, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630800000000, 0))); check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_mpower(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); } @@ -835,12 +899,12 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_m // params: start of date, days remaining, bonding status // note: since they don't have min. mPower their bonding status changes to `2`, which is unbonding - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1630972800000, 0, 2))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630972800000, 0))); - check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); + check_cooling_down_period_starts_again_if_sufficient_mpower_again(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); } -fn check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { +fn check_cooling_down_period_starts_again_if_sufficient_mpower_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); // reset mpower to what it was @@ -853,7 +917,7 @@ fn check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonde // params: start of date, days remaining, bonding status // note: they have min. mPower again so their bonding status changes to `0`, which is unbonded - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1631059200000, 0, 0))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1631059200000, 0))); // use original mpower change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1631145600000i64); @@ -865,7 +929,7 @@ fn check_cooling_off_period_starts_again_if_sufficient_mpower_again(amount_bonde // params: start of date, days remaining, bonding status // note: they have min. mPower again so their bonding status changes to `1`, which means they are bonded again - assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(account_1_public_key.clone()), Some((1631145600000, 1, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1631145600000, 1))); // params: total days, days remaining assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1631059200000, 1631145600000, 2u32, 1u32))); From eadb462142a5ad96406e38ebd26c435941a30c60 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 20 Dec 2021 17:41:00 +0100 Subject: [PATCH 36/37] wip --- pallets/mining/rewards-allowance/src/tests.rs | 77 +++++++++++-------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index a2f4c37e3..533516d6a 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -71,10 +71,12 @@ fn it_calcs_rewards_allowance_using_on_initialize_with_claim_using_extrinsic_for let r = setup_bonding(NORMAL_AMOUNT, TEN_DHX); setup_treasury_balance(); - - setup_multiplier(); - - distribute_rewards(NORMAL_AMOUNT, amount_mpower_each_miner, r); + setup_multiplier(90u32); + setup_registered_dhx_miners(vec![CHARLIE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), ALICE_PUBLIC_KEY.clone().into()]); + // TODO - don't need this unless testing unbonding period + setup_cooling_down_period_days(7_u32); + setup_rewards_allowance_dhx_daily(FIVE_THOUSAND_DHX); + claim_eligible_rewards_after_challenge_period_if_suffient_bonded(NORMAL_AMOUNT, amount_mpower_each_miner.clone()); }) } @@ -90,10 +92,12 @@ fn it_calcs_rewards_allowance_using_on_initialize_with_claim_using_extrinsic_for let r = setup_bonding(LARGE_AMOUNT_DHX, TEN_DHX); setup_treasury_balance(); - - setup_multiplier(); - - distribute_rewards(LARGE_AMOUNT_DHX, amount_mpower_each_miner, r); + setup_multiplier(90u32); + setup_registered_dhx_miners(vec![CHARLIE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), ALICE_PUBLIC_KEY.clone().into()]); + // TODO - don't need this unless testing unbonding period + setup_cooling_down_period_days(7_u32); + setup_rewards_allowance_dhx_daily(FIVE_THOUSAND_DHX); + claim_eligible_rewards_after_challenge_period_if_suffient_bonded(LARGE_AMOUNT_DHX, amount_mpower_each_miner.clone()); }) } @@ -333,25 +337,6 @@ fn it_checks_if_is_more_than_challenge_period() { } fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( - Origin::root(), - vec![CHARLIE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), ALICE_PUBLIC_KEY.clone().into()], - )); - - assert_ok!(MiningRewardsAllowanceTestModule::set_cooling_down_period_days( - Origin::root(), - 7_u32, // debug quickly for testing - )); - assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_allowance_dhx_daily( - Origin::root(), - FIVE_THOUSAND_DHX, - )); - - assert_eq!(MiningRewardsAllowanceTestModule::registered_dhx_miners(), Some(vec![ALICE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), CHARLIE_PUBLIC_KEY.clone().into()])); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days(), Some(7)); - assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_daily(), Some(FIVE_THOUSAND_DHX)); - - claim_eligible_rewards_after_challenge_period_if_suffient_bonded(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone()); // // check that rewards multiplier increases by multiplier every period days and that days total and remaining are reset // check_rewards_double_each_multiplier_period(amount_mpower_each_miner.clone()); @@ -436,7 +421,7 @@ fn setup_bonding(amount_bonded_each_miner: u128, min_bonding_dhx_daily: u128) -> return r; } -fn setup_multiplier() { +fn setup_multiplier(days: u32) { assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_operation( Origin::root(), 1u8, @@ -446,15 +431,47 @@ fn setup_multiplier() { // since we don't want to wait so long to check that it changes each cycle in the tests assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_default_period_days( Origin::root(), - 90u32, + days.clone(), )); assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_next_period_days( Origin::root(), - 90u32, + days.clone(), )); } +fn setup_registered_dhx_miners(registered_dhx_miners: Vec>) { + assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miners( + Origin::root(), + registered_dhx_miners.clone(), + )); + + assert_eq!( + MiningRewardsAllowanceTestModule::registered_dhx_miners(), + Some( + vec![ALICE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), CHARLIE_PUBLIC_KEY.clone().into()] + ), + ); +} + +fn setup_cooling_down_period_days(cooling_down_period_days: u32) { + assert_ok!(MiningRewardsAllowanceTestModule::set_cooling_down_period_days( + Origin::root(), + cooling_down_period_days.clone(), + )); + + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days(), Some(cooling_down_period_days.clone())); +} + +fn setup_rewards_allowance_dhx_daily(rewards_allowance_dhx_daily: u128) { + assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_allowance_dhx_daily( + Origin::root(), + rewards_allowance_dhx_daily.clone(), + )); + + assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_daily(), Some(rewards_allowance_dhx_daily.clone())); +} + fn setup_treasury_balance() { // set the balance of the treasury so it distributes rewards Balances::set_balance(Origin::root(), Treasury::account_id(), INIT_DAO_BALANCE_DHX, 0); From 1e9585f00777de3734b374d43e8ae82457f6d793 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 3 Jan 2022 10:06:54 +0100 Subject: [PATCH 37/37] wip --- node/src/chain_spec.rs | 4 + pallets/mining/rewards-allowance/src/lib.rs | 113 +++++-- pallets/mining/rewards-allowance/src/tests.rs | 304 ++++++++++++------ 3 files changed, 312 insertions(+), 109 deletions(-) diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index 71292c861..1af986c47 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -959,6 +959,7 @@ fn testnet_genesis( ( 0, 7u32, + 0u32, ), ), ( @@ -967,6 +968,7 @@ fn testnet_genesis( ( 0, 7u32, + 0u32, ), ), ], @@ -1104,6 +1106,7 @@ fn mainnet_genesis( ( 0, 7u32, + 0u32, ), ), ( @@ -1112,6 +1115,7 @@ fn mainnet_genesis( ( 0, 7u32, + 0u32, ), ), ], diff --git a/pallets/mining/rewards-allowance/src/lib.rs b/pallets/mining/rewards-allowance/src/lib.rs index d46be2906..a44d4ee92 100644 --- a/pallets/mining/rewards-allowance/src/lib.rs +++ b/pallets/mining/rewards-allowance/src/lib.rs @@ -443,6 +443,7 @@ pub mod pallet { // current date for a miner (i.e. only reduce the days remaining once per day per miner) Date, u32, // days remaining + u32, // 0: during cooldown period, 1: cooldown period finished (don't reset cooldown days remaining unless bond min. then unbond again) ), >; @@ -511,7 +512,7 @@ pub mod pallet { pub min_mpower_daily_default: u128, pub challenge_period_days: u64, pub cooling_down_period_days: u32, - pub cooling_down_period_days_remaining: Vec<(Vec, (Date, u32))>, + pub cooling_down_period_days_remaining: Vec<(Vec, (Date, u32, u32))>, } // The default value for the genesis config type. @@ -558,6 +559,7 @@ pub mod pallet { ( Default::default(), Default::default(), + Default::default(), ), ), ] @@ -607,8 +609,8 @@ pub mod pallet { >::put(&self.min_mpower_daily_default); >::put(&self.challenge_period_days); >::put(&self.cooling_down_period_days); - for (a, (b, c)) in &self.cooling_down_period_days_remaining { - >::insert(a, (b, c)); + for (a, (b, c, d)) in &self.cooling_down_period_days_remaining { + >::insert(a, (b, c, d)); } } } @@ -1513,6 +1515,7 @@ pub mod pallet { let mut cooling_down_period_days_remaining = ( start_of_requested_date_millis.clone(), 0u32, + 0u32, ); if let Some(_cooling_down_period_days_remaining) = >::get(miner_public_key.clone()) { // we do not change cooling_down_period_days_remaining.0 to the default value in the chain_spec.rs of 0, @@ -1521,6 +1524,7 @@ pub mod pallet { cooling_down_period_days_remaining.0 = _cooling_down_period_days_remaining.0; } cooling_down_period_days_remaining.1 = _cooling_down_period_days_remaining.1; + cooling_down_period_days_remaining.2 = _cooling_down_period_days_remaining.2; } else { log::info!("Unable to retrieve cooling down period days remaining for given miner, using default {:?}", miner_public_key.clone()); println!("Unable to retrieve cooling down period days remaining for given miner, using default {:?}", miner_public_key.clone()); @@ -1536,18 +1540,65 @@ pub mod pallet { if cooling_down_period_days_remaining.1 == 0u32 && is_bonding_min_dhx == false + { - // Write the new value to storage - >::insert( - miner_public_key.clone(), - ( - start_of_requested_date_millis.clone(), - cooling_down_period_days.clone(), - ), - ); + // case 1: just finished unbonding period + if cooling_down_period_days_remaining.2 == 1u32 { + >::insert( + miner_public_key.clone(), + ( + start_of_requested_date_millis.clone(), + 0u32, + 0u32, + ), + ); + } + + // // case 2: after finished unbonding period, and where .2 set to 2u32 already + // if cooling_down_period_days_remaining.2 == 2u32 { + // >::insert( + // miner_public_key.clone(), + // ( + // start_of_requested_date_millis.clone(), + // cooling_down_period_days_remaining.1, + // 0u32, + // ), + // ); + // } + // // case 1: just started unbonding after being + // if cooling_down_period_days_remaining.2 == 0u32 { + // >::insert( + // miner_public_key.clone(), + // ( + // start_of_requested_date_millis.clone(), + // cooling_down_period_days.clone(), + // 1u32, + // ), + // ); + // } + // // case 2: midway through unbonding + // if cooling_down_period_days_remaining.2 == 1u32 { + // >::insert( + // miner_public_key.clone(), + // ( + // start_of_requested_date_millis.clone(), + // cooling_down_period_days_remaining.1, + // 1u32, + // ), + // ); + // // case 3: just finished unbonding + // } else if cooling_down_period_days_remaining.2 == 0u32 { + // >::insert( + // miner_public_key.clone(), + // ( + // start_of_requested_date_millis.clone(), + // cooling_down_period_days_remaining.1, + // 0u32, + // ), + // ); + // } + // // case 4: finished unbonding period - log::info!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_down_period_days.clone()); - println!("Unbonding detected for miner. Starting cooling down period {:?} {:?}", miner_public_key.clone(), cooling_down_period_days.clone()); // if cooling_down_period_days_remaining.0 is not the start of the current date // (since if they just started un-bonding @@ -1558,8 +1609,9 @@ pub mod pallet { // but not yet completely unbonded so cannot claim rewards yet } else if cooling_down_period_days_remaining.0 != start_of_requested_date_millis.clone() && - cooling_down_period_days_remaining.1 > 0u32 && - is_bonding_min_dhx == false + cooling_down_period_days_remaining.1 > 0u32 + // && + // is_bonding_min_dhx == false { let old_cooling_down_period_days_remaining = cooling_down_period_days_remaining.1.clone(); @@ -1585,6 +1637,7 @@ pub mod pallet { ( start_of_requested_date_millis.clone(), new_cooling_down_period_days_remaining.clone(), + 1u32, ), ); @@ -1955,10 +2008,28 @@ pub mod pallet { let current_timestamp = >::get(); let current_timestamp_as_u64 = Self::convert_moment_to_u64_in_milliseconds(current_timestamp.clone())?; log::info!("current_timestamp_as_u64: {:?}", current_timestamp_as_u64.clone()); + println!("current_timestamp_as_u64: {:?}", current_timestamp_as_u64.clone()); // convert the current timestamp to the start of that day date/time // i.e. 21 Apr @ 1420 -> 21 Apr @ 0000 let start_of_current_date_millis = Self::convert_u64_in_milliseconds_to_start_of_date(current_timestamp_as_u64.clone())?; + // // Prevent them from claiming during their unbonding period + // let mut is_still_unbonding = false; + // if let Some(_cooling_down_period_days_remaining) = >::get(miner_public_key.clone()) { + // if _cooling_down_period_days_remaining.2 == 1 { + // is_still_unbonding = true; + // } + // } else { + // log::info!("Unable to retrieve cooling down period days remaining for given miner {:?}", miner_public_key.clone()); + // println!("Unable to retrieve cooling down period days remaining for given miner {:?}", miner_public_key.clone()); + // return Err(DispatchError::Other("Unable to retrieve cooling down period days remaining for given miner")); + // } + // if is_still_unbonding == true { + // log::info!("Unbonding still in progress for given miner {:?}", miner_public_key.clone()); + // println!("Unbonding still in progress for given miner {:?}", miner_public_key.clone()); + // return Err(DispatchError::Other("Unbonding still in progress for given miner")); + // } + // where there are 86400000 milliseconds in a day // there are 7 * 86400000 = 604800000 milliseconds in 7 days // so we want to make sure `start_of_current_date_millis` - `start_of_requested_date_millis` > 604800000 @@ -1975,7 +2046,7 @@ pub mod pallet { Ok(x) => { log::info!("Proceeding since waited at least the challenge period"); println!("Proceeding since waited at least the challenge period"); - is_more_than_challenge_period = x; + is_more_than_challenge_period = true; } } @@ -3640,7 +3711,7 @@ pub mod pallet { // // `ChallengePeriodDays` is used only to ensure you can only claim each daily rewards manually 7 days after being found eligible, // even for the first 7 days after they start bonding) - pub fn is_more_than_challenge_period(start_of_requested_date_millis: i64) -> Result { + pub fn is_more_than_challenge_period(start_of_requested_date_millis: i64) -> Result<(), DispatchError> { let current_timestamp = >::get(); let current_timestamp_as_u64 = Self::convert_moment_to_u64_in_milliseconds(current_timestamp.clone())?; log::info!("current_timestamp_as_u64: {:?}", current_timestamp_as_u64.clone()); @@ -3658,6 +3729,8 @@ pub mod pallet { let mut challenge_period_days = 0u64; if let Some(_challenge_period_days) = >::get() { challenge_period_days = _challenge_period_days; + log::info!("existing challenge_period_days: {:?}", challenge_period_days.clone()); + println!("existing challenge_period_days: {:?}", challenge_period_days.clone()); } else { log::error!("Unable to get challenge_period_days"); return Err(DispatchError::Other("Unable to get challenge_period_days"));; @@ -3684,13 +3757,15 @@ pub mod pallet { // println!("period_millis_u64: {:?}", period_millis_u64.clone()); if (period_millis_u64 >= challenge_period_millis.clone()) { is_more_than_challenge_period = true; + println!("is_more_than_challenge_period: {:?}", is_more_than_challenge_period.clone()); + return Ok(()); + } else { + return Err(DispatchError::Other("Not more than challenge period")); } } else { log::error!("Unable to subtract to determine if challenge period is satisfied"); return Err(DispatchError::Other("Unable to subtract to determine if challenge period is satisfied")); } - - return Ok(is_more_than_challenge_period.clone()); } } } diff --git a/pallets/mining/rewards-allowance/src/tests.rs b/pallets/mining/rewards-allowance/src/tests.rs index 533516d6a..b23f303e9 100644 --- a/pallets/mining/rewards-allowance/src/tests.rs +++ b/pallets/mining/rewards-allowance/src/tests.rs @@ -68,20 +68,19 @@ fn it_calcs_rewards_allowance_using_on_initialize_with_claim_using_extrinsic_for setup_min_mpower_daily(min_mpower_daily); - let r = setup_bonding(NORMAL_AMOUNT, TEN_DHX); + let referendum_index = setup_bonding(NORMAL_AMOUNT, TEN_DHX); setup_treasury_balance(); setup_multiplier(90u32); setup_registered_dhx_miners(vec![CHARLIE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), ALICE_PUBLIC_KEY.clone().into()]); // TODO - don't need this unless testing unbonding period - setup_cooling_down_period_days(7_u32); + // setup_cooling_down_period_days(7_u32); setup_rewards_allowance_dhx_daily(FIVE_THOUSAND_DHX); claim_eligible_rewards_after_challenge_period_if_suffient_bonded(NORMAL_AMOUNT, amount_mpower_each_miner.clone()); }) } #[test] -// #[ignore] fn it_calcs_rewards_allowance_using_on_initialize_with_claim_using_extrinsic_for_large_amount() { new_test_ext().execute_with(|| { let amount_mpower_each_miner = 5u128; @@ -89,18 +88,49 @@ fn it_calcs_rewards_allowance_using_on_initialize_with_claim_using_extrinsic_for setup_min_mpower_daily(min_mpower_daily); - let r = setup_bonding(LARGE_AMOUNT_DHX, TEN_DHX); + let referendum_index = setup_bonding(LARGE_AMOUNT_DHX, TEN_DHX); setup_treasury_balance(); setup_multiplier(90u32); setup_registered_dhx_miners(vec![CHARLIE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), ALICE_PUBLIC_KEY.clone().into()]); // TODO - don't need this unless testing unbonding period - setup_cooling_down_period_days(7_u32); + // setup_cooling_down_period_days(7_u32); setup_rewards_allowance_dhx_daily(FIVE_THOUSAND_DHX); claim_eligible_rewards_after_challenge_period_if_suffient_bonded(LARGE_AMOUNT_DHX, amount_mpower_each_miner.clone()); }) } +#[test] +fn it_changes_rewards_multiplier_every_period_day_and_resets_remaining_days() { + new_test_ext().execute_with(|| { + // TODO - do we need all these setup to run this test? + let amount_mpower_each_miner = 5u128; + let min_mpower_daily = 1u128; + + setup_min_mpower_daily(min_mpower_daily); + + let referendum_index = setup_bonding(LARGE_AMOUNT_DHX, TEN_DHX); + + setup_treasury_balance(); + setup_multiplier(2u32); + // TODO - this function doesn't exist, do we need this function? + // setup_multiplier_period_days_remaining(2u32); + setup_registered_dhx_miners(vec![CHARLIE_PUBLIC_KEY.clone().into(), BOB_PUBLIC_KEY.clone().into(), ALICE_PUBLIC_KEY.clone().into()]); + // TODO - this function doesn't exist, do we need this function? + // setup_cooling_down_period_days_remaining(0_u32); + setup_rewards_allowance_dhx_daily(FIVE_THOUSAND_DHX); + + // check that rewards multiplier increases by multiplier every period days and that days total and remaining are reset + check_rewards_double_each_multiplier_period(amount_mpower_each_miner.clone()); + + setup_cooling_down_period_days(2_u32); + // check that after the multiplier doubles, they are no longer eligible to receive the rewards + // if they have the same amount bonded (since they’d then need twice the amount bonded as ratio changes from 10:1 to 20:1), + // even if they have sufficient mpower + check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_bonded(LARGE_AMOUNT_DHX, amount_mpower_each_miner.clone(), referendum_index.clone()); + }) +} + #[test] fn it_sets_rewards_allowance_with_timestamp() { new_test_ext().execute_with(|| { @@ -316,37 +346,31 @@ fn it_converts_vec_u8_to_u128() { } #[test] -// note: we're using a challenge period of 7 days +// note: we're using a challenge period of 7 days in this test fn it_checks_if_is_more_than_challenge_period() { new_test_ext().execute_with(|| { // where milliseconds/day 86400000 + assert_ok!(MiningRewardsAllowanceTestModule::set_challenge_period_days( + Origin::root(), + 7u64, + )); + // 1st Dec 2021 @ 12am is 1638316800000 (start of day) let start_of_requested_date_millis: i64 = 1638316800000i64; // 7th Dec 2021 @ 12am is 1638835200000 (start of day) let current_timestamp_6_days_later = 1638835200000u64; Timestamp::set_timestamp(current_timestamp_6_days_later); - assert_eq!(MiningRewardsAllowanceTestModule::is_more_than_challenge_period(start_of_requested_date_millis), Ok(false)); + assert_eq!(MiningRewardsAllowanceTestModule::is_more_than_challenge_period(start_of_requested_date_millis), Err(DispatchError::Other("Not more than challenge period"))); - // 8th Dec 2021 @ 12am is 1638921600000 (start of day) - let current_timestamp_7_days_later = 1638921600000u64; - Timestamp::set_timestamp(current_timestamp_7_days_later); - assert_eq!(MiningRewardsAllowanceTestModule::is_more_than_challenge_period(start_of_requested_date_millis), Ok(true)); + // // 8th Dec 2021 @ 12am is 1638921600000 (start of day) + // let current_timestamp_7_days_later = 1638921600000u64; + // Timestamp::set_timestamp(current_timestamp_7_days_later); + // assert_eq!(MiningRewardsAllowanceTestModule::is_more_than_challenge_period(start_of_requested_date_millis), Ok(())); }); } -fn distribute_rewards(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { - - // // check that rewards multiplier increases by multiplier every period days and that days total and remaining are reset - // check_rewards_double_each_multiplier_period(amount_mpower_each_miner.clone()); - - // // check that after the multiplier doubles, they are no longer eligible to receive the rewards - // // if they have the same amount bonded (since they’d then need twice the amount bonded as ratio changes from 10:1 to 20:1), - // // even if they have sufficient mpower - // check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_bonded(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); -} - fn setup_min_mpower_daily(min_mpower_daily: u128) { assert_ok!(MiningRewardsAllowanceTestModule::set_min_mpower_daily( Origin::root(), @@ -534,7 +558,7 @@ fn unbond_each_miner_by_removing_their_referendum_vote(referendum_index: u32) { let account_2_account_id: u64 = Decode::decode(&mut account_2_public_key.as_slice().clone()).ok().unwrap(); let account_3_account_id: u64 = Decode::decode(&mut account_3_public_key.as_slice().clone()).ok().unwrap(); - // remove the votes and then unlock for each account + // remove the votes and then unlock for each account // note: `remove_vote` must be done before `unlock` assert_ok!(Democracy::remove_vote(Origin::signed(account_1_account_id.clone()), referendum_index)); assert_ok!(Democracy::remove_vote(Origin::signed(account_2_account_id.clone()), referendum_index)); @@ -542,8 +566,8 @@ fn unbond_each_miner_by_removing_their_referendum_vote(referendum_index: u32) { // we removed their votes assert_eq!(Democracy::referendum_status(referendum_index).unwrap().tally, Tally { ayes: 0, nays: 0, turnout: 0 }); assert_ok!(Democracy::unlock(Origin::signed(account_1_account_id.clone()), account_1_account_id.clone())); - assert_ok!(Democracy::unlock(Origin::signed(account_2_account_id.clone()), account_1_account_id.clone())); - assert_ok!(Democracy::unlock(Origin::signed(account_3_account_id.clone()), account_1_account_id.clone())); + assert_ok!(Democracy::unlock(Origin::signed(account_2_account_id.clone()), account_2_account_id.clone())); + assert_ok!(Democracy::unlock(Origin::signed(account_3_account_id.clone()), account_3_account_id.clone())); // check that all accounts are unlocked assert_eq!(Balances::locks(account_1_account_id.clone()), vec![]); @@ -680,68 +704,78 @@ fn claim_eligible_rewards_after_challenge_period_if_suffient_bonded(amount_bonde change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); + // 30th Aug 2021 @ 12am is 1630281600000 (start of day) + Timestamp::set_timestamp(1630281600000u64); + MiningRewardsAllowanceTestModule::on_initialize(5); + + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630368000000i64); + + // 31th Aug 2021 @ 12am is 1630368000000 (start of day) + Timestamp::set_timestamp(1630368000000u64); + MiningRewardsAllowanceTestModule::on_initialize(6); + // we can only claim the rewards for a date that was at least the challenge period (i.e. 7 days) prior to the current date // when a user submits a request to claim rewards that were calculated that they were eligible for on that prior date assert_ok!(MiningRewardsAllowanceTestModule::set_challenge_period_days( Origin::root(), - 7u64, + 2u64, )); - change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630713600000i64); - // 4th September 2021 @ 12am is 1630713600000 (start of day) - Timestamp::set_timestamp(1630713600000u64); - - // try to claim rewards they were NOT eligible for yet on the 29th Aug because it is less than the challenge period ago + // try to claim rewards they were NOT eligible for yet on the 31th Aug because it is less than the challenge period ago // i'll just try claiming the reward for one of the miners assert_eq!( MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( Origin::signed(account_1_account_id.clone()), account_1_public_key.clone(), - 1630713600000 + 1630368000000 ), - Err(DispatchError::Other("Unable to retrieve balance for rewards_aggregated_dhx_daily. cooling down period or challenge period may not be finished yet")) + Err(DispatchError::Other("Not more than challenge period")) ); - change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630886400000i64); - // 6th September 2021 @ 12am is 1630886400000 (start of day) - Timestamp::set_timestamp(1630886400000u64); - - // try to claim rewards they were deemed eligible for back on the 29th Aug + // try to claim rewards they were deemed eligible for back on the 29th Aug (more than challenge period prior) - // we'll get all three of the registered dhx miners to claim their rewards assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( Origin::signed(account_1_account_id.clone()), account_1_public_key.clone(), 1630195200000 )); - // // added this so logs appear so i can debug - // // assert_eq!(1, 0); + // change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630713600000i64); + // // 4th September 2021 @ 12am is 1630713600000 (start of day) + // Timestamp::set_timestamp(1630713600000u64); - assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( - Origin::signed(account_2_account_id.clone()), - account_2_public_key.clone(), - 1630195200000 - )); + // change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630886400000i64); + // // 6th September 2021 @ 12am is 1630886400000 (start of day) + // Timestamp::set_timestamp(1630886400000u64); - assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( - Origin::signed(account_3_account_id.clone()), - account_3_public_key.clone(), - 1630195200000 - )); - // after all the registered dhx miners have claimed their rewards this is the amount that should be remaining from the allocated dhx for the date - assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); - // // TODO - each registered dhx miner is claiming rewards now instead of the rewards being automatically distributed, - // // see notes in the implementation lib.rs - // // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); + // // // added this so logs appear so i can debug + // // // assert_eq!(1, 0); + + // assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + // Origin::signed(account_2_account_id.clone()), + // account_2_public_key.clone(), + // 1630195200000 + // )); + + // assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + // Origin::signed(account_3_account_id.clone()), + // account_3_public_key.clone(), + // 1630195200000 + // )); + + // // after all the registered dhx miners have claimed their rewards this is the amount that should be remaining from the allocated dhx for the date + // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630195200000), Some(TWO_DHX)); + // // // TODO - each registered dhx miner is claiming rewards now instead of the rewards being automatically distributed, + // // // see notes in the implementation lib.rs + // // // assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630195200000), Some(true)); - // TODO - test the multiplier changing works. move the below into a separate test + // TODO - move the below into a separate test - // assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0))); + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630195200000, 0, 0))); // change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630281600000i64); @@ -752,7 +786,7 @@ fn claim_eligible_rewards_after_challenge_period_if_suffient_bonded(amount_bonde // // we have finished the cooling down period and should now be distributing rewards each day unless they reduce their bonded // // amount below the min. bonded DHX daily amount - // assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0))); + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630281600000, 0, 0))); // // check that the min_bonded_dhx_daily doubled after 3 months from 10 DHX to 20 DHX // assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(TWENTY_DHX)); // // the change between each multiplier period is 10 unless a user sets it to a different value @@ -779,14 +813,26 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { let account_2_public_key: Vec = BOB_PUBLIC_KEY.clone().into(); let account_3_public_key: Vec = CHARLIE_PUBLIC_KEY.clone().into(); + // 30th August 2021 @ ~7am is 1630306800000 + // 30th August 2021 @ 12am is 1630281600000 (start of day) + Timestamp::set_timestamp(1630306800000u64); + MiningRewardsAllowanceTestModule::on_initialize(5); + + assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630281600000, 2u32, 2u32))); + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630368000000i64); // 31th August 2021 @ ~7am is 1630393200000 // 31th August 2021 @ 12am is 1630368000000 (start of day) Timestamp::set_timestamp(1630393200000u64); MiningRewardsAllowanceTestModule::on_initialize(6); - // cooling down period doesn't change again unless they unbond - assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630368000000, 0))); + // TODO - we don't need to use `cooling_down_period_days_remaining` to test the multiplier period works, + // but it should be set to the value below, so we might need an extrinsic like + // `set_cooling_down_period_days_remaining` to set it so we can test it is the + // value below + // + // // cooling down period must be 0 otherwise they are unbonding + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630368000000, 0, 0))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630368000000, 2u32, 1u32))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); @@ -796,7 +842,7 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { // 1st Sept 2021 @ 12am is 1630454400000 (start of day) Timestamp::set_timestamp(1630479600000u64); MiningRewardsAllowanceTestModule::on_initialize(7); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630454400000, 0))); + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630454400000, 0, 0))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630281600000, 1630454400000, 2u32, 0u32))); assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_change(), Some(10u32)); @@ -805,9 +851,10 @@ fn check_rewards_double_each_multiplier_period(amount_mpower_each_miner: u128) { // 2nd Sept 2021 @ ~7am is 1630566000000 // 2nd Sept 2021 @ 12am is 1630540800000 (start of day) Timestamp::set_timestamp(1630566000000u64); - MiningRewardsAllowanceTestModule::on_initialize(7); - assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630540800000, 0))); - // start of new multiplier period + MiningRewardsAllowanceTestModule::on_initialize(8); + // assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630540800000, 0, 0))); + + // check that it resets for a start of new multiplier period assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630540800000, 1630540800000, 2u32, 2u32))); // check that the min_bonded_dhx_daily doubled after 3 months (we're only doing it after 2 days in the tests though) from 20 DHX to 30 DHX assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(THIRTY_DHX)); @@ -823,7 +870,7 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b // 3rd Sept 2021 @ ~7am is 1630652400000 // 3rd Sept 2021 @ 12am is 1630627200000 (start of day) Timestamp::set_timestamp(1630652400000u64); - MiningRewardsAllowanceTestModule::on_initialize(8); + MiningRewardsAllowanceTestModule::on_initialize(9); // the below works to unbond each of the accounts @@ -838,25 +885,24 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b // 4th Sept 2021 @ ~7am is 1630738800000 // 4th Sept 2021 @ 12am is 1630713600000 (start of day) Timestamp::set_timestamp(1630738800000u64); - MiningRewardsAllowanceTestModule::on_initialize(9); + MiningRewardsAllowanceTestModule::on_initialize(10); // IMPORTANT NOTE: The min. DHX bonded has increased from 10 (10:1) to 20 (20:1) in order to be eligible // for rewards, however none of the miner's increased their bonded DHX amount proportionally to still remain // eligible for rewards, so since having insufficient bonded DHX is the same as unbonding, we expect the // cooling down period days remaining to change so they are now going through the unbonding cool down period, // (which we also count using `cooling_down_period_days_remaining`) - // where they aren't eligble for rewards until they bond the new min. DHX so cooling down period starts and - // then they'd be eligible for rewards after waiting that period, but also note that if they don't bond the new min. - // DHX and wait until the end of the cool down period then they'll be able to withdraw the amount they had bonded. + // where they aren't eligble for rewards during the unbonding whole unbonding period, + // then when they bond the new min. DHX then after the unbonding period the cooling down period starts and + // then they'd be eligible for rewards after waiting the challenge period. // // but in the tests the initial bonded amounts were much more than the min. DHX bonded, so even after it increases // from 10 (10:1) to 20 (20:1) they are still eligible for rewards. // so in the tests we've just decided to remove their vote and `unlock` their bonded DHX so they don't have a lock // and so don't satisfy the min. DHX bonded - // params: start of date, days remaining, bonding status - // note: since they don't have the min. DHX bonded their bonding status changes to `2`, which is unbonding - assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630713600000, 1))); + // params: start of date, days remaining + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630713600000, 2, 1))); assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, account_1_public_key.clone())), Some(0u128)); assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, account_2_public_key.clone())), Some(0u128)); @@ -872,13 +918,12 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_b assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630713600000), Some(FIVE_THOUSAND_DHX)); assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630713600000), Some(false)); - check_cooling_down_period_starts_again_if_sufficient_bonded_again(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); + check_cooling_down_period_resets_and_eligible_for_rewards_if_sufficient_bonded_again(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); } -fn check_cooling_down_period_starts_again_if_sufficient_bonded_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { +fn check_cooling_down_period_resets_and_eligible_for_rewards_if_sufficient_bonded_again(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { let account_1_public_key: Vec = ALICE_PUBLIC_KEY.clone().into(); - - bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner, referendum_index); + let account_1_account_id: u64 = Decode::decode(&mut account_1_public_key.as_slice().clone()).ok().unwrap(); change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630800000000i64); @@ -886,13 +931,92 @@ fn check_cooling_down_period_starts_again_if_sufficient_bonded_again(amount_bond // 5th Sept 2021 @ ~7am is 1630825200000 // 5th Sept 2021 @ 12am is 1630800000000 (start of day) Timestamp::set_timestamp(1630825200000u64); - MiningRewardsAllowanceTestModule::on_initialize(10); + MiningRewardsAllowanceTestModule::on_initialize(11); // params: start of date, days remaining, bonding status // note: since they have the min. DHX bonded again their bonding status changes to `1`, which is bonding - assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630800000000, 0))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630800000000, 1, 1))); - check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_mpower(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630886400000i64); + + // 6th Sept 2021 @ ~7am is 1630911600000 + // 6th Sept 2021 @ 12am is 1630886400000 (start of day) + Timestamp::set_timestamp(1630911600000u64); + MiningRewardsAllowanceTestModule::on_initialize(12); + + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630886400000, 0, 1))); + + // // temporarily set the challenge period really short so we can test that they weren't eligible for any rewards during the cooling down period + // assert_ok!(MiningRewardsAllowanceTestModule::set_challenge_period_days( + // Origin::root(), + // 1u64, + // )); + + // // try to claim rewards they were NOT eligible for yet on the 5th Sept since they were in the unbonding period + // assert_eq!( + // MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + // Origin::signed(account_1_account_id.clone()), + // account_1_public_key.clone(), + // 1630800000000 + // ), + // Err(DispatchError::Other("Unable to retrieve balance for rewards_aggregated_dhx_daily. cooling down period or challenge period may not be finished yet")) + // ); + + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1630972800000i64); + + // 7th Sept 2021 @ ~7am is 1630998000000 + // 7th Sept 2021 @ 12am is 1630972800000 (start of day) + Timestamp::set_timestamp(1630998000000u64); + MiningRewardsAllowanceTestModule::on_initialize(13); + + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630972800000, 0, 0))); + + change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1631059200000i64); + + // 8th Sept 2021 @ ~7am is 1631084400000 + // 8th Sept 2021 @ 12am is 1631059200000 (start of day) + Timestamp::set_timestamp(1631084400000u64); + MiningRewardsAllowanceTestModule::on_initialize(14); + + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630972800000, 0, 0))); + + // try to claim rewards they were NOT eligible for yet on the 7th Sept since they were in the unbonding period + assert_eq!( + MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + Origin::signed(account_1_account_id.clone()), + account_1_public_key.clone(), + 1630972800000 + ), + Err(DispatchError::Other("Unable to retrieve balance for rewards_aggregated_dhx_daily. cooling down period or challenge period may not be finished yet")) + ); + + + + + // restore again + assert_ok!(MiningRewardsAllowanceTestModule::set_challenge_period_days( + Origin::root(), + 1u64, + )); + + + + + // // try to claim rewards they were deemed eligible for back on the 29th Aug + + // // we'll get all three of the registered dhx miners to claim their rewards + // assert_ok!(MiningRewardsAllowanceTestModule::claim_rewards_of_account_for_date( + // Origin::signed(account_1_account_id.clone()), + // account_1_public_key.clone(), + // 1630195200000 + // )); + + + + + // bond_each_miner_by_voting_for_referendum(amount_bonded_each_miner, referendum_index); + + // check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_mpower(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); } fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_mpower(amount_bonded_each_miner: u128, amount_mpower_each_miner: u128, referendum_index: u32) { @@ -904,7 +1028,7 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_m // 6th Sept 2021 @ ~7am is 1630911600000 // 6th Sept 2021 @ 12am is 1630886400000 (start of day) Timestamp::set_timestamp(1630911600000u64); - MiningRewardsAllowanceTestModule::on_initialize(11); + MiningRewardsAllowanceTestModule::on_initialize(12); // no mpower to check they'll be ineligible for rewards change_mpower_for_each_miner(0u128, 1630972800000i64); @@ -912,11 +1036,11 @@ fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_m // 7th Sept 2021 @ ~7am is 1630998000000 // 7th Sept 2021 @ 12am is 1630972800000 (start of day) Timestamp::set_timestamp(1630998000000u64); - MiningRewardsAllowanceTestModule::on_initialize(12); + MiningRewardsAllowanceTestModule::on_initialize(13); // params: start of date, days remaining, bonding status // note: since they don't have min. mPower their bonding status changes to `2`, which is unbonding - assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630972800000, 0))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1630972800000, 0, 0))); check_cooling_down_period_starts_again_if_sufficient_mpower_again(amount_bonded_each_miner.clone(), amount_mpower_each_miner.clone(), referendum_index.clone()); } @@ -930,11 +1054,11 @@ fn check_cooling_down_period_starts_again_if_sufficient_mpower_again(amount_bond // 8th Sept 2021 @ ~7am is 1631084400000 // 8th Sept 2021 @ 12am is 1631059200000 (start of day) Timestamp::set_timestamp(1631084400000u64); - MiningRewardsAllowanceTestModule::on_initialize(13); + MiningRewardsAllowanceTestModule::on_initialize(14); // params: start of date, days remaining, bonding status // note: they have min. mPower again so their bonding status changes to `0`, which is unbonded - assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1631059200000, 0))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1631059200000, 0, 0))); // use original mpower change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1631145600000i64); @@ -942,11 +1066,11 @@ fn check_cooling_down_period_starts_again_if_sufficient_mpower_again(amount_bond // 9th Sept 2021 @ ~7am is 1631170800000 // 9th Sept 2021 @ 12am is 1631145600000 (start of day) Timestamp::set_timestamp(1631170800000u64); - MiningRewardsAllowanceTestModule::on_initialize(14); + MiningRewardsAllowanceTestModule::on_initialize(15); // params: start of date, days remaining, bonding status // note: they have min. mPower again so their bonding status changes to `1`, which means they are bonded again - assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1631145600000, 1))); + assert_eq!(MiningRewardsAllowanceTestModule::cooling_down_period_days_remaining(account_1_public_key.clone()), Some((1631145600000, 1, 0))); // params: total days, days remaining assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1631059200000, 1631145600000, 2u32, 1u32))); @@ -968,7 +1092,7 @@ fn check_pause_and_reset_rewards_multiplier_works(amount_bonded_each_miner: u128 // 10th Sept 2021 @ ~7am is 1631257200000 // 10th Sept 2021 @ 12am is 1631232000000 (start of day) Timestamp::set_timestamp(1631257200000u64); - MiningRewardsAllowanceTestModule::on_initialize(15); + MiningRewardsAllowanceTestModule::on_initialize(16); // use original mpower change_mpower_for_each_miner(amount_mpower_each_miner.clone(), 1631318400000i64); @@ -976,7 +1100,7 @@ fn check_pause_and_reset_rewards_multiplier_works(amount_bonded_each_miner: u128 // 11th Sept 2021 @ ~7am is 1631343600000 // 11th Sept 2021 @ 12am is 1631318400000 (start of day) Timestamp::set_timestamp(1631343600000u64); - MiningRewardsAllowanceTestModule::on_initialize(16); + MiningRewardsAllowanceTestModule::on_initialize(17); // params: total days, days remaining // assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1631318400000, 1631318400000, 2u32, 2u32))); @@ -997,7 +1121,7 @@ fn check_pause_and_reset_rewards_multiplier_works(amount_bonded_each_miner: u128 // 12th Sept 2021 @ ~7am is 1631430000000 // 12th Sept 2021 @ 12am is 1631404800000 (start of day) Timestamp::set_timestamp(1631430000000u64); - MiningRewardsAllowanceTestModule::on_initialize(17); + MiningRewardsAllowanceTestModule::on_initialize(18); // this starts reducing again since we unpaused it assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1631059200000, 1631404800000, 2u32, 0u32)));