Skip to content

Commit fc7eeff

Browse files
committed
Merge remote-tracking branch 'upstream/devnet-ready' into feature/add-pallet-contracts
2 parents 05550de + 4a01966 commit fc7eeff

File tree

37 files changed

+263
-389
lines changed

37 files changed

+263
-389
lines changed

.github/copilot-instructions.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Bittensor PR Review Guidelines
2+
3+
You are reviewing code for a Substrate-based blockchain with a $4B market cap. Lives and livelihoods depend on the security and correctness of this code. Be thorough, precise, and uncompromising on safety.
4+
5+
## Branch Strategy
6+
* Unless this is a hotfix or deployment PR (`devnet-ready` => `devnet`, `devnet` => `testnet`, or `testnet` => `main`), all PRs must target `devnet-ready`
7+
* Flag PRs targeting `main` directly unless they are hotfixes
8+
* `devnet` and `testnet` branches must only receive merges from their respective `-ready` branches
9+
10+
## CRITICAL: Runtime Safety (Chain-Bricking Prevention)
11+
The runtime CANNOT panic under any circumstances. A single panic can brick the entire chain.
12+
13+
**Panic Sources to Flag:**
14+
* Direct indexing: `vec[i]`, `arr[3]` → Must use `.get()` returning `Option`
15+
* `.unwrap()`, `.expect()` → Must handle `Result`/`Option` properly
16+
* `.unwrap_or()` is acceptable only with safe defaults
17+
* Unchecked arithmetic: `a + b`, `a - b`, `a * b`, `a / b` → Must use `checked_*` or `saturating_*`
18+
* Division without zero checks
19+
* Type conversions: `.try_into()` without handling, casting that could truncate
20+
* Iterator operations that assume non-empty collections: `.first().unwrap()`, `.last().unwrap()`
21+
* String operations: slicing without bounds checking
22+
* `unsafe` blocks (absolutely prohibited in runtime)
23+
24+
## Substrate-Specific Vulnerabilities
25+
26+
### Storage Safety
27+
* Unbounded storage iterations (DoS vector) - check for loops over storage maps without limits
28+
* Missing storage deposits/bonds for user-created entries (state bloat attack)
29+
* Storage migrations without proper version checks or error handling
30+
* Direct storage manipulation without proper weight accounting
31+
* `kill_storage()` or storage removals without cleanup of dependent data
32+
33+
### Weight & Resource Exhaustion
34+
* Missing or incorrect `#[pallet::weight]` annotations
35+
* Computational complexity not reflected in weight calculations
36+
* Database reads/writes not accounted for in weights
37+
* Potential for weight exhaustion attacks through parameter manipulation
38+
* Loops with user-controlled bounds in extrinsics
39+
40+
### Origin & Permission Checks
41+
* Missing `ensure_signed`, `ensure_root`, or `ensure_none` checks
42+
* Origin checks that can be bypassed
43+
* Privilege escalation paths
44+
* Missing checks before state-modifying operations
45+
* Incorrect origin forwarding in cross-pallet calls
46+
47+
### Economic & Cryptoeconomic Exploits
48+
* Integer overflow/underflow in token/balance calculations
49+
* Rounding errors that can be exploited (especially in repeated operations)
50+
* MEV/front-running vulnerabilities in auction/pricing mechanisms
51+
* Flash loan-style attacks or single-block exploits
52+
* Reward calculation errors or manipulation vectors
53+
* Slashing logic vulnerabilities
54+
* Economic denial of service (forcing expensive operations on others)
55+
56+
### Migration Safety
57+
* Migrations without try-state checks or validation
58+
* Missing version guards (checking current vs new version)
59+
* Unbounded migrations that could time out
60+
* Data loss risks during migration
61+
* Missing rollback handling for failed migrations
62+
63+
### Consensus & Chain State
64+
* Anything that could cause non-deterministic behavior (randomness sources, timestamps without validation)
65+
* Fork-causing conditions due to different execution paths
66+
* Block production or finalization blockers
67+
*Validator set manipulation vulnerabilities
68+
69+
### Cross-Pallet Interactions
70+
* Reentrancy-like patterns when calling other pallets
71+
* Circular dependencies between pallets
72+
* Assumptions about other pallet state that could be violated
73+
* Missing error handling from pallet calls
74+
75+
## Supply Chain & Dependency Security
76+
77+
**Flag any PR that:**
78+
* Adds new dependencies (require justification and thorough vetting)
79+
* Updates cryptographic or core dependencies
80+
* Uses dependencies with known vulnerabilities (check advisories)
81+
* Depends on unmaintained or obscure crates
82+
* Introduces git dependencies or path dependencies pointing outside the repo
83+
* Uses pre-release versions of critical dependencies
84+
* Includes large dependency version jumps without explanation
85+
86+
**For dependency changes, verify:**
87+
* Changelog review for security fixes or breaking changes
88+
* Maintainer reputation and project activity
89+
* Number of reverse dependencies (more = more scrutiny)
90+
* Whether it introduces new transitive dependencies
91+
92+
## Code Quality & Maintainability
93+
94+
* Code duplication that could lead to inconsistent bug fixes
95+
* Overly complex logic that obscures security issues
96+
* Missing error messages or unclear panic contexts in tests
97+
* Insufficient test coverage for new extrinsics or storage operations
98+
* Missing or inadequate documentation for complex algorithms
99+
* Magic numbers without explanation
100+
* TODO/FIXME comments introducing technical debt in critical paths
101+
102+
## External Contributor Scrutiny
103+
For contributors without "Nucleus" role, apply **maximum scrutiny**:
104+
* Verify the PR solves a real, documented issue
105+
* Check for hidden backdoors or logic bombs
106+
* Review commit history for suspicious patterns
107+
* Validate that changes match the stated purpose
108+
* Question any unusual patterns or overcomplicated solutions
109+
* Require clear explanations for non-obvious changes
110+
111+
## Build & Tooling
112+
* If lints fail (clippy, rustfmt, cargo check), suggest running `./scripts/fix_rust.sh`
113+
* Uncommitted `Cargo.lock` changes should be included in commits
114+
* Ensure CI passes before deep review
115+
116+
## Review Style
117+
* Be **concise** - report only legitimate issues, no nitpicks
118+
* Provide **specific line numbers** and **concrete examples**
119+
* Suggest **fixes** when possible, not just problems
120+
* **Severity levels**: Use [CRITICAL], [HIGH], [MEDIUM], [LOW] tags
121+
* Block PRs on [CRITICAL] and [HIGH] issues
122+
* For security issues, consider discussing privately before commenting publicly
123+
124+
## Final Check
125+
Before approving, ask yourself:
126+
1. Could this brick the chain? (panic, consensus break)
127+
2. Could this lose or steal funds? (arithmetic, logic errors)
128+
3. Could this DOS the network? (unbounded operations, weight issues)
129+
4. Could this introduce a backdoor? (especially for external contributors)
130+
5. Is this change necessary and minimal?
131+
132+
**Remember: $4B market cap. Err on the side of caution. When in doubt, escalate.**

