Skip to content

Commit 32195fa

Browse files
authored
fix(pallet-tfgrid): improve IP validation (#870)
1 parent 0b8aa91 commit 32195fa

File tree

10 files changed

+374
-177
lines changed

10 files changed

+374
-177
lines changed

substrate-node/pallets/pallet-tfgrid/src/farm.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,13 @@ impl<T: Config> Pallet<T> {
322322
let mut public_ips_list: PublicIpListOf =
323323
vec![].try_into().map_err(|_| Error::<T>::InvalidPublicIP)?;
324324

325-
for ip in public_ips {
325+
for ip4 in public_ips {
326+
// Check if it's a valid IP4
327+
ip4.is_valid().map_err(|_| Error::<T>::InvalidPublicIP)?;
328+
326329
let pub_ip = PublicIP {
327-
ip: ip.ip,
328-
gateway: ip.gw,
330+
ip: ip4.ip,
331+
gateway: ip4.gw,
329332
contract_id: 0,
330333
};
331334

substrate-node/pallets/pallet-tfgrid/src/migrations/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ pub mod v12;
55
pub mod v13;
66
pub mod v14;
77
//pub mod v15;
8-
pub mod v16;
8+
pub mod v16;
9+
pub mod v17;
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use crate::*;
2+
use frame_support::{traits::Get, traits::OnRuntimeUpgrade, weights::Weight};
3+
use log::{debug, info};
4+
use scale_info::prelude::string::String;
5+
use sp_core::ConstU32;
6+
use sp_runtime::{BoundedVec, Saturating};
7+
use sp_std::{marker::PhantomData, vec::Vec};
8+
use tfchain_support::types::{PublicIP, IP4};
9+
10+
#[cfg(feature = "try-runtime")]
11+
use parity_scale_codec::{Decode, Encode};
12+
13+
pub struct FixFarmPublicIps<T: Config>(PhantomData<T>);
14+
15+
impl<T: Config> OnRuntimeUpgrade for FixFarmPublicIps<T> {
16+
#[cfg(feature = "try-runtime")]
17+
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
18+
info!("current pallet version: {:?}", PalletVersion::<T>::get());
19+
assert!(PalletVersion::<T>::get() >= types::StorageVersion::V16Struct);
20+
21+
let farms_count: u64 = Farms::<T>::iter().count() as u64;
22+
info!(
23+
"🔎 FixFarmPublicIps pre migration: Number of existing farms {:?}",
24+
farms_count
25+
);
26+
27+
info!("👥 TFGrid pallet to V17 passes PRE migrate checks ✅",);
28+
Ok(farms_count.encode())
29+
}
30+
31+
fn on_runtime_upgrade() -> Weight {
32+
if PalletVersion::<T>::get() == types::StorageVersion::V16Struct {
33+
fix_farm_public_ips::<T>()
34+
} else {
35+
info!(" >>> Unused TFGrid pallet V17 migration");
36+
Weight::zero()
37+
}
38+
}
39+
40+
#[cfg(feature = "try-runtime")]
41+
fn post_upgrade(pre_farms_count: Vec<u8>) -> Result<(), &'static str> {
42+
info!("current pallet version: {:?}", PalletVersion::<T>::get());
43+
assert!(PalletVersion::<T>::get() >= types::StorageVersion::V17Struct);
44+
45+
// Check number of farms against pre-check result
46+
let pre_farms_count: u64 = Decode::decode(&mut pre_farms_count.as_slice())
47+
.expect("the state parameter should be something that was generated by pre_upgrade");
48+
assert_eq!(
49+
Farms::<T>::iter().count() as u64,
50+
pre_farms_count,
51+
"Number of farms migrated does not match"
52+
);
53+
54+
info!(
55+
"👥 TFGrid pallet migration to {:?} passes POST migrate checks ✅",
56+
Pallet::<T>::pallet_version()
57+
);
58+
59+
Ok(())
60+
}
61+
}
62+
63+
pub fn fix_farm_public_ips<T: Config>() -> frame_support::weights::Weight {
64+
info!(" >>> Migrating farms storage...");
65+
66+
let mut r = 0u64;
67+
let mut w = 0u64;
68+
69+
let farms = Farms::<T>::iter().collect::<Vec<_>>();
70+
r.saturating_accrue(farms.len() as u64);
71+
72+
for (_, mut farm) in Farms::<T>::iter() {
73+
r.saturating_inc();
74+
let size = farm.public_ips.len();
75+
76+
farm.public_ips.retain(|pubip| {
77+
let ip4 = IP4 {
78+
ip: pubip.ip.clone(),
79+
gw: pubip.gateway.clone(),
80+
};
81+
ip4.is_valid().is_ok()
82+
});
83+
84+
// Update farm only if some invalid IP was found
85+
if farm.public_ips.len() < size {
86+
debug!("Farm #{:?}: invalid IP found", farm.id);
87+
debug!(
88+
" public ips were: {:?}",
89+
public_ips_to_string(Farms::<T>::get(farm.id).unwrap().public_ips)
90+
);
91+
92+
Farms::<T>::insert(farm.id, &farm);
93+
94+
debug!(
95+
" public ips now: {:?}",
96+
public_ips_to_string(Farms::<T>::get(farm.id).unwrap().public_ips)
97+
);
98+
w.saturating_inc();
99+
}
100+
}
101+
102+
info!(" <<< Farms storage updated! Migrated {} Farms ✅", w);
103+
104+
// Update pallet storage version
105+
PalletVersion::<T>::set(types::StorageVersion::V17Struct);
106+
w.saturating_inc();
107+
info!(" <<< Storage version upgraded");
108+
109+
// Return the weight consumed by the migration.
110+
T::DbWeight::get().reads_writes(r, w)
111+
}
112+
113+
fn public_ips_to_string(public_ips: BoundedVec<PublicIP, ConstU32<256>>) -> String {
114+
let mut s = String::new();
115+
for pub_ip in public_ips {
116+
s.push_str("{ ip: ");
117+
s.push_str(&String::from_utf8_lossy(&pub_ip.ip));
118+
s.push_str(", gw: ");
119+
s.push_str(&String::from_utf8_lossy(&pub_ip.gateway));
120+
s.push_str("} ");
121+
}
122+
s
123+
}

substrate-node/pallets/pallet-tfgrid/src/tests.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ fn test_update_farm_name_existing_name_fails() {
411411
}
412412

413413
#[test]
414-
fn test_create_farm_with_double_ip_fails() {
414+
fn test_create_farm_duplicate_ip_fails() {
415415
ExternalityBuilder::build().execute_with(|| {
416416
create_entity();
417417
create_twin();
@@ -438,6 +438,26 @@ fn test_create_farm_with_double_ip_fails() {
438438
});
439439
}
440440

441+
#[test]
442+
fn test_create_farm_not_valid_ip_fails() {
443+
ExternalityBuilder::build().execute_with(|| {
444+
create_entity();
445+
create_twin();
446+
447+
let farm_name = get_farm_name_input(b"test_farm");
448+
449+
let mut pub_ips: PublicIpListInput<TestRuntime> = bounded_vec![];
450+
let ip = get_public_ip_ip_input(b"185.206.122.33/24");
451+
let gw = get_public_ip_gw_input(b"185.206.122.33");
452+
pub_ips.try_push(IP4 { ip, gw }).unwrap();
453+
454+
assert_noop!(
455+
TfgridModule::create_farm(RuntimeOrigin::signed(alice()), farm_name, pub_ips),
456+
Error::<TestRuntime>::InvalidPublicIP
457+
);
458+
});
459+
}
460+
441461
#[test]
442462
fn test_adding_ip_to_farm_works() {
443463
ExternalityBuilder::build().execute_with(|| {

substrate-node/pallets/pallet-tfgrid/src/types.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ pub enum StorageVersion {
2424
V14Struct,
2525
V15Struct,
2626
V16Struct,
27+
V17Struct,
2728
}
2829

2930
impl Default for StorageVersion {
3031
fn default() -> StorageVersion {
31-
StorageVersion::V16Struct
32+
StorageVersion::V17Struct
3233
}
3334
}
3435

substrate-node/runtime/src/lib.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -771,10 +771,11 @@ pub type Executive = frame_executive::Executive<
771771
// All migrations executed on runtime upgrade as a nested tuple of types implementing
772772
// `OnRuntimeUpgrade`.
773773
type Migrations = (
774-
pallet_tfgrid::migrations::v16::KillNodeGpuStatus<Runtime>,
775-
pallet_smart_contract::migrations::v10::ReworkBillingLoopInsertion<Runtime>,
776-
pallet_smart_contract::migrations::v11::ExtendContractLock<Runtime>,
777-
migrations::remove_sudo::RemoveSudo<Runtime>,
774+
// pallet_tfgrid::migrations::v16::KillNodeGpuStatus<Runtime>,
775+
// pallet_smart_contract::migrations::v10::ReworkBillingLoopInsertion<Runtime>,
776+
// pallet_smart_contract::migrations::v11::ExtendContractLock<Runtime>,
777+
// migrations::remove_sudo::RemoveSudo<Runtime>,
778+
pallet_tfgrid::migrations::v17::FixFarmPublicIps<Runtime>,
778779
);
779780

780781
// follows Substrate's non destructive way of eliminating otherwise required

substrate-node/support/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#![cfg_attr(not(feature = "std"), no_std)]
22

3+
pub mod constants;
4+
pub mod resources;
35
pub mod traits;
46
pub mod types;
5-
pub mod resources;
6-
pub mod constants;
7+
8+
#[cfg(test)]
9+
mod tests;

substrate-node/support/src/resources.rs

Lines changed: 0 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -114,150 +114,3 @@ impl Resources {
114114
return self.hru == 0 && self.sru == 0 && self.cru == 0 && self.mru == 0;
115115
}
116116
}
117-
118-
#[cfg(test)]
119-
mod test {
120-
use super::*;
121-
122-
#[test]
123-
fn test_calc_cu_falsy_values() {
124-
let resources = Resources {
125-
hru: 0,
126-
cru: 0,
127-
mru: 0,
128-
sru: 0,
129-
};
130-
131-
let cu = resources.get_cu();
132-
assert_eq!(cu, 0);
133-
}
134-
135-
#[test]
136-
fn test_calc_cu() {
137-
let resources = Resources {
138-
hru: 4 * GIGABYTE as u64 * 1024,
139-
cru: 64,
140-
mru: 64 * GIGABYTE as u64 * 1024,
141-
sru: 12 * GIGABYTE as u64 * 1024,
142-
};
143-
144-
let cu = resources.get_cu();
145-
assert_eq!(cu, 256);
146-
}
147-
148-
#[test]
149-
fn test_calc_cu_2() {
150-
let resources = Resources {
151-
hru: 4 * GIGABYTE as u64 * 1024,
152-
cru: 4,
153-
mru: 8,
154-
sru: 12 * GIGABYTE as u64 * 1024,
155-
};
156-
157-
let cu = resources.get_cu();
158-
assert_eq!(cu, 2);
159-
}
160-
161-
#[test]
162-
fn test_calc_su() {
163-
let resources = Resources {
164-
hru: 4 * GIGABYTE as u64 * 1024,
165-
cru: 64,
166-
mru: 64,
167-
sru: 12 * GIGABYTE as u64 * 1024,
168-
};
169-
170-
let su = resources.get_su();
171-
assert_eq!(su, 52);
172-
}
173-
174-
#[test]
175-
fn test_calc_su_2() {
176-
let resources = Resources {
177-
hru: 0,
178-
cru: 64,
179-
mru: 64,
180-
sru: 12 * GIGABYTE as u64 * 1024,
181-
};
182-
183-
let su = resources.get_su();
184-
assert_eq!(su, 49);
185-
}
186-
187-
#[test]
188-
fn test_calc_su_3() {
189-
let resources = Resources {
190-
hru: 0,
191-
cru: 64,
192-
mru: 64,
193-
sru: 0,
194-
};
195-
196-
let su = resources.get_su();
197-
assert_eq!(su, 0);
198-
}
199-
200-
#[test]
201-
fn test_calc_su_4() {
202-
let resources = Resources {
203-
hru: 4 * GIGABYTE as u64 * 1024,
204-
cru: 64,
205-
mru: 64,
206-
sru: 0,
207-
};
208-
209-
let su = resources.get_su();
210-
assert_eq!(su, 3);
211-
}
212-
213-
#[test]
214-
fn test_resources_diff() {
215-
let resources = Resources {
216-
hru: 4 * GIGABYTE as u64 * 1024,
217-
cru: 64,
218-
mru: 64 * GIGABYTE as u64,
219-
sru: 0,
220-
};
221-
222-
let new_resources = Resources {
223-
hru: 4 * GIGABYTE as u64 * 1024,
224-
cru: 64,
225-
mru: 64 * GIGABYTE as u64,
226-
sru: 0,
227-
};
228-
229-
assert_eq!(Resources::has_changed(&resources, &new_resources, 1), false);
230-
231-
let resources = Resources {
232-
hru: 4 * GIGABYTE as u64 * 1024,
233-
cru: 64,
234-
mru: 64 * GIGABYTE as u64,
235-
sru: 0,
236-
};
237-
238-
let new_resources = Resources {
239-
hru: 4 * GIGABYTE as u64 * 1024,
240-
cru: 64,
241-
mru: 40 * GIGABYTE as u64,
242-
sru: 0,
243-
};
244-
245-
assert_eq!(Resources::has_changed(&resources, &new_resources, 1), true);
246-
247-
let resources = Resources {
248-
hru: 4 * GIGABYTE as u64 * 1024,
249-
cru: 64,
250-
mru: 64 * GIGABYTE as u64,
251-
sru: 1000 * GIGABYTE as u64,
252-
};
253-
254-
let new_resources = Resources {
255-
hru: 4 * GIGABYTE as u64 * 1024,
256-
cru: 64,
257-
mru: 64 * GIGABYTE as u64,
258-
sru: 989 * GIGABYTE as u64,
259-
};
260-
261-
assert_eq!(Resources::has_changed(&resources, &new_resources, 1), true);
262-
}
263-
}

0 commit comments

Comments
 (0)