wormhole/sui/wormhole/sources/guardian_set_upgrade.move

189 lines
8.1 KiB
Plaintext

module wormhole::guardian_set_upgrade {
use std::vector::{Self};
use sui::tx_context::{TxContext};
use wormhole::deserialize;
use wormhole::cursor::{Self};
use wormhole::myvaa::{Self as vaa};
//use wormhole::myvaa::{Self as vaa};
use wormhole::state::{Self, State};
use wormhole::structs::{
Guardian,
create_guardian,
create_guardian_set
};
use wormhole::myu32::{Self as u32,U32};
use wormhole::myu16::{Self as u16};
const E_WRONG_GUARDIAN_LEN: u64 = 0x0;
const E_NO_GUARDIAN_SET: u64 = 0x1;
const E_INVALID_MODULE: u64 = 0x2;
const E_INVALID_ACTION: u64 = 0x3;
const E_INVALID_TARGET: u64 = 0x4;
const E_NON_INCREMENTAL_GUARDIAN_SETS: u64 = 0x5;
struct GuardianSetUpgrade {
new_index: U32,
guardians: vector<Guardian>,
}
public entry fun submit_vaa(state: &mut State, vaa: vector<u8>, ctx: &mut TxContext) {
let vaa = vaa::parse_and_verify(state, vaa, ctx);
vaa::assert_governance(state, &vaa);
vaa::replay_protect(state, &vaa);
do_upgrade(state, parse_payload(vaa::destroy(vaa)), ctx)
}
fun do_upgrade(state: &mut State, upgrade: GuardianSetUpgrade, ctx: &TxContext) {
let current_index = state::get_current_guardian_set_index(state);
let GuardianSetUpgrade {
new_index,
guardians,
} = upgrade;
assert!(
u32::to_u64(new_index) == u32::to_u64(current_index) + 1,
E_NON_INCREMENTAL_GUARDIAN_SETS
);
state::update_guardian_set_index(state, new_index);
state::store_guardian_set(state, new_index, create_guardian_set(new_index, guardians));
state::expire_guardian_set(state, current_index, ctx);
}
#[test_only]
public fun do_upgrade_test(s: &mut State, new_index: U32, guardians: vector<Guardian>, ctx: &mut TxContext) {
do_upgrade(s, GuardianSetUpgrade { new_index, guardians }, ctx)
}
public fun parse_payload(bytes: vector<u8>): GuardianSetUpgrade {
let cur = cursor::cursor_init(bytes);
let guardians = vector::empty<Guardian>();
let target_module = deserialize::deserialize_vector(&mut cur, 32);
let expected_module = x"00000000000000000000000000000000000000000000000000000000436f7265"; // Core
assert!(target_module == expected_module, E_INVALID_MODULE);
let action = deserialize::deserialize_u8(&mut cur);
assert!(action == 0x02, E_INVALID_ACTION);
let chain = deserialize::deserialize_u16(&mut cur);
assert!(chain == u16::from_u64(0x00), E_INVALID_TARGET);
let new_index = deserialize::deserialize_u32(&mut cur);
let guardian_len = deserialize::deserialize_u8(&mut cur);
while (guardian_len > 0) {
let key = deserialize::deserialize_vector(&mut cur, 20);
vector::push_back(&mut guardians, create_guardian(key));
guardian_len = guardian_len - 1;
};
cursor::destroy_empty(cur);
GuardianSetUpgrade {
new_index: new_index,
guardians: guardians,
}
}
#[test_only]
public fun split(upgrade: GuardianSetUpgrade): (U32, vector<Guardian>) {
let GuardianSetUpgrade { new_index, guardians } = upgrade;
(new_index, guardians)
}
}
#[test_only]
module wormhole::guardian_set_upgrade_test {
use std::vector;
use wormhole::structs::{create_guardian};
use wormhole::guardian_set_upgrade;
use wormhole::myu32::{Self as u32};
use sui::test_scenario::{Self, Scenario, next_tx, take_shared, return_shared, ctx};
use sui::tx_context::{increment_epoch_number};
fun scenario(): Scenario { test_scenario::begin(@0x123233) }
fun people(): (address, address, address) { (@0x124323, @0xE05, @0xFACE) }
#[test]
public fun test_parse_guardian_set_upgrade() {
use wormhole::myu32::{Self as u32};
let b = x"00000000000000000000000000000000000000000000000000000000436f7265020000000000011358cc3ae5c097b213ce3c81979e1b9f9570746aa5ff6cb952589bde862c25ef4392132fb9d4a42157114de8460193bdf3a2fcf81f86a09765f4762fd1107a0086b32d7a0977926a205131d8731d39cbeb8c82b2fd82faed2711d59af0f2499d16e726f6b211b39756c042441be6d8650b69b54ebe715e234354ce5b4d348fb74b958e8966e2ec3dbd4958a7cdeb5f7389fa26941519f0863349c223b73a6ddee774a3bf913953d695260d88bc1aa25a4eee363ef0000ac0076727b35fbea2dac28fee5ccb0fea768eaf45ced136b9d9e24903464ae889f5c8a723fc14f93124b7c738843cbb89e864c862c38cddcccf95d2cc37a4dc036a8d232b48f62cdd4731412f4890da798f6896a3331f64b48c12d1d57fd9cbe7081171aa1be1d36cafe3867910f99c09e347899c19c38192b6e7387ccd768277c17dab1b7a5027c0b3cf178e21ad2e77ae06711549cfbb1f9c7a9d8096e85e1487f35515d02a92753504a8d75471b9f49edb6fbebc898f403e4773e95feb15e80c9a99c8348d";
let (new_index, guardians) = guardian_set_upgrade::split(guardian_set_upgrade::parse_payload(b));
assert!(new_index == u32::from_u64(1), 0);
assert!(vector::length(&guardians) == 19, 0);
let expected = vector[
create_guardian(x"58cc3ae5c097b213ce3c81979e1b9f9570746aa5"),
create_guardian(x"ff6cb952589bde862c25ef4392132fb9d4a42157"),
create_guardian(x"114de8460193bdf3a2fcf81f86a09765f4762fd1"),
create_guardian(x"107a0086b32d7a0977926a205131d8731d39cbeb"),
create_guardian(x"8c82b2fd82faed2711d59af0f2499d16e726f6b2"),
create_guardian(x"11b39756c042441be6d8650b69b54ebe715e2343"),
create_guardian(x"54ce5b4d348fb74b958e8966e2ec3dbd4958a7cd"),
create_guardian(x"eb5f7389fa26941519f0863349c223b73a6ddee7"),
create_guardian(x"74a3bf913953d695260d88bc1aa25a4eee363ef0"),
create_guardian(x"000ac0076727b35fbea2dac28fee5ccb0fea768e"),
create_guardian(x"af45ced136b9d9e24903464ae889f5c8a723fc14"),
create_guardian(x"f93124b7c738843cbb89e864c862c38cddcccf95"),
create_guardian(x"d2cc37a4dc036a8d232b48f62cdd4731412f4890"),
create_guardian(x"da798f6896a3331f64b48c12d1d57fd9cbe70811"),
create_guardian(x"71aa1be1d36cafe3867910f99c09e347899c19c3"),
create_guardian(x"8192b6e7387ccd768277c17dab1b7a5027c0b3cf"),
create_guardian(x"178e21ad2e77ae06711549cfbb1f9c7a9d8096e8"),
create_guardian(x"5e1487f35515d02a92753504a8d75471b9f49edb"),
create_guardian(x"6fbebc898f403e4773e95feb15e80c9a99c8348d"),
];
assert!(expected == guardians, 0);
}
#[test]
public fun test_guardian_set_expiry() {
use wormhole::state::{State, Self as worm_state};
use wormhole::test_state::{init_wormhole_state};
let (admin, _, _) = people();
let test = init_wormhole_state(scenario(), admin);
next_tx(&mut test, admin);{
let state = take_shared<State>(&test);
let first_index = worm_state::get_current_guardian_set_index(&state);
let guardian_set = worm_state::get_guardian_set(&state, first_index);
// make sure guardian set is active
assert!(worm_state::guardian_set_is_active(&state, &guardian_set, ctx(&mut test)), 0);
// do an upgrade
guardian_set_upgrade::do_upgrade_test(
&mut state,
u32::from_u64(1),
vector[create_guardian(x"71aa1be1d36cafe3867910f99c09e347899c19c3")], // new guardian set
ctx(&mut test),
);
// make sure old guardian set is still active
guardian_set = worm_state::get_guardian_set(&state, first_index);
assert!(worm_state::guardian_set_is_active(&state, &guardian_set, ctx(&mut test)), 0);
// fast forward time beyond expiration
// increment by 3 epochs
increment_epoch_number(ctx(&mut test));
increment_epoch_number(ctx(&mut test));
increment_epoch_number(ctx(&mut test));
// make sure old guardian set is no longer active
assert!(!worm_state::guardian_set_is_active(&state, &guardian_set, ctx(&mut test)), 0);
return_shared<State>(state);
};
test_scenario::end(test);
}
}