Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions common/src/transaction_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub enum CustomTransactionError {
InvalidRealAccount,
FailedShieldedTxParsing,
InvalidShieldedTxPubKeyHash,
NonAssociatedColdKey,
}

impl From<CustomTransactionError> for u8 {
Expand Down Expand Up @@ -62,6 +63,7 @@ impl From<CustomTransactionError> for u8 {
CustomTransactionError::InvalidRealAccount => 22,
CustomTransactionError::FailedShieldedTxParsing => 23,
CustomTransactionError::InvalidShieldedTxPubKeyHash => 24,
CustomTransactionError::NonAssociatedColdKey => 25,
}
}
}
Expand Down
231 changes: 189 additions & 42 deletions pallets/subtensor/src/extensions/subtensor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ where
}

pub fn result_to_validity(result: Result<(), Error<T>>, priority: u64) -> TransactionValidity {
if let Err(err) = result {
Err(match err {
match result {
Ok(()) => Ok(ValidTransaction {
priority,
..Default::default()
}),
Err(err) => Err(match err {
Error::<T>::AmountTooLow => CustomTransactionError::StakeAmountTooLow,
Error::<T>::SubnetNotExists => CustomTransactionError::SubnetNotExists,
Error::<T>::NotEnoughBalanceToStake => CustomTransactionError::BalanceTooLow,
Expand All @@ -73,14 +77,10 @@ where
CustomTransactionError::ServingRateLimitExceeded
}
Error::<T>::InvalidPort => CustomTransactionError::InvalidPort,
Error::<T>::NonAssociatedColdKey => CustomTransactionError::NonAssociatedColdKey,
_ => CustomTransactionError::BadRequest,
}
.into())
} else {
Ok(ValidTransaction {
priority,
..Default::default()
})
.into()),
}
}
}
Expand Down Expand Up @@ -115,13 +115,29 @@ where
};

