Skip to content

Commit

Permalink
crv3 implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
orriin committed Nov 18, 2024
1 parent 4ee5e06 commit 41cfff9
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 65 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion pallets/subtensor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ pallet-drand = { path = "../drand", default-features = false }
pallet-membership = { workspace = true }
hex-literal = { workspace = true }
num-traits = { version = "0.2.19", default-features = false, features = ["libm"] }

tle = { workspace = true, default-features = false }
ark-bls12-381 = { workspace = true, default-features = false }
ark-serialize = { workspace = true, default-features = false }
w3f-bls = { workspace = true, default-features = false }

[dev-dependencies]
pallet-balances = { workspace = true, features = ["std"] }
Expand Down
2 changes: 0 additions & 2 deletions pallets/subtensor/src/coinbase/block_step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
Self::adjust_registration_terms_for_networks();
// --- 2. Run emission through network.
Self::run_coinbase();
// --- 3. Reveal commits
Self::reveal_commits();
// Return ok.
Ok(())
}
Expand Down
160 changes: 138 additions & 22 deletions pallets/subtensor/src/coinbase/run_coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ use super::*;
use substrate_fixed::types::I64F64;
use substrate_fixed::types::I96F32;

impl<T: Config + pallet_drand::Config> Pallet<T> {
/// The `reveal_crv3_commits` function is used for revealing commitments whos drand round has
/// passed.
pub fn reveal_commits() {
// TODO: Get drand pallet round number

// TODO: Get encrypted commits

// TODO: Get oldest commit round

// TODO: While oldest commit round < drand round, decrypt and store results in Weights
}
/// Contains all necesarry information to set weights.
///
/// In the context of commit-reveal v3, this is the payload which should be
/// encrypted, compressed, serialized, and submitted to the `commit_crv3_weights`
/// extrinsic.
#[derive(Encode, Decode)]
pub struct WeightsPayload {
pub uids: Vec<u16>,
pub values: Vec<u16>,
pub version_key: u64,
}

impl<T: Config> Pallet<T> {
/// The `coinbase` function performs a four-part emission distribution process involving
/// subnets, epochs, hotkeys, and nominators.
// It is divided into several steps, each handling a specific part of the distribution:
Expand Down Expand Up @@ -89,7 +89,16 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
for netuid in subnets.clone().iter() {
// --- 4.1 Check to see if the subnet should run its epoch.
if Self::should_run_epoch(*netuid, current_block) {
// --- 4.2 Drain the subnet emission.
// --- 4.2 Reveal weights from the n-2nd epoch.
if let Err(e) = Self::reveal_crv3_commits(*netuid) {
log::warn!(
"Failed to reveal commits for subnet {} due to error: {:?}",
*netuid,
e
);
};

// --- 4.3 Drain the subnet emission.
let mut subnet_emission: u64 = PendingEmission::<T>::get(*netuid);
PendingEmission::<T>::insert(*netuid, 0);
log::debug!(
Expand All @@ -98,7 +107,7 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
subnet_emission
);

// --- 4.3 Set last step counter.
// --- 4.4 Set last step counter.
Self::set_blocks_since_last_step(*netuid, 0);
Self::set_last_mechanism_step_block(*netuid, current_block);

Expand All @@ -107,30 +116,30 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
continue;
}

// --- 4.4 Distribute owner take.
// --- 4.5 Distribute owner take.
if SubnetOwner::<T>::contains_key(netuid) {
// Does the subnet have an owner?

// --- 4.4.1 Compute the subnet owner cut.
// --- 4.5.1 Compute the subnet owner cut.
let owner_cut: I96F32 = I96F32::from_num(subnet_emission).saturating_mul(
I96F32::from_num(Self::get_subnet_owner_cut())
.saturating_div(I96F32::from_num(u16::MAX)),
);

// --- 4.4.2 Remove the cut from the subnet emission
// --- 4.5.2 Remove the cut from the subnet emission
subnet_emission = subnet_emission.saturating_sub(owner_cut.to_num::<u64>());

// --- 4.4.3 Add the cut to the balance of the owner
// --- 4.5.3 Add the cut to the balance of the owner
Self::add_balance_to_coldkey_account(
&Self::get_subnet_owner(*netuid),
owner_cut.to_num::<u64>(),
);

// --- 4.4.4 Increase total issuance on the chain.
// --- 4.5.4 Increase total issuance on the chain.
Self::coinbase(owner_cut.to_num::<u64>());
}

// 4.3 Pass emission through epoch() --> hotkey emission.
// 4.6 Pass emission through epoch() --> hotkey emission.
let hotkey_emission: Vec<(T::AccountId, u64, u64)> =
Self::epoch(*netuid, subnet_emission);
log::debug!(
Expand All @@ -139,9 +148,9 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
hotkey_emission
);

// 4.4 Accumulate the tuples on hotkeys:
// 4.7 Accumulate the tuples on hotkeys:
for (hotkey, mining_emission, validator_emission) in hotkey_emission {
// 4.5 Accumulate the emission on the hotkey and parent hotkeys.
// 4.8 Accumulate the emission on the hotkey and parent hotkeys.
Self::accumulate_hotkey_emission(
&hotkey,
*netuid,
Expand Down Expand Up @@ -191,6 +200,113 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
}
}

/// The `reveal_crv3_commits` function is run at the very beginning of epoch `n`,
/// revealing commitments from epoch `n - 2`.
/// n - 2.
pub fn reveal_crv3_commits(netuid: u16) -> dispatch::DispatchResult {
use ark_serialize::CanonicalDeserialize;
use frame_support::traits::OriginTrait;
use tle::curves::drand::TinyBLS381;
use tle::tlock::TLECiphertext;
use w3f_bls::EngineBLS;

let cur_block = Self::get_current_block_as_u64();
let cur_epoch = Self::get_epoch_index(netuid, cur_block);

// No commits to reveal until at least epoch 2.
if cur_epoch < 2 {
return Ok(());
}

// This fn is run at the VERY BEGINNING of epoch `n`, therefore the weights revealed
// must have been committed during epoch `n-2`.
let reveal_epoch = cur_epoch.saturating_sub(2);

let mut entries = CRV3WeightCommits::<T>::take(netuid, reveal_epoch);

// Keep popping item off the end of the queue until we sucessfully reveal a commit.
while let Some((who, serialized_compresssed_commit, round_number)) = entries.pop_front() {
let reader = &mut &serialized_compresssed_commit[..];
let commit = match TLECiphertext::<TinyBLS381>::deserialize_compressed(reader) {
Ok(c) => c,
Err(e) => {
log::warn!(
"Failed to reveal commit for subnet {} submitted by {:?} due to deserialization error: {:?}",
netuid,
who,
e
);
continue;
}
};

// Try to get the round number from pallet_drand.
let pulse = match pallet_drand::Pulses::<T>::get(round_number) {
Some(p) => p,
None => {
// Round number used was not found on the chain. Skip this commit.
log::warn!(
"Failed to reveal commit for subnet {} submitted by {:?} due to missing round number {} at time of reveal.",
netuid,
who,
round_number
);
continue;
}
};
let sig_reader = &mut &pulse.signature[..];
let sig =
match <TinyBLS381 as EngineBLS>::SignatureGroup::deserialize_compressed(sig_reader)
{
Ok(s) => s,
Err(e) => {
log::error!(
"Failed to reveal commit for subnet {} submitted by {:?} due to deserialization error: {:?}",
netuid,
who,
e
);
continue;
}
};

let decrypted_bytes: Vec<u8> = match commit.tld(sig) {
Ok(d) => d.message,
Err(e) => {
log::warn!(
"Failed to reveal commit for subnet {} submitted by {:?} due to decryption error: {:?}",
netuid,
who,
e
);
continue;
}
};

// Decrypt the bytes into Vec<(u64, u64)>
let mut reader = &decrypted_bytes[..];
let payload: WeightsPayload = match Decode::decode(&mut reader) {
Ok(w) => w,
Err(e) => {
log::warn!("Failed to reveal commit for subnet {} submitted by {:?} due to deserialization error: {:?}", netuid, who, e);
continue;
}
};

// TODO: Set Weights
Self::do_set_weights(
T::RuntimeOrigin::signed(who),
netuid,
payload.values,
payload.uids,
payload.version_key,
)?;
return Ok(());
}

return Ok(());
}

/// Accumulates the mining and validator emissions on a hotkey and distributes the validator emission among its parents.
///
/// This function is responsible for accumulating the mining and validator emissions associated with a hotkey onto a hotkey.
Expand Down
11 changes: 6 additions & 5 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub mod pallet {
BoundedVec,
};
use frame_system::pallet_prelude::*;
use pallet_drand::types::RoundNumber;
use sp_core::{ConstU32, H256};
use sp_runtime::traits::{Dispatchable, TrailingZeroInput};
use sp_std::collections::vec_deque::VecDeque;
Expand Down Expand Up @@ -1292,19 +1293,19 @@ pub mod pallet {
OptionQuery,
>;
#[pallet::storage]
/// --- MAP (netuid, who) --> VecDeque<(commit, commit_block, reveal_round)> | Stores a queue of v3 commits for an account on a given netuid.
/// --- MAP (netuid, commit_epoch) --> VecDeque<(who, serialized_compressed_commit, reveal_round)> | Stores a queue of v3 commits for an account on a given netuid.
pub type CRV3WeightCommits<T: Config> = StorageDoubleMap<
_,
Twox64Concat,
u16,
Twox64Concat,
T::AccountId,
u64,
VecDeque<(
T::AccountId,
BoundedVec<u8, ConstU32<MAX_CRV3_COMMIT_SIZE_BYTES>>,
u64,
u64,
RoundNumber,
)>,
OptionQuery,
ValueQuery,
>;
#[pallet::storage]
/// --- Map (netuid) --> Number of epochs allowed for commit reveal periods
Expand Down
54 changes: 21 additions & 33 deletions pallets/subtensor/src/subnets/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,17 @@ impl<T: Config> Pallet<T> {
/// - The u16 network identifier.
///
/// * `commit` (`Vec<u8>`):
/// - The encrypted commit
/// - The encrypted compressed commit.
/// The steps for this are:
/// 1. Instantiate [`WeightsPayload`]
/// 2. Serialize it using the `parity_scale_codec::Encode` trait
/// 3. Encrypt it following the steps (here)[https://github.com/ideal-lab5/tle/blob/f8e6019f0fb02c380ebfa6b30efb61786dede07b/timelock/src/tlock.rs#L283-L336]
/// to produce a [`TLECiphertext<TinyBLS381>`] type.
/// 4. Serialize and compress using the `ark-serialize` `CanonicalSerialize` trait.
///
/// * reveal_round (`u64`):
/// - The drand reveal round which will be avaliable during epoch `n+1` from the current
/// epoch.
///
/// # Raises:
/// * `CommitRevealDisabled`:
Expand Down Expand Up @@ -171,51 +181,29 @@ impl<T: Config> Pallet<T> {
Error::<T>::CommittingWeightsTooFast
);

// 5. Calculate the reveal blocks based on network tempo and reveal period.
// TODO: Double check this is not done on-chain for CRV3
// let (first_reveal_block, last_reveal_block) = Self::get_reveal_blocks(netuid, commit_block);

// 6. Retrieve or initialize the VecDeque of commits for the hotkey.
CRV3WeightCommits::<T>::try_mutate(netuid, &who, |maybe_commits| -> DispatchResult {
let mut commits: VecDeque<(
BoundedVec<u8, ConstU32<MAX_CRV3_COMMIT_SIZE_BYTES>>,
u64,
u64,
)> = maybe_commits.take().unwrap_or_default();

// TODO: Check it is OK to remove this code block, and do the "expiring"/"reveal" step
// entirely in block_step
// 7. Remove any expired commits from the front of the queue.
// while let Some((_, commit_block_existing, _, _)) = commits.front() {
// if Self::is_commit_expired(netuid, *commit_block_existing) {
// commits.pop_front();
// } else {
// break;
// }
// }

// 8. Verify that the number of unrevealed commits is within the allowed limit.
// 5. Retrieve or initialize the VecDeque of commits for the hotkey.
let cur_block = Self::get_current_block_as_u64();
let cur_epoch = Self::get_epoch_index(netuid, cur_block);
CRV3WeightCommits::<T>::try_mutate(netuid, &cur_epoch, |commits| -> DispatchResult {
// 6. Verify that the number of unrevealed commits is within the allowed limit.
ensure!(commits.len() < 10, Error::<T>::TooManyUnrevealedCommits);

// 9. Append the new commit with calculated reveal blocks.
// 7. Append the new commit with calculated reveal blocks.
// Hash the commit before it is moved, for the event
let commit_hash = BlakeTwo256::hash(&commit);
commits.push_back((commit, commit_block, reveal_round));
commits.push_back((who.clone(), commit, reveal_round));

// 10. Store the updated commits queue back to storage.
*maybe_commits = Some(commits);

// 11. Emit the WeightsCommitted event
// 8. Emit the WeightsCommitted event
Self::deposit_event(Event::CRV3WeightsCommitted(
who.clone(),
netuid,
commit_hash,
));

// 12. Update the last commit block for the hotkey's UID.
// 9. Update the last commit block for the hotkey's UID.
Self::set_last_crv3_update_for_uid(netuid, neuron_uid, commit_block);

// 13. Return success.
// 10. Return success.
Ok(())
})
}
Expand Down
5 changes: 3 additions & 2 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2067,13 +2067,14 @@ impl_runtime_apis! {

#[cfg(test)]
mod tests {
use ark_serialize::CanonicalDeserialize;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use rand_chacha::rand_core::SeedableRng;
use rand_chacha::ChaCha20Rng;
use sha2::Digest;
use tle::curves::drand::TinyBLS381;
use tle::ibe::fullident::Identity;
use tle::tlock::tle;
use w3f_bls::{EngineBLS, Message, TinyBLS381};
use w3f_bls::{EngineBLS, Message};

#[test]
pub fn tlock_encrypt_decrypt_drand_quicknet_works() {
Expand Down

0 comments on commit 41cfff9

Please sign in to comment.