.github/pull_request_template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Please ensure the following tasks are completed before requesting a review:
3131

3232
- [ ] I have performed a self-review of my own code
3333
- [ ] I have commented my code, particularly in hard-to-understand areas
34-
- [ ] I have run `cargo fmt` and `cargo clippy` to ensure my code is formatted and linted correctly
34+
- [ ] I have run `./scripts/fix_rust.sh` to ensure my code is formatted and linted correctly
3535
- [ ] I have made corresponding changes to the documentation
3636
- [ ] My changes generate no new warnings
3737
- [ ] I have added tests that prove my fix is effective or that my feature works

common/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub enum ProxyType {
147147
NonCritical,
148148
NonTransfer,
149149
Senate,
150-
NonFungibile, // Nothing involving moving TAO
150+
NonFungible, // Nothing involving moving TAO
151151
Triumvirate,
152152
Governance, // Both above governance
153153
Staking,

evm-tests/src/contracts/subnet.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -663,24 +663,6 @@ export const ISubnetABI = [
663663
stateMutability: "payable",
664664
type: "function",
665665
},
666-
{
667-
inputs: [
668-
{
669-
internalType: "uint16",
670-
name: "netuid",
671-
type: "uint16",
672-
},
673-
{
674-
internalType: "uint16",
675-
name: "maxWeightLimit",
676-
type: "uint16",
677-
},
678-
],
679-
name: "setMaxWeightLimit",
680-
outputs: [],
681-
stateMutability: "payable",
682-
type: "function",
683-
},
684666
{
685667
inputs: [
686668
{

evm-tests/test/subnet.precompile.hyperparameter.test.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -208,25 +208,17 @@ describe("Test the Subnet precompile contract", () => {
208208
assert.equal(valueFromContract, onchainValue);
209209
})
210210

211-
it("Can set maxWeightLimit parameter", async () => {
211+
it("Returns constant maxWeightLimit", async () => {
212212

213213
const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue()
214214
const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet);
215215
const netuid = totalNetwork - 1;
216216

217-
const newValue = 106;
218-
const tx = await contract.setMaxWeightLimit(netuid, newValue);
219-
await tx.wait();
220-
221-
let onchainValue = await api.query.SubtensorModule.MaxWeightsLimit.getValue(netuid)
222-
223-
224-
let valueFromContract = Number(
217+
const valueFromContract = Number(
225218
await contract.getMaxWeightLimit(netuid)
226219
);
227220

228-
assert.equal(valueFromContract, newValue)
229-
assert.equal(valueFromContract, onchainValue);
221+
assert.equal(valueFromContract, 0xFFFF)
230222
})
231223

232224
it("Can set immunityPeriod parameter", async () => {

hyperparameters.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
```rust
33
DefaultTake: u16 = 11_796; // 18% honest number.
44
TxRateLimit: u64 = 1; // [1 @ 64,888]
5+
MaxWeightsLimit: u16 = u16::MAX; // constant limit
56
```
67

78
### netuid 1 (text_prompting)
@@ -13,7 +14,6 @@ MaxAllowedUids: u16 = 1024;
1314
Issuance: u64 = 0;
1415
MinAllowedWeights: u16 = 8;
1516
EmissionValue: u64 = 142_223_000;
16-
MaxWeightsLimit: 455; // 455/2^16 = 0.0069
1717
ValidatorBatchSize: u16 = 1;
1818
ValidatorSequenceLen: u16 = 2048; // 2048
1919
ValidatorEpochLen: u16 = 100;
@@ -54,7 +54,6 @@ MaxAllowedUids: u16 = 4096;
5454
Issuance: u64 = 0;
5555
MinAllowedWeights: u16 = 50;
5656
EmissionValue: u64 = 857_777_000;
57-
MaxWeightsLimit: u16 = 655; // 655/2^16 = 0.01 [655 @ 7,160]
5857
ValidatorBatchSize: u16 = 32; // 32
5958
ValidatorSequenceLen: u16 = 256; // 256
6059
ValidatorEpochLen: u16 = 250; // [250 @ 7,161]

pallets/admin-utils/src/benchmarking.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -292,19 +292,6 @@ mod benchmarks {
292292
_(RawOrigin::Root, 1u16.into()/*netuid*/, 100u16/*immunity_period*/)/*sudo_set_immunity_period*/;
293293
}
294294

295-
#[benchmark]
296-
fn sudo_set_max_weight_limit() {
297-
// disable admin freeze window
298-
pallet_subtensor::Pallet::<T>::set_admin_freeze_window(0);
299-
pallet_subtensor::Pallet::<T>::init_new_network(
300-
1u16.into(), /*netuid*/
301-
1u16, /*tempo*/
302-
);
303-
304-
#[extrinsic_call]
305-
_(RawOrigin::Root, 1u16.into()/*netuid*/, 100u16/*max_weight_limit*/)/*sudo_set_max_weight_limit*/;
306-
}
307-
308295
#[benchmark]
309296
fn sudo_set_max_registrations_per_block() {
310297
// disable admin freeze window

pallets/admin-utils/src/lib.rs

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -426,40 +426,6 @@ pub mod pallet {
426426
Ok(())
427427
}
428428

429-
/// The extrinsic sets the adjustment beta for a subnet.
430-
/// It is only callable by the root account or subnet owner.
431-
/// The extrinsic will call the Subtensor pallet to set the adjustment beta.
432-
#[pallet::call_index(12)]
433-
#[pallet::weight(Weight::from_parts(26_890_000, 0)
434-
.saturating_add(<T as frame_system::Config>::DbWeight::get().reads(3_u64))
435-
.saturating_add(<T as frame_system::Config>::DbWeight::get().writes(1_u64)))]
436-
pub fn sudo_set_max_weight_limit(
437-
origin: OriginFor<T>,
438-
netuid: NetUid,
439-
max_weight_limit: u16,
440-
) -> DispatchResult {
441-
let maybe_owner = pallet_subtensor::Pallet::<T>::ensure_sn_owner_or_root_with_limits(
442-
origin,
443-
netuid,
444-
&[Hyperparameter::MaxWeightLimit.into()],
445-
)?;
446-
447-
ensure!(
448-
pallet_subtensor::Pallet::<T>::if_subnet_exist(netuid),
449-
Error::<T>::SubnetDoesNotExist
450-
);
451-
pallet_subtensor::Pallet::<T>::set_max_weight_limit(netuid, max_weight_limit);
452-
pallet_subtensor::Pallet::<T>::record_owner_rl(
453-
maybe_owner,
454-
netuid,
455-
&[Hyperparameter::MaxWeightLimit.into()],
456-
);
457-
log::debug!(
458-
"MaxWeightLimitSet( netuid: {netuid:?} max_weight_limit: {max_weight_limit:?} ) "
459-
);
460-
Ok(())
461-
}
462-
463429
/// The extrinsic sets the immunity period for a subnet.
464430
/// It is only callable by the root account or subnet owner.
465431
/// The extrinsic will call the Subtensor pallet to set the immunity period.
@@ -1252,7 +1218,7 @@ pub mod pallet {
12521218
/// The extrinsic will call the Subtensor pallet to set the minimum delegate take.
12531219
#[pallet::call_index(46)]
12541220
#[pallet::weight((
1255-
Weight::from_parts(5_000_000, 0).saturating_add(T::DbWeight::get().writes(1_u64)),
1221+
Weight::from_parts(7_885_000, 0).saturating_add(T::DbWeight::get().writes(1_u64)),
12561222
DispatchClass::Operational,
12571223
Pays::Yes
12581224
))]
@@ -1999,7 +1965,7 @@ pub mod pallet {
19991965
/// Only callable by root.
20001966
#[pallet::call_index(74)]
20011967
#[pallet::weight((
2002-
Weight::from_parts(5_771_000, 0)
1968+
Weight::from_parts(9_418_000, 0)
20031969
.saturating_add(<T as frame_system::Config>::DbWeight::get().reads(0_u64))
20041970
.saturating_add(<T as frame_system::Config>::DbWeight::get().writes(1_u64)),
20051971
DispatchClass::Operational

pallets/admin-utils/src/tests/mock.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ pub type UncheckedExtrinsic = TestXt<RuntimeCall, ()>;
7777
parameter_types! {
7878
pub const InitialMinAllowedWeights: u16 = 0;
7979
pub const InitialEmissionValue: u16 = 0;
80-
pub const InitialMaxWeightsLimit: u16 = u16::MAX;
8180
pub BlockWeights: limits::BlockWeights = limits::BlockWeights::with_sensible_defaults(
8281
Weight::from_parts(2_000_000_000_000, u64::MAX),
8382
Perbill::from_percent(75),
@@ -162,7 +161,6 @@ impl pallet_subtensor::Config for Test {
162161
type Scheduler = Scheduler;
163162
type InitialMinAllowedWeights = InitialMinAllowedWeights;
164163
type InitialEmissionValue = InitialEmissionValue;
165-
type InitialMaxWeightsLimit = InitialMaxWeightsLimit;
166164
type InitialTempo = InitialTempo;
167165
type InitialDifficulty = InitialDifficulty;
168166
type InitialAdjustmentInterval = InitialAdjustmentInterval;

pallets/admin-utils/src/tests/mod.rs

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -391,39 +391,6 @@ fn test_sudo_subnet_owner_cut() {
391391
});
392392
}
393393

394-
#[test]
395-
fn test_sudo_set_max_weight_limit() {
396-
new_test_ext().execute_with(|| {
397-
let netuid = NetUid::from(1);
398-
let to_be_set: u16 = 10;
399-
add_network(netuid, 10);
400-
let init_value: u16 = SubtensorModule::get_max_weight_limit(netuid);
401-
assert_eq!(
402-
AdminUtils::sudo_set_max_weight_limit(
403-
<<Test as Config>::RuntimeOrigin>::signed(U256::from(1)),
404-
netuid,
405-
to_be_set
406-
),
407-
Err(DispatchError::BadOrigin)
408-
);
409-
assert_eq!(
410-
AdminUtils::sudo_set_max_weight_limit(
411-
<<Test as Config>::RuntimeOrigin>::root(),
412-
netuid.next(),
413-
to_be_set
414-
),
415-
Err(Error::<Test>::SubnetDoesNotExist.into())
416-
);
417-
assert_eq!(SubtensorModule::get_max_weight_limit(netuid), init_value);
418-
assert_ok!(AdminUtils::sudo_set_max_weight_limit(
419-
<<Test as Config>::RuntimeOrigin>::root(),
420-
netuid,
421-
to_be_set
422-
));
423-
assert_eq!(SubtensorModule::get_max_weight_limit(netuid), to_be_set);
424-
});
425-
}
426-
427394
#[test]
428395
fn test_sudo_set_issuance() {
429396
new_test_ext().execute_with(|| {

0 commit comments

Comments
 (0)