match call.is_sub_type() {
Some(Call::commit_weights { netuid, .. }) => {
Some(Call::commit_weights { netuid, .. })
| Some(Call::commit_mechanism_weights { netuid, .. }) => {
if Self::check_weights_min_stake(who, *netuid) {
Ok((Default::default(), (), origin))
} else {
Err(CustomTransactionError::StakeAmountTooLow.into())
}
}
Some(Call::batch_commit_weights {
netuids,
commit_hashes,
}) => {
if netuids.len() != commit_hashes.len() {
return Err(CustomTransactionError::InputLengthsUnequal.into());
}
for netuid in netuids.iter() {
let netuid: NetUid = (*netuid).into();
if !Self::check_weights_min_stake(who, netuid) {
return Err(CustomTransactionError::StakeAmountTooLow.into());
}
}
Ok((Default::default(), (), origin))
}
Some(Call::reveal_weights {
netuid,
uids,
Expand Down Expand Up @@ -152,61 +168,108 @@ where
Err(CustomTransactionError::StakeAmountTooLow.into())
}
}
Some(Call::reveal_mechanism_weights {
netuid,
mecid: _,
uids,
values,
salt,
version_key,
}) => {
if Self::check_weights_min_stake(who, *netuid) {
let provided_hash = Pallet::<T>::get_commit_hash(
who,
NetUidStorageIndex::from(*netuid),
uids,
values,
salt,
*version_key,
);
match Pallet::<T>::find_commit_block_via_hash(provided_hash) {
Some(commit_block) => {
if Pallet::<T>::is_reveal_block_range(*netuid, commit_block) {
Ok((Default::default(), (), origin))
} else {
Err(CustomTransactionError::CommitBlockNotInRevealRange.into())
}
}
None => Err(CustomTransactionError::CommitNotFound.into()),
}
} else {
Err(CustomTransactionError::StakeAmountTooLow.into())
}
}
Some(Call::batch_reveal_weights {
netuid,
uids_list,
values_list,
salts_list,
version_keys,
}) => {
if Self::check_weights_min_stake(who, *netuid) {
let num_reveals = uids_list.len();
if num_reveals == values_list.len()
&& num_reveals == salts_list.len()
&& num_reveals == version_keys.len()
{
let provided_hashes = (0..num_reveals)
.map(|i| {
Pallet::<T>::get_commit_hash(
who,
NetUidStorageIndex::from(*netuid),
uids_list.get(i).unwrap_or(&Vec::new()),
values_list.get(i).unwrap_or(&Vec::new()),
salts_list.get(i).unwrap_or(&Vec::new()),
*version_keys.get(i).unwrap_or(&0_u64),
)
})
.collect::<Vec<_>>();
if !Self::check_weights_min_stake(who, *netuid) {
return Err(CustomTransactionError::StakeAmountTooLow.into());
}

let batch_reveal_block = provided_hashes
.iter()
.filter_map(|hash| Pallet::<T>::find_commit_block_via_hash(*hash))
.collect::<Vec<_>>();
let num_reveals = uids_list.len();
if num_reveals == values_list.len()
&& num_reveals == salts_list.len()
&& num_reveals == version_keys.len()
{
let provided_hashes = (0..num_reveals)
.map(|i| {
Pallet::<T>::get_commit_hash(
who,
NetUidStorageIndex::from(*netuid),
uids_list.get(i).unwrap_or(&Vec::new()),
values_list.get(i).unwrap_or(&Vec::new()),
salts_list.get(i).unwrap_or(&Vec::new()),
*version_keys.get(i).unwrap_or(&0_u64),
)
})
.collect::<Vec<_>>();

if provided_hashes.len() == batch_reveal_block.len() {
if Pallet::<T>::is_batch_reveal_block_range(*netuid, batch_reveal_block)
{
Ok((Default::default(), (), origin))
} else {
Err(CustomTransactionError::CommitBlockNotInRevealRange.into())
}
let batch_reveal_block = provided_hashes
.iter()
.filter_map(|hash| Pallet::<T>::find_commit_block_via_hash(*hash))
.collect::<Vec<_>>();

if provided_hashes.len() == batch_reveal_block.len() {
if Pallet::<T>::is_batch_reveal_block_range(*netuid, batch_reveal_block) {
Ok((Default::default(), (), origin))
} else {
Err(CustomTransactionError::CommitNotFound.into())
Err(CustomTransactionError::CommitBlockNotInRevealRange.into())
}
} else {
Err(CustomTransactionError::InputLengthsUnequal.into())
Err(CustomTransactionError::CommitNotFound.into())
}
} else {
Err(CustomTransactionError::StakeAmountTooLow.into())
Err(CustomTransactionError::InputLengthsUnequal.into())
}
}
Some(Call::set_weights { netuid, .. }) => {
Some(Call::set_weights { netuid, .. })
| Some(Call::set_mechanism_weights { netuid, .. }) => {
if Self::check_weights_min_stake(who, *netuid) {
Ok((Default::default(), (), origin))
} else {
Err(CustomTransactionError::StakeAmountTooLow.into())
}
}
Some(Call::batch_set_weights {
netuids,
weights,
version_keys,
}) => {
if netuids.len() != weights.len() || netuids.len() != version_keys.len() {
return Err(CustomTransactionError::InputLengthsUnequal.into());
}
for netuid in netuids.iter() {
let netuid: NetUid = (*netuid).into();
if !Self::check_weights_min_stake(who, netuid) {
return Err(CustomTransactionError::StakeAmountTooLow.into());
}
}
Ok((Default::default(), (), origin))
}
Some(Call::commit_timelocked_weights {
netuid,
reveal_round,
Expand All @@ -221,6 +284,52 @@ where
Err(CustomTransactionError::StakeAmountTooLow.into())
}
}
Some(Call::commit_timelocked_mechanism_weights {
netuid,
mecid: _,
reveal_round,
..
})
| Some(Call::commit_crv3_mechanism_weights {
netuid,
mecid: _,
reveal_round,
..
}) => {
if Self::check_weights_min_stake(who, *netuid) {
if *reveal_round < pallet_drand::LastStoredRound::<T>::get() {
return Err(CustomTransactionError::InvalidRevealRound.into());
}
Ok((Default::default(), (), origin))
} else {
Err(CustomTransactionError::StakeAmountTooLow.into())
}
}
Some(Call::increase_take { hotkey, take: _ })
| Some(Call::decrease_take { hotkey, take: _ }) => {
Self::result_to_validity(Pallet::<T>::do_take_checks(who, hotkey), 0u64)
.map(|validity| (validity, (), origin.clone()))
}

Some(Call::swap_hotkey_v2 {
hotkey,
new_hotkey: _,
netuid: _,
keep_stake: _,
}) => {
if !Pallet::<T>::coldkey_owns_hotkey(who, hotkey) {
return Err(CustomTransactionError::NonAssociatedColdKey.into());
}

let block: u64 = Pallet::<T>::get_current_block_as_u64();

if Pallet::<T>::exceeds_tx_rate_limit(Pallet::<T>::get_last_tx_block(who), block) {
return Err(CustomTransactionError::RateLimitExceeded.into());
}

Ok((Default::default(), (), origin))
}

Some(Call::serve_axon {
netuid,
version,
Expand Down Expand Up @@ -248,6 +357,44 @@ where
)
.map(|validity| (validity, (), origin.clone()))
}
Some(Call::serve_axon_tls {
netuid,
version,
ip,
port,
ip_type,
protocol,
placeholder1,
placeholder2,
certificate: _,
}) => Self::result_to_validity(
Pallet::<T>::validate_serve_axon(
who,
*netuid,
*version,
*ip,
*port,
*ip_type,
*protocol,
*placeholder1,
*placeholder2,
),
0u64,
)
.map(|validity| (validity, (), origin.clone())),
Some(Call::serve_prometheus {
netuid,
version,
ip,
port,
ip_type,
}) => Self::result_to_validity(
Pallet::<T>::validate_serve_prometheus(
who, *netuid, *version, *ip, *port, *ip_type,
),
0u64,
)
.map(|validity| (validity, (), origin.clone())),
Some(Call::register_network { .. }) => {
if !TransactionType::RegisterNetwork.passes_rate_limit::<T>(who) {
return Err(CustomTransactionError::RateLimitExceeded.into());
Expand Down
42 changes: 42 additions & 0 deletions pallets/subtensor/src/subnets/serving.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,4 +369,46 @@ impl<T: Config> Pallet<T> {

Ok(())
}

/// Same checks as [`Self::do_serve_prometheus`] before storage writes (for transaction extension).
pub fn validate_serve_prometheus(
hotkey_id: &T::AccountId,
netuid: NetUid,
version: u32,
ip: u128,
port: u16,
ip_type: u8,
) -> Result<(), Error<T>> {
ensure!(Self::is_valid_ip_type(ip_type), Error::<T>::InvalidIpType);
ensure!(
Self::is_valid_ip_address(ip_type, ip, false),
Error::<T>::InvalidIpAddress
);

ensure!(
Self::is_hotkey_registered_on_any_network(hotkey_id),
Error::<T>::HotKeyNotRegisteredInNetwork
);

let mut prev_prometheus = Self::get_prometheus_info(netuid, hotkey_id);
let current_block: u64 = Self::get_current_block_as_u64();
ensure!(
Self::prometheus_passes_rate_limit(netuid, &prev_prometheus, current_block),
Error::<T>::ServingRateLimitExceeded
);

prev_prometheus.block = Self::get_current_block_as_u64();
prev_prometheus.version = version;
prev_prometheus.ip = ip;
prev_prometheus.port = port;
prev_prometheus.ip_type = ip_type;

let prom_validated = Self::validate_prometheus_data(&prev_prometheus);
ensure!(
prom_validated.is_ok(),
prom_validated.err().unwrap_or(Error::<T>::InvalidPort)
);

Ok(())
}
}
1 change: 1 addition & 0 deletions pallets/subtensor/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod subnet_emissions;
mod swap_coldkey;
mod swap_hotkey;
mod swap_hotkey_with_subnet;
mod transaction_extension_pays_no;
mod uids;
mod voting_power;
mod weights;
Loading
Loading