Skip to content

Commit 59da0eb

Browse files
authored
Merge pull request #4540 from anoma/murisi/migrate-wasms
Implemented logic to update transaction WASMs in hard-fork migration.
2 parents 1e428c9 + ad7db27 commit 59da0eb

File tree

4 files changed

+199
-60
lines changed

4 files changed

+199
-60
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Implemented an example hard-fork migration for transaction WASM code.
2+
([\#4540](https://github.com/anoma/namada/pull/4540))

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,5 @@ data-encoding.workspace = true
5353
linkme.workspace = true
5454
proptest.workspace = true
5555
serde_json.workspace = true
56+
sha2.workspace = true
5657
tokio = { workspace = true, default-features = false }

examples/make-db-migration.rs

Lines changed: 195 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ use masp_primitives::transaction::components::I128Sum;
99
use namada_core::borsh::BorshSerializeExt;
1010
use namada_core::hash::Hash;
1111
use namada_core::masp::{Precision, encode_asset_type};
12+
use namada_core::storage::Key;
1213
use namada_macros::BorshDeserializer;
1314
use namada_migrations::REGISTER_DESERIALIZERS;
15+
use namada_parameters::storage::get_tx_allowlist_storage_key;
1416
use namada_sdk::address::Address;
1517
use namada_sdk::ibc::trace::ibc_token;
1618
use namada_sdk::masp_primitives::asset_type::AssetType;
@@ -25,6 +27,7 @@ use namada_shielded_token::storage_key::{
2527
use namada_shielded_token::{ConversionLeaf, ConversionState, MaspEpoch};
2628
use namada_trans_token::storage_key::{balance_key, minted_balance_key};
2729
use namada_trans_token::{Amount, Denomination, MaspDigitPos, Store};
30+
use sha2::{Digest, Sha256};
2831

2932
pub const OLD_CONVERSION_STATE_TYPE_HASH: &str =
3033
"05E2FD0BEBD54A05AAE349BBDE61F90893F09A72850EFD4F69060821EC5DE65F";
@@ -54,7 +57,7 @@ impl From<ConversionState> for NewConversionState {
5457
}
5558

5659
// Demonstrate how to set the minted balance using a migration
57-
fn minted_balance_migration() {
60+
fn minted_balance_migration(updates: &mut Vec<migrations::DbUpdateType>) {
5861
let person =
5962
Address::decode("tnam1q9rhgyv3ydq0zu3whnftvllqnvhvhm270qxay5tn")
6063
.unwrap();
@@ -65,34 +68,29 @@ fn minted_balance_migration() {
6568
let minted_key = minted_balance_key(&nam);
6669
let minted_value = Amount::from(117600000504441u64);
6770

68-
let updates = [
69-
migrations::DbUpdateType::Add {
70-
key: balance_key(&nam, &person),
71-
cf: DbColFam::SUBSPACE,
72-
value: amount.into(),
73-
force: false,
74-
},
75-
migrations::DbUpdateType::Add {
76-
key: minted_key,
77-
cf: DbColFam::SUBSPACE,
78-
value: minted_value.into(),
79-
force: false,
80-
},
81-
migrations::DbUpdateType::RepeatDelete(apfel, DbColFam::SUBSPACE),
82-
];
83-
let changes = migrations::DbChanges {
84-
changes: updates.into_iter().collect(),
85-
};
86-
std::fs::write(
87-
"minted_balance_migration.json",
88-
serde_json::to_string(&changes).unwrap(),
89-
)
90-
.unwrap();
71+
updates.push(migrations::DbUpdateType::Add {
72+
key: balance_key(&nam, &person),
73+
cf: DbColFam::SUBSPACE,
74+
value: amount.into(),
75+
force: false,
76+
});
77+
updates.push(migrations::DbUpdateType::Add {
78+
key: minted_key,
79+
cf: DbColFam::SUBSPACE,
80+
value: minted_value.into(),
81+
force: false,
82+
});
83+
updates.push(migrations::DbUpdateType::RepeatDelete(
84+
apfel,
85+
DbColFam::SUBSPACE,
86+
));
9187
}
9288

9389
// Demonstrate how to set the shielded reward precision of IBC tokens using a
9490
// migration
95-
fn shielded_reward_precision_migration() {
91+
fn shielded_reward_precision_migration(
92+
updates: &mut Vec<migrations::DbUpdateType>,
93+
) {
9694
pub type ChannelId = &'static str;
9795
pub type BaseToken = &'static str;
9896

@@ -105,7 +103,6 @@ fn shielded_reward_precision_migration() {
105103
("channel-0", "stutia", 1000u128),
106104
];
107105

108-
let mut updates = Vec::new();
109106
// Set IBC token shielded reward precisions
110107
for (channel_id, base_token, precision) in IBC_TOKENS {
111108
let ibc_denom = format!("transfer/{channel_id}/{base_token}");
@@ -122,20 +119,13 @@ fn shielded_reward_precision_migration() {
122119
force: false,
123120
});
124121
}
125-
126-
let changes = migrations::DbChanges {
127-
changes: updates.into_iter().collect(),
128-
};
129-
std::fs::write(
130-
"shielded_reward_precision_migration.json",
131-
serde_json::to_string(&changes).unwrap(),
132-
)
133-
.unwrap();
134122
}
135123

136124
// Demonstrate clearing MASP rewards for the given IBC tokens by overwriting
137125
// their allowed conversions with conversions that do not contain rewards.
138-
fn shielded_reward_reset_migration() {
126+
fn shielded_reward_reset_migration(
127+
updates: &mut Vec<migrations::DbUpdateType>,
128+
) {
139129
pub type ChannelId = &'static str;
140130
pub type BaseToken = &'static str;
141131

@@ -155,7 +145,6 @@ fn shielded_reward_reset_migration() {
155145
("channel-0", "stutia", 1000u128),
156146
];
157147

158-
let mut updates = Vec::new();
159148
// Reset the allowed conversions for the above tokens
160149
for (channel_id, base_token, precision) in IBC_TOKENS {
161150
let ibc_denom = format!("transfer/{channel_id}/{base_token}");
@@ -241,20 +230,11 @@ fn shielded_reward_reset_migration() {
241230
}
242231
}
243232
}
244-
245-
let changes = migrations::DbChanges {
246-
changes: updates.into_iter().collect(),
247-
};
248-
std::fs::write(
249-
"shielded_reward_reset_migration.json",
250-
serde_json::to_string(&changes).unwrap(),
251-
)
252-
.unwrap();
253233
}
254234

255235
// Demonstrate replacing the entire conversion state with a new state that does
256236
// not contain rewards.
257-
fn conversion_state_migration() {
237+
fn conversion_state_migration(updates: &mut Vec<migrations::DbUpdateType>) {
258238
// Valid precisions must be in the intersection of i128 and u128
259239
pub type Precision = u128;
260240

@@ -309,7 +289,6 @@ fn conversion_state_migration() {
309289
),
310290
];
311291

312-
let mut updates = Vec::new();
313292
let mut assets = BTreeMap::new();
314293
let mut conv_notes = Vec::new();
315294
// Reset the allowed conversions for the above tokens
@@ -430,21 +409,177 @@ fn conversion_state_migration() {
430409
value: assets_hash.into(),
431410
force: false,
432411
});
412+
}
433413

434-
let changes = migrations::DbChanges {
435-
changes: updates.into_iter().collect(),
436-
};
437-
std::fs::write(
438-
"conversion_state_migration.json",
439-
serde_json::to_string(&changes).unwrap(),
440-
)
441-
.unwrap();
414+
// Demonstrate upgrading the transaction WASM code and hashes in storage
415+
fn wasm_migration(updates: &mut Vec<migrations::DbUpdateType>) {
416+
// wasm_updates[x].0) The WASM hash that is being replaced
417+
// wasm_updates[x].1) The name of WASM being updated
418+
// wasm_updates[x].2) The bytes of the new WASM code
419+
let wasm_updates: Vec<(&str, &str, &[u8])> =
420+
vec![
421+
(
422+
"83afcbf97c35188991ae2e73db2f48cb8d019c4295fe5323d9c3dfebcd5dbec0",
423+
"tx_transfer.wasm",
424+
//include_bytes!("tx_transfer.5c7e44e61c00df351fa7c497cd2e186d71909f1a18db0c8d362dff36057e0fbf.wasm"),
425+
&[0xDE, 0xAD, 0xBE, 0xEF],
426+
),
427+
(
428+
"6ff3c2a2ebc65061a9b89abd15fb37851ca77e162b42b7989889bd537e802b09",
429+
"tx_ibc.wasm",
430+
//include_bytes!("tx_ibc.ae9b900edd6437461addd1fe1c723c4b1a8ac8d2fce30e1e4c417ef34f299f73.wasm"),
431+
&[0xDE, 0xAD, 0xBE, 0xEF],
432+
),
433+
];
434+
435+
// Update the tx allowlist parameter
436+
let tx_allowlist_key = get_tx_allowlist_storage_key();
437+
let tx_allowlist: Vec<&str> = vec![
438+
"ec357c39e05677da3d8da359fee6e3a8b9012dd1a7e7def51f4e484132f68c77",
439+
"a324288bdc7a7d3cb15ca5ef3ebb04b9121b1d5804478dabd1ef4533459d7069",
440+
"6012fff1d191a545d6f7960f1dd9b2df5fcdfc9dbb8dfd22bb1458f3983144b9",
441+
"4fe1bb1e76c21eacd5eb84782c51aebd683643eefbd1034e4e13aa7284f508f8",
442+
"23eec5e1bad79387e57d052840b86ff061aa3182638f690a642126183788f0e3",
443+
"5a31f468d03207a8e566a55072ddad7aad018fc635621564fb1c105b0f089f4d",
444+
"9eb40c4b40b5af540f9a32f8bd377a53cd3b5e0c3c799b4381ef6475f333e33d",
445+
"2b3cf66f49093f674793fcdba72d45f1d7c0e34556800f597d3d5242d97091e0",
446+
"6ff3c2a2ebc65061a9b89abd15fb37851ca77e162b42b7989889bd537e802b09",
447+
"31a7199befce4226faad7fe1744895fb6845ee0749016c3a2a0a31b26088aff9",
448+
"f0d270cab3357124eb8894c1e7cb0e775056ed613e41d075e23467bcaa36a1f7",
449+
"51c4d0149807597c1c7981cf28cb8b078c93843b7ae91a6cd9e6b422f343e9a3",
450+
"a07d722db5d3d06b0c65cb0c20811ce2a95105cebe2456a3ea6334eb2438fbab",
451+
"f1cdb278dae8b7ab28fd850dcf9746b03aee2b42444ec9e39ae3a0bd46f3e17c",
452+
"b48de32b91a58d8e63cd283bd96276f38736822ca8f90bfec2093eefdcdf5148",
453+
"83afcbf97c35188991ae2e73db2f48cb8d019c4295fe5323d9c3dfebcd5dbec0",
454+
"8293cecc00c63bb4b6216eec912c57c72544f42203ba1ff5a42ae098c9e921e4",
455+
"f0e37af0417f5d54f20c81c2cf1b9301bd13ce79695b78c85d11b2ba187fa86d",
456+
"0c650c7869da1ac3e734a4367557a499c937962effde4f7e7cc609278000ebd1",
457+
"dbb6f005883075ab4133d8bd367af914a899946e7ae532f816be48c77044a512",
458+
"bf4716b590b68562ee2c872757a0c370daf1504596d4350fffc0b94a566072ca",
459+
"f6330d8c8bc92d9f8ea0f023688873722b65291bc6db9bb11ab3a0836e1be86b",
460+
"c4357f5548c43086e56f22ac2e951ee2500368d8ed2479c0d0046b6e59f8a8e5",
461+
"b4261ecafcfb0254efb39165311268d99bb5aa85ac47514913317d20f1791790",
462+
];
463+
let mut tx_allowlist: Vec<String> = tx_allowlist
464+
.into_iter()
465+
.map(|hash_str| {
466+
Hash::from_str(hash_str).unwrap().to_string().to_lowercase()
467+
})
468+
.collect();
469+
// Replace the targetted old hashes
470+
for (old_code_hash, name, code) in wasm_updates {
471+
let old_code_hash = Hash::from_str(old_code_hash).unwrap();
472+
let new_code_hash = Hash(*Sha256::digest(code).as_ref());
473+
let new_code_len = u64::try_from(code.len()).unwrap();
474+
let pos = tx_allowlist
475+
.iter()
476+
.position(|x| Hash::from_str(x).unwrap() == old_code_hash)
477+
.expect("old tx code hash not found");
478+
tx_allowlist[pos] = new_code_hash.to_string().to_lowercase();
479+
480+
// Delete the old tx code
481+
let old_code_key = Key::wasm_code(&old_code_hash);
482+
let old_code_len_key = Key::wasm_code_len(&old_code_hash);
483+
updates.push(migrations::DbUpdateType::Delete(
484+
old_code_key,
485+
DbColFam::SUBSPACE,
486+
));
487+
updates.push(migrations::DbUpdateType::Delete(
488+
old_code_len_key,
489+
DbColFam::SUBSPACE,
490+
));
491+
492+
// Write the new tx code into storage
493+
let code_key = Key::wasm_code(&new_code_hash);
494+
let code_len_key = Key::wasm_code_len(&new_code_hash);
495+
let hash_key = Key::wasm_hash(name);
496+
let code_name_key = Key::wasm_code_name(name.to_owned());
497+
498+
updates.push(migrations::DbUpdateType::Add {
499+
key: code_key,
500+
cf: DbColFam::SUBSPACE,
501+
value: code.to_vec().into(),
502+
force: false,
503+
});
504+
updates.push(migrations::DbUpdateType::Add {
505+
key: code_len_key,
506+
cf: DbColFam::SUBSPACE,
507+
value: new_code_len.into(),
508+
force: false,
509+
});
510+
updates.push(migrations::DbUpdateType::Add {
511+
key: hash_key,
512+
cf: DbColFam::SUBSPACE,
513+
value: new_code_hash.into(),
514+
force: false,
515+
});
516+
updates.push(migrations::DbUpdateType::Add {
517+
key: code_name_key,
518+
cf: DbColFam::SUBSPACE,
519+
value: new_code_hash.into(),
520+
force: false,
521+
});
522+
}
523+
// Put the allow list in storage
524+
updates.push(migrations::DbUpdateType::Add {
525+
key: tx_allowlist_key,
526+
cf: DbColFam::SUBSPACE,
527+
value: tx_allowlist.into(),
528+
force: false,
529+
});
442530
}
443531

444532
// Generate various migrations
445533
fn main() {
446-
minted_balance_migration();
447-
shielded_reward_precision_migration();
448-
shielded_reward_reset_migration();
449-
conversion_state_migration();
534+
// Write an example migration that updates minted balances
535+
let mut minted_balance_changes = migrations::DbChanges { changes: vec![] };
536+
minted_balance_migration(&mut minted_balance_changes.changes);
537+
std::fs::write(
538+
"minted_balance_migration.json",
539+
serde_json::to_string(&minted_balance_changes).unwrap(),
540+
)
541+
.unwrap();
542+
// Write an example migration that updates token precision
543+
let mut reward_precision_changes =
544+
migrations::DbChanges { changes: vec![] };
545+
shielded_reward_precision_migration(&mut reward_precision_changes.changes);
546+
std::fs::write(
547+
"reward_precision_migration.json",
548+
serde_json::to_string(&reward_precision_changes).unwrap(),
549+
)
550+
.unwrap();
551+
// Write an example migration that resets shielded rewards
552+
let mut reward_reset_changes = migrations::DbChanges { changes: vec![] };
553+
shielded_reward_reset_migration(&mut reward_reset_changes.changes);
554+
std::fs::write(
555+
"reward_reset_migration.json",
556+
serde_json::to_string(&reward_reset_changes).unwrap(),
557+
)
558+
.unwrap();
559+
// Write an example migration that directly updates conversion state
560+
let mut conversion_state_changes =
561+
migrations::DbChanges { changes: vec![] };
562+
conversion_state_migration(&mut conversion_state_changes.changes);
563+
std::fs::write(
564+
"conversion_state_migration.json",
565+
serde_json::to_string(&conversion_state_changes).unwrap(),
566+
)
567+
.unwrap();
568+
// Write an example migration that just updates WASMs
569+
let mut wasm_changes = migrations::DbChanges { changes: vec![] };
570+
wasm_migration(&mut wasm_changes.changes);
571+
std::fs::write(
572+
"wasm_migration.json",
573+
serde_json::to_string(&wasm_changes).unwrap(),
574+
)
575+
.unwrap();
576+
// Write an example migration that updates WASMs and resets shielded rewards
577+
let mut pre_phase4_changes = migrations::DbChanges { changes: vec![] };
578+
shielded_reward_reset_migration(&mut pre_phase4_changes.changes);
579+
wasm_migration(&mut pre_phase4_changes.changes);
580+
std::fs::write(
581+
"pre_phase4_migration.json",
582+
serde_json::to_string(&pre_phase4_changes).unwrap(),
583+
)
584+
.unwrap();
450585
}

0 commit comments

Comments
 (0)