[solana/cosmwasm/near] Rust tests refactor (#1238)

* Try

* Near

* revert

* Try to add CI

* Cleanup

* Cleanup

* Fmt

* cleanup

* Fix CI

* Cleanup

* Cleanup

* Cleanup rust toolchains

* Pin to tag

* Rename to test-utils

* Add deps

* Checkpoint

* Checkpoint

* Checkpoint

* Fix wormhole stub

* Checkpoint

* Start debugging

* Green

* More green

* Cleanup

* More cleanup

* Cleanup

* Factor create_dummy_price_feed_message

* Format

* Cleanup imports

* Cleanup

* Near cleanup:

* Format

* Refactor constants

* cleanup

* More refactor

* Cleanup more magic numbers

* Remove magic numbers

* Cleanup

* Format

* Remove magic numnber
This commit is contained in:
guibescos 2024-01-25 18:25:07 +00:00 committed by GitHub
parent 82cd11cc77
commit 9697fad077
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 731 additions and 817 deletions

View File

@ -10,6 +10,9 @@ edition = "2021"
crate-type = ["lib"] crate-type = ["lib"]
name = "pythnet_sdk" name = "pythnet_sdk"
[features]
test-utils = ["dep:wormhole-sdk", "dep:serde_wormhole"]
[dependencies] [dependencies]
bincode = "1.3.1" bincode = "1.3.1"
borsh = "0.10.3" borsh = "0.10.3"
@ -23,6 +26,12 @@ quickcheck = { version = "1", optional = true}
sha3 = "0.10.4" sha3 = "0.10.4"
slow_primes = "0.1.14" slow_primes = "0.1.14"
thiserror = "1.0.40" thiserror = "1.0.40"
serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", optional = true, tag="v2.23.37"}
wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", optional = true, tag="v2.23.37"}
[patch.crates-io]
serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", tag="v2.23.37"}
[dev-dependencies] [dev-dependencies]
base64 = "0.21.0" base64 = "0.21.0"

View File

@ -5,6 +5,9 @@ pub mod messages;
pub mod wire; pub mod wire;
pub mod wormhole; pub mod wormhole;
#[cfg(feature = "test-utils")]
pub mod test_utils;
pub(crate) type Pubkey = [u8; 32]; pub(crate) type Pubkey = [u8; 32];
/// Official Message Buffer Program Id /// Official Message Buffer Program Id

View File

@ -0,0 +1,166 @@
use {
crate::{
accumulators::{
merkle::MerkleTree,
Accumulator,
},
hashers::keccak256_160::Keccak160,
messages::{
Message,
PriceFeedMessage,
},
wire::{
to_vec,
v1::{
AccumulatorUpdateData,
MerklePriceUpdate,
Proof,
WormholeMerkleRoot,
WormholeMessage,
WormholePayload,
},
PrefixedVec,
},
},
byteorder::BigEndian,
serde_wormhole::RawMessage,
wormhole_sdk::{
Address,
Chain,
Vaa,
},
};
pub struct DataSource {
pub address: Address,
pub chain: Chain,
}
pub const DEFAULT_DATA_SOURCE: DataSource = DataSource {
address: Address([1u8; 32]),
chain: Chain::Solana,
};
pub const DEFAULT_GOVERNANCE_SOURCE: DataSource = DataSource {
address: Address([2u8; 32]),
chain: Chain::Ethereum,
};
pub const WRONG_SOURCE: DataSource = DataSource {
address: Address([3u8; 32]),
chain: Chain::Bsc,
};
pub const SECONDARY_DATA_SOURCE: DataSource = DataSource {
address: Address([4u8; 32]),
chain: Chain::Polygon,
};
pub const SECONDARY_GOVERNANCE_SOURCE: DataSource = DataSource {
address: Address([5u8; 32]),
chain: Chain::Avalanche,
};
pub const DEFAULT_CHAIN_ID: Chain = Chain::Oasis;
pub const WRONG_CHAIN_ID: Chain = Chain::Algorand;
pub const DEFAULT_VALID_TIME_PERIOD: u64 = 180;
const DEFAULT_SEQUENCE: u64 = 2;
pub fn create_dummy_price_feed_message(value: i64) -> Message {
let mut dummy_id = [0; 32];
dummy_id[0] = value as u8;
let msg = PriceFeedMessage {
feed_id: dummy_id,
price: value,
conf: value as u64,
exponent: value as i32,
publish_time: value,
prev_publish_time: value,
ema_price: value,
ema_conf: value as u64,
};
Message::PriceFeedMessage(msg)
}
pub fn create_accumulator_message(
all_feeds: &[Message],
updates: &[Message],
corrupt_wormhole_message: bool,
) -> Vec<u8> {
let all_feeds_bytes: Vec<_> = all_feeds
.iter()
.map(|f| to_vec::<_, BigEndian>(f).unwrap())
.collect();
let all_feeds_bytes_refs: Vec<_> = all_feeds_bytes.iter().map(|f| f.as_ref()).collect();
let tree = MerkleTree::<Keccak160>::new(all_feeds_bytes_refs.as_slice()).unwrap();
let mut price_updates: Vec<MerklePriceUpdate> = vec![];
for update in updates {
let proof = tree
.prove(&to_vec::<_, BigEndian>(update).unwrap())
.unwrap();
price_updates.push(MerklePriceUpdate {
message: PrefixedVec::from(to_vec::<_, BigEndian>(update).unwrap()),
proof,
});
}
create_accumulator_message_from_updates(
price_updates,
tree,
corrupt_wormhole_message,
DEFAULT_DATA_SOURCE.address,
DEFAULT_DATA_SOURCE.chain,
)
}
pub fn create_accumulator_message_from_updates(
price_updates: Vec<MerklePriceUpdate>,
tree: MerkleTree<Keccak160>,
corrupt_wormhole_message: bool,
emitter_address: Address,
emitter_chain: Chain,
) -> Vec<u8> {
let mut root_hash = [0u8; 20];
root_hash.copy_from_slice(&to_vec::<_, BigEndian>(&tree.root).unwrap()[..20]);
let wormhole_message = WormholeMessage::new(WormholePayload::Merkle(WormholeMerkleRoot {
slot: 0,
ring_size: 0,
root: root_hash,
}));
let mut vaa_payload = to_vec::<_, BigEndian>(&wormhole_message).unwrap();
if corrupt_wormhole_message {
vaa_payload[0] = 0;
}
let vaa = create_vaa_from_payload(
&vaa_payload,
emitter_address,
emitter_chain,
DEFAULT_SEQUENCE,
);
let accumulator_update_data = AccumulatorUpdateData::new(Proof::WormholeMerkle {
vaa: PrefixedVec::from(serde_wormhole::to_vec(&vaa).unwrap()),
updates: price_updates,
});
to_vec::<_, BigEndian>(&accumulator_update_data).unwrap()
}
pub fn create_vaa_from_payload(
payload: &[u8],
emitter_address: Address,
emitter_chain: Chain,
sequence: u64,
) -> Vaa<Box<RawMessage>> {
let vaa: Vaa<Box<RawMessage>> = Vaa {
emitter_chain: emitter_chain,
emitter_address: emitter_address,
sequence,
payload: <Box<RawMessage>>::from(payload.to_vec()),
..Default::default()
};
vaa
}

View File

@ -213,6 +213,17 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "bstr"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.12.0" version = "3.12.0"
@ -1483,10 +1494,12 @@ dependencies = [
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"serde_repr", "serde_repr",
"serde_wormhole",
"sha3 0.9.1", "sha3 0.9.1",
"terraswap", "terraswap",
"thiserror", "thiserror",
"wormhole-cosmwasm", "wormhole-cosmwasm",
"wormhole-sdk",
] ]
[[package]] [[package]]
@ -1546,9 +1559,11 @@ dependencies = [
"hex", "hex",
"rustc_version", "rustc_version",
"serde", "serde",
"serde_wormhole",
"sha3 0.10.8", "sha3 0.10.8",
"slow_primes", "slow_primes",
"thiserror", "thiserror",
"wormhole-sdk",
] ]
[[package]] [[package]]
@ -1617,6 +1632,12 @@ dependencies = [
"smallvec", "smallvec",
] ]
[[package]]
name = "regex-automata"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9"
[[package]] [[package]]
name = "region" name = "region"
version = "3.0.0" version = "3.0.0"
@ -1857,6 +1878,18 @@ dependencies = [
"syn 2.0.15", "syn 2.0.15",
] ]
[[package]]
name = "serde_wormhole"
version = "0.1.0"
source = "git+https://github.com/wormhole-foundation/wormhole?tag=v2.23.37#846c2e9c9dce18a48745e79ba2ee7eaa5acaf1f4"
dependencies = [
"base64",
"itoa",
"serde",
"serde_bytes",
"thiserror",
]
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.9.9" version = "0.9.9"
@ -2661,6 +2694,20 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "wormhole-sdk"
version = "0.1.0"
source = "git+https://github.com/wormhole-foundation/wormhole?tag=v2.23.37#846c2e9c9dce18a48745e79ba2ee7eaa5acaf1f4"
dependencies = [
"anyhow",
"bstr",
"schemars",
"serde",
"serde_wormhole",
"sha3 0.10.8",
"thiserror",
]
[[package]] [[package]]
name = "zeroize" name = "zeroize"
version = "1.6.0" version = "1.6.0"

View File

@ -14,3 +14,6 @@ codegen-units = 1
panic = 'abort' panic = 'abort'
incremental = false incremental = false
overflow-checks = true overflow-checks = true
[patch.crates-io]
serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", tag="v2.23.37"}

View File

@ -45,3 +45,6 @@ wormhole-cosmwasm = {git = "https://github.com/wormhole-foundation/wormhole", t
[dev-dependencies] [dev-dependencies]
cosmwasm-vm = { version = "1.0.0", default-features = false } cosmwasm-vm = { version = "1.0.0", default-features = false }
serde_json = "1.0" serde_json = "1.0"
pythnet-sdk = { path = "../../../../pythnet/pythnet_sdk", features = ["test-utils"] }
serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", tag="v2.23.37"}
wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", tag="v2.23.37"}

View File

@ -835,31 +835,44 @@ mod test {
PriceFeedMessage, PriceFeedMessage,
TwapMessage, TwapMessage,
}, },
test_utils::{
create_accumulator_message,
create_accumulator_message_from_updates,
create_dummy_price_feed_message,
create_vaa_from_payload,
DEFAULT_CHAIN_ID,
DEFAULT_DATA_SOURCE,
DEFAULT_GOVERNANCE_SOURCE,
DEFAULT_VALID_TIME_PERIOD,
SECONDARY_GOVERNANCE_SOURCE,
WRONG_CHAIN_ID,
WRONG_SOURCE,
},
wire::{ wire::{
to_vec, to_vec,
v1::{ v1::MerklePriceUpdate,
MerklePriceUpdate,
WormholeMerkleRoot,
},
PrefixedVec, PrefixedVec,
}, },
}, },
serde_wormhole::RawMessage,
std::time::Duration, std::time::Duration,
wormhole_sdk::{
Address,
Chain,
Vaa,
},
}; };
/// Default valid time period for testing purposes. /// Default valid time period for testing purposes.
const VALID_TIME_PERIOD: Duration = Duration::from_secs(3 * 60);
const WORMHOLE_ADDR: &str = "Wormhole"; const WORMHOLE_ADDR: &str = "Wormhole";
const EMITTER_CHAIN: u16 = 3;
fn default_emitter_addr() -> Vec<u8> {
vec![0, 1, 80]
}
fn default_config_info() -> ConfigInfo { fn default_config_info() -> ConfigInfo {
ConfigInfo { ConfigInfo {
wormhole_contract: Addr::unchecked(WORMHOLE_ADDR), wormhole_contract: Addr::unchecked(WORMHOLE_ADDR),
data_sources: create_data_sources(default_emitter_addr(), EMITTER_CHAIN), data_sources: create_data_sources(
DEFAULT_DATA_SOURCE.address.0.to_vec(),
DEFAULT_DATA_SOURCE.chain.into(),
),
..create_zero_config_info() ..create_zero_config_info()
} }
} }
@ -871,25 +884,22 @@ mod test {
let mut config = config(dependencies.as_mut().storage); let mut config = config(dependencies.as_mut().storage);
config config
.save(&ConfigInfo { .save(&ConfigInfo {
valid_time_period: VALID_TIME_PERIOD, valid_time_period: Duration::from_secs(DEFAULT_VALID_TIME_PERIOD),
..create_zero_config_info() ..create_zero_config_info()
}) })
.unwrap(); .unwrap();
(dependencies, mock_env()) (dependencies, mock_env())
} }
/// Mock handler for wormhole queries.
/// Warning: the interface for the `VerifyVAA` action is slightly different than the real wormhole contract.
/// In the mock, you pass in a binary-encoded `ParsedVAA`, and that exact vaa will be returned by wormhole.
/// The real contract uses a different binary VAA format (see `ParsedVAA::deserialize`) which includes
/// the guardian signatures.
fn handle_wasm_query(wasm_query: &WasmQuery) -> QuerierResult { fn handle_wasm_query(wasm_query: &WasmQuery) -> QuerierResult {
match wasm_query { match wasm_query {
WasmQuery::Smart { contract_addr, msg } if *contract_addr == WORMHOLE_ADDR => { WasmQuery::Smart { contract_addr, msg } if *contract_addr == WORMHOLE_ADDR => {
let query_msg = from_binary::<WormholeQueryMsg>(msg); let query_msg = from_binary::<WormholeQueryMsg>(msg);
match query_msg { match query_msg {
Ok(WormholeQueryMsg::VerifyVAA { vaa, .. }) => { Ok(WormholeQueryMsg::VerifyVAA { vaa, .. }) => {
SystemResult::Ok(ContractResult::Ok(vaa)) SystemResult::Ok(ContractResult::Ok(
to_binary(&ParsedVAA::deserialize(&vaa).unwrap()).unwrap(),
))
} }
Err(_e) => SystemResult::Err(SystemError::InvalidRequest { Err(_e) => SystemResult::Err(SystemError::InvalidRequest {
error: "Invalid message".into(), error: "Invalid message".into(),
@ -919,45 +929,30 @@ mod test {
} }
} }
fn create_zero_vaa() -> ParsedVAA {
ParsedVAA {
version: 0,
guardian_set_index: 0,
timestamp: 0,
nonce: 0,
len_signers: 0,
emitter_chain: 0,
emitter_address: vec![],
sequence: 0,
consistency_level: 0,
payload: vec![],
hash: vec![],
}
}
fn create_batch_price_update_msg( fn create_batch_price_update_msg(
emitter_address: &[u8], emitter_address: Address,
emitter_chain: u16, emitter_chain: Chain,
attestations: Vec<PriceAttestation>, attestations: Vec<PriceAttestation>,
) -> Binary { ) -> Binary {
let batch_attestation = BatchPriceAttestation { let batch_attestation = BatchPriceAttestation {
price_attestations: attestations, price_attestations: attestations,
}; };
let mut vaa = create_zero_vaa(); let vaa = create_vaa_from_payload(
vaa.emitter_address = emitter_address.to_vec(); &batch_attestation.serialize().unwrap(),
vaa.emitter_chain = emitter_chain; emitter_address,
vaa.payload = batch_attestation.serialize().unwrap(); emitter_chain,
0,
to_binary(&vaa).unwrap() );
serde_wormhole::to_vec(&vaa).unwrap().into()
} }
fn create_batch_price_update_msg_from_attestations( fn create_batch_price_update_msg_from_attestations(
attestations: Vec<PriceAttestation>, attestations: Vec<PriceAttestation>,
) -> Binary { ) -> Binary {
create_batch_price_update_msg( create_batch_price_update_msg(
default_emitter_addr().as_slice(), DEFAULT_DATA_SOURCE.address,
EMITTER_CHAIN, DEFAULT_DATA_SOURCE.chain,
attestations, attestations,
) )
} }
@ -1012,8 +1007,8 @@ mod test {
fn apply_price_update( fn apply_price_update(
config_info: &ConfigInfo, config_info: &ConfigInfo,
emitter_address: &[u8], emitter_address: Address,
emitter_chain: u16, emitter_chain: Chain,
attestations: Vec<PriceAttestation>, attestations: Vec<PriceAttestation>,
) -> StdResult<(usize, Vec<PriceFeed>)> { ) -> StdResult<(usize, Vec<PriceFeed>)> {
let (mut deps, env) = setup_test(); let (mut deps, env) = setup_test();
@ -1160,20 +1155,16 @@ mod test {
let feed1 = create_dummy_price_feed_message(100); let feed1 = create_dummy_price_feed_message(100);
let feed2 = create_dummy_price_feed_message(200); let feed2 = create_dummy_price_feed_message(200);
let feed3 = create_dummy_price_feed_message(300); let feed3 = create_dummy_price_feed_message(300);
let data = [create_accumulator_message( let data = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false);
&[feed1, feed2, feed3], check_sufficient_fee(&deps.as_ref(), &[data.into()])
&[feed1],
false,
)];
check_sufficient_fee(&deps.as_ref(), &data)
} }
#[test] #[test]
fn test_parse_batch_attestation_empty_array() { fn test_parse_batch_attestation_empty_array() {
let (num_attestations, new_attestations) = apply_price_update( let (num_attestations, new_attestations) = apply_price_update(
&default_config_info(), &default_config_info(),
default_emitter_addr().as_slice(), DEFAULT_DATA_SOURCE.address,
EMITTER_CHAIN, DEFAULT_DATA_SOURCE.chain,
vec![], vec![],
) )
.unwrap(); .unwrap();
@ -1182,85 +1173,6 @@ mod test {
assert_eq!(new_attestations.len(), 0); assert_eq!(new_attestations.len(), 0);
} }
fn create_dummy_price_feed_message(value: i64) -> Message {
let mut dummy_id = [0; 32];
dummy_id[0] = value as u8;
let msg = PriceFeedMessage {
feed_id: dummy_id,
price: value,
conf: value as u64,
exponent: value as i32,
publish_time: value,
prev_publish_time: value,
ema_price: value,
ema_conf: value as u64,
};
Message::PriceFeedMessage(msg)
}
fn create_accumulator_message_from_updates(
price_updates: Vec<MerklePriceUpdate>,
tree: MerkleTree<Keccak160>,
corrupt_wormhole_message: bool,
emitter_address: Vec<u8>,
emitter_chain: u16,
) -> Binary {
let mut root_hash = [0u8; 20];
root_hash.copy_from_slice(&to_vec::<_, BigEndian>(&tree.root).unwrap()[..20]);
let wormhole_message = WormholeMessage::new(WormholePayload::Merkle(WormholeMerkleRoot {
slot: 0,
ring_size: 0,
root: root_hash,
}));
let mut vaa = create_zero_vaa();
vaa.emitter_address = emitter_address;
vaa.emitter_chain = emitter_chain;
vaa.payload = to_vec::<_, BigEndian>(&wormhole_message).unwrap();
if corrupt_wormhole_message {
vaa.payload[0] = 0;
}
let vaa_binary = to_binary(&vaa).unwrap();
let accumulator_update_data = AccumulatorUpdateData::new(Proof::WormholeMerkle {
vaa: PrefixedVec::from(vaa_binary.to_vec()),
updates: price_updates,
});
Binary::from(to_vec::<_, BigEndian>(&accumulator_update_data).unwrap())
}
fn create_accumulator_message(
all_feeds: &[Message],
updates: &[Message],
corrupt_wormhole_message: bool,
) -> Binary {
let all_feeds_bytes: Vec<_> = all_feeds
.iter()
.map(|f| to_vec::<_, BigEndian>(f).unwrap())
.collect();
let all_feeds_bytes_refs: Vec<_> = all_feeds_bytes.iter().map(|f| f.as_ref()).collect();
let tree = MerkleTree::<Keccak160>::new(all_feeds_bytes_refs.as_slice()).unwrap();
let mut price_updates: Vec<MerklePriceUpdate> = vec![];
for update in updates {
let proof = tree
.prove(&to_vec::<_, BigEndian>(update).unwrap())
.unwrap();
price_updates.push(MerklePriceUpdate {
message: PrefixedVec::from(to_vec::<_, BigEndian>(update).unwrap()),
proof,
});
}
create_accumulator_message_from_updates(
price_updates,
tree,
corrupt_wormhole_message,
default_emitter_addr(),
EMITTER_CHAIN,
)
}
fn check_price_match(deps: &OwnedDeps<MockStorage, MockApi, MockQuerier>, msg: &Message) { fn check_price_match(deps: &OwnedDeps<MockStorage, MockApi, MockQuerier>, msg: &Message) {
match msg { match msg {
Message::PriceFeedMessage(feed_msg) => { Message::PriceFeedMessage(feed_msg) => {
@ -1283,7 +1195,7 @@ mod test {
}; };
} }
fn test_accumulator_wrong_source(emitter_address: Vec<u8>, emitter_chain: u16) { fn test_accumulator_wrong_source(emitter_address: Address, emitter_chain: Chain) {
let (mut deps, env) = setup_test(); let (mut deps, env) = setup_test();
config(&mut deps.storage) config(&mut deps.storage)
.save(&default_config_info()) .save(&default_config_info())
@ -1306,20 +1218,19 @@ mod test {
emitter_chain, emitter_chain,
); );
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_err()); assert!(result.is_err());
assert_eq!(result, Err(PythContractError::InvalidUpdateEmitter.into())); assert_eq!(result, Err(PythContractError::InvalidUpdateEmitter.into()));
} }
#[test] #[test]
fn test_accumulator_verify_vaa_sender_fail_wrong_emitter_address() { fn test_accumulator_verify_vaa_sender_fail_wrong_emitter_address() {
let emitter_address = [17, 23, 14]; test_accumulator_wrong_source(WRONG_SOURCE.address, DEFAULT_DATA_SOURCE.chain);
test_accumulator_wrong_source(emitter_address.to_vec(), EMITTER_CHAIN);
} }
#[test] #[test]
fn test_accumulator_verify_vaa_sender_fail_wrong_emitter_chain() { fn test_accumulator_verify_vaa_sender_fail_wrong_emitter_chain() {
test_accumulator_wrong_source(default_emitter_addr(), EMITTER_CHAIN + 1); test_accumulator_wrong_source(DEFAULT_DATA_SOURCE.address, WRONG_SOURCE.chain);
} }
#[test] #[test]
@ -1336,23 +1247,32 @@ mod test {
let feed3 = create_dummy_price_feed_message(300); let feed3 = create_dummy_price_feed_message(300);
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false); let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false);
assert_eq!(get_update_fee_amount(&deps.as_ref(), &[msg]).unwrap(), 200); assert_eq!(
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
200
);
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false); let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false);
assert_eq!(get_update_fee_amount(&deps.as_ref(), &[msg]).unwrap(), 100); assert_eq!(
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
100
);
let msg = create_accumulator_message( let msg = create_accumulator_message(
&[feed1, feed2, feed3], &[feed1, feed2, feed3],
&[feed1, feed2, feed3, feed1, feed3], &[feed1, feed2, feed3, feed1, feed3],
false, false,
); );
assert_eq!(get_update_fee_amount(&deps.as_ref(), &[msg]).unwrap(), 500); assert_eq!(
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
500
);
let batch_msg = let batch_msg =
create_batch_price_update_msg_from_attestations(vec![PriceAttestation::default()]); create_batch_price_update_msg_from_attestations(vec![PriceAttestation::default()]);
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false); let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false);
assert_eq!( assert_eq!(
get_update_fee_amount(&deps.as_ref(), &[msg, batch_msg]).unwrap(), get_update_fee_amount(&deps.as_ref(), &[msg.into(), batch_msg]).unwrap(),
400 400
); );
} }
@ -1369,7 +1289,7 @@ mod test {
let feed2 = create_dummy_price_feed_message(200); let feed2 = create_dummy_price_feed_message(200);
let msg = create_accumulator_message(&[feed1, feed2], &[feed1], false); let msg = create_accumulator_message(&[feed1, feed2], &[feed1], false);
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_ok()); assert!(result.is_ok());
check_price_match(&deps, &feed1); check_price_match(&deps, &feed1);
} }
@ -1386,7 +1306,7 @@ mod test {
} }
let msg = create_accumulator_message(&all_feeds, &all_feeds[100..110], false); let msg = create_accumulator_message(&all_feeds, &all_feeds[100..110], false);
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_ok()); assert!(result.is_ok());
for i in 100..110 { for i in 100..110 {
check_price_match(&deps, &all_feeds[i]); check_price_match(&deps, &all_feeds[i]);
@ -1421,7 +1341,7 @@ mod test {
let msg2 = let msg2 =
create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false); create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false);
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg, msg2]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into(), msg2.into()]);
assert!(result.is_ok()); assert!(result.is_ok());
check_price_match(&deps, &feed1); check_price_match(&deps, &feed1);
@ -1442,7 +1362,7 @@ mod test {
as_mut_price_feed(&mut feed2).price *= 2; as_mut_price_feed(&mut feed2).price *= 2;
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false); let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false);
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_ok()); assert!(result.is_ok());
check_price_match(&deps, &feed1); check_price_match(&deps, &feed1);
@ -1464,7 +1384,7 @@ mod test {
let msg2 = create_accumulator_message(&[feed1, feed2, feed3], &[feed2, feed3], false); let msg2 = create_accumulator_message(&[feed1, feed2, feed3], &[feed2, feed3], false);
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg, msg2]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into(), msg2.into()]);
assert!(result.is_ok()); assert!(result.is_ok());
check_price_match(&deps, &feed1); check_price_match(&deps, &feed1);
@ -1480,9 +1400,9 @@ mod test {
let feed1 = create_dummy_price_feed_message(100); let feed1 = create_dummy_price_feed_message(100);
let mut msg = create_accumulator_message(&[feed1], &[feed1], false); let mut msg = create_accumulator_message(&[feed1], &[feed1], false);
msg.0[4] = 3; // major version msg[4] = 3; // major version
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
result.unwrap_err(), result.unwrap_err(),
@ -1500,7 +1420,7 @@ mod test {
let feed1 = create_dummy_price_feed_message(100); let feed1 = create_dummy_price_feed_message(100);
let msg = create_accumulator_message(&[feed1], &[feed1], true); let msg = create_accumulator_message(&[feed1], &[feed1], true);
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
result.unwrap_err(), result.unwrap_err(),
@ -1528,7 +1448,7 @@ mod test {
}); });
let msg = create_accumulator_message(&[feed1], &[feed1], false); let msg = create_accumulator_message(&[feed1], &[feed1], false);
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
result.unwrap_err(), result.unwrap_err(),
@ -1560,11 +1480,11 @@ mod test {
price_updates, price_updates,
tree, tree,
false, false,
default_emitter_addr(), DEFAULT_DATA_SOURCE.address,
EMITTER_CHAIN, DEFAULT_DATA_SOURCE.chain,
); );
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
result.unwrap_err(), result.unwrap_err(),
@ -1594,11 +1514,11 @@ mod test {
price_updates, price_updates,
tree, tree,
false, false,
default_emitter_addr(), DEFAULT_DATA_SOURCE.address,
EMITTER_CHAIN, DEFAULT_DATA_SOURCE.chain,
); );
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = update_price_feeds(deps.as_mut(), env, info, &[msg]); let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
result.unwrap_err(), result.unwrap_err(),
@ -1779,8 +1699,8 @@ mod test {
fn test_verify_vaa_sender_ok() { fn test_verify_vaa_sender_ok() {
let result = apply_price_update( let result = apply_price_update(
&default_config_info(), &default_config_info(),
default_emitter_addr().as_slice(), DEFAULT_DATA_SOURCE.address,
EMITTER_CHAIN, DEFAULT_DATA_SOURCE.chain,
vec![PriceAttestation::default()], vec![PriceAttestation::default()],
); );
assert!(result.is_ok()); assert!(result.is_ok());
@ -1788,11 +1708,10 @@ mod test {
#[test] #[test]
fn test_verify_vaa_sender_fail_wrong_emitter_address() { fn test_verify_vaa_sender_fail_wrong_emitter_address() {
let emitter_address = [17, 23, 14];
let result = apply_price_update( let result = apply_price_update(
&default_config_info(), &default_config_info(),
emitter_address.as_slice(), WRONG_SOURCE.address,
EMITTER_CHAIN, DEFAULT_DATA_SOURCE.chain,
vec![PriceAttestation::default()], vec![PriceAttestation::default()],
); );
assert_eq!(result, Err(PythContractError::InvalidUpdateEmitter.into())); assert_eq!(result, Err(PythContractError::InvalidUpdateEmitter.into()));
@ -1802,8 +1721,8 @@ mod test {
fn test_verify_vaa_sender_fail_wrong_emitter_chain() { fn test_verify_vaa_sender_fail_wrong_emitter_chain() {
let result = apply_price_update( let result = apply_price_update(
&default_config_info(), &default_config_info(),
default_emitter_addr().as_slice(), DEFAULT_DATA_SOURCE.address,
EMITTER_CHAIN + 1, WRONG_SOURCE.chain,
vec![PriceAttestation::default()], vec![PriceAttestation::default()],
); );
assert_eq!(result, Err(PythContractError::InvalidUpdateEmitter.into())); assert_eq!(result, Err(PythContractError::InvalidUpdateEmitter.into()));
@ -2091,14 +2010,19 @@ mod test {
/// against it. Returns the response of the governance instruction along with the resulting config. /// against it. Returns the response of the governance instruction along with the resulting config.
fn apply_governance_vaa( fn apply_governance_vaa(
initial_config: &ConfigInfo, initial_config: &ConfigInfo,
vaa: &ParsedVAA, vaa: &Vaa<Box<RawMessage>>,
) -> StdResult<(Response<MsgWrapper>, ConfigInfo)> { ) -> StdResult<(Response<MsgWrapper>, ConfigInfo)> {
let (mut deps, env) = setup_test(); let (mut deps, env) = setup_test();
config(&mut deps.storage).save(initial_config).unwrap(); config(&mut deps.storage).save(initial_config).unwrap();
let info = mock_info("123", &[]); let info = mock_info("123", &[]);
let result = execute_governance_instruction(deps.as_mut(), env, info, &to_binary(&vaa)?); let result = execute_governance_instruction(
deps.as_mut(),
env,
info,
&serde_wormhole::to_vec(vaa).unwrap().into(),
);
result.and_then(|response| config_read(&deps.storage).load().map(|c| (response, c))) result.and_then(|response| config_read(&deps.storage).load().map(|c| (response, c)))
} }
@ -2107,23 +2031,22 @@ mod test {
ConfigInfo { ConfigInfo {
wormhole_contract: Addr::unchecked(WORMHOLE_ADDR), wormhole_contract: Addr::unchecked(WORMHOLE_ADDR),
governance_source: PythDataSource { governance_source: PythDataSource {
emitter: Binary(vec![1u8, 2u8]), emitter: Binary(DEFAULT_GOVERNANCE_SOURCE.address.0.to_vec()),
chain_id: 3, chain_id: DEFAULT_GOVERNANCE_SOURCE.chain.into(),
}, },
governance_sequence_number: 4, governance_sequence_number: 4,
chain_id: 5, chain_id: DEFAULT_CHAIN_ID.into(),
..create_zero_config_info() ..create_zero_config_info()
} }
} }
fn governance_vaa(instruction: &GovernanceInstruction) -> ParsedVAA { fn governance_vaa(instruction: &GovernanceInstruction) -> Vaa<Box<RawMessage>> {
let mut vaa = create_zero_vaa(); create_vaa_from_payload(
vaa.emitter_address = vec![1u8, 2u8]; &instruction.serialize().unwrap(),
vaa.emitter_chain = 3; DEFAULT_GOVERNANCE_SOURCE.address,
vaa.sequence = 7; DEFAULT_GOVERNANCE_SOURCE.chain,
vaa.payload = instruction.serialize().unwrap(); 7,
)
vaa
} }
#[test] #[test]
@ -2132,7 +2055,7 @@ mod test {
let test_instruction = GovernanceInstruction { let test_instruction = GovernanceInstruction {
module: Target, module: Target,
target_chain_id: 5, target_chain_id: DEFAULT_CHAIN_ID.into(),
action: SetFee { val: 6, expo: 0 }, action: SetFee { val: 6, expo: 0 },
}; };
let test_vaa = governance_vaa(&test_instruction); let test_vaa = governance_vaa(&test_instruction);
@ -2142,12 +2065,12 @@ mod test {
// Wrong emitter address // Wrong emitter address
let mut vaa_copy = test_vaa.clone(); let mut vaa_copy = test_vaa.clone();
vaa_copy.emitter_address = vec![2u8, 3u8]; vaa_copy.emitter_address = WRONG_SOURCE.address;
assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err()); assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err());
// wrong source chain // wrong source chain
let mut vaa_copy = test_vaa.clone(); let mut vaa_copy = test_vaa.clone();
vaa_copy.emitter_chain = 4; vaa_copy.emitter_chain = WRONG_SOURCE.chain;
assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err()); assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err());
// sequence number too low // sequence number too low
@ -2157,53 +2080,50 @@ mod test {
// wrong magic number // wrong magic number
let mut vaa_copy = test_vaa.clone(); let mut vaa_copy = test_vaa.clone();
vaa_copy.payload[0] = 0; let mut new_payload = vaa_copy.payload.to_vec();
new_payload[0] = 0;
vaa_copy.payload = <Box<RawMessage>>::from(new_payload);
assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err()); assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err());
// wrong target chain // wrong target chain
let mut instruction_copy = test_instruction.clone(); let mut instruction_copy = test_instruction.clone();
instruction_copy.target_chain_id = 6; instruction_copy.target_chain_id = WRONG_CHAIN_ID.into();
let mut vaa_copy = test_vaa.clone(); let mut vaa_copy = test_vaa.clone();
vaa_copy.payload = instruction_copy.serialize().unwrap(); vaa_copy.payload = <Box<RawMessage>>::from(instruction_copy.serialize().unwrap());
assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err()); assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err());
// target chain == 0 is allowed // target chain == 0 is allowed
let mut instruction_copy = test_instruction.clone(); let mut instruction_copy = test_instruction.clone();
instruction_copy.target_chain_id = 0; instruction_copy.target_chain_id = 0;
let mut vaa_copy = test_vaa.clone(); let mut vaa_copy = test_vaa.clone();
vaa_copy.payload = instruction_copy.serialize().unwrap(); vaa_copy.payload = <Box<RawMessage>>::from(instruction_copy.serialize().unwrap());
assert!(apply_governance_vaa(&test_config, &vaa_copy).is_ok()); assert!(apply_governance_vaa(&test_config, &vaa_copy).is_ok());
// wrong module // wrong module
let mut instruction_copy = test_instruction.clone(); let mut instruction_copy = test_instruction;
instruction_copy.module = Executor; instruction_copy.module = Executor;
let mut vaa_copy = test_vaa; let mut vaa_copy = test_vaa;
vaa_copy.payload = instruction_copy.serialize().unwrap(); vaa_copy.payload = <Box<RawMessage>>::from(instruction_copy.serialize().unwrap());
assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err()); assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err());
// invalid action index // invalid action index
let _instruction_copy = test_instruction; let mut new_payload = vaa_copy.payload.to_vec();
vaa_copy.payload[9] = 100; new_payload[9] = 100;
vaa_copy.payload = <Box<RawMessage>>::from(new_payload);
assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err()); assert!(apply_governance_vaa(&test_config, &vaa_copy).is_err());
} }
#[test] #[test]
fn test_authorize_governance_transfer_success() { fn test_authorize_governance_transfer_success() {
let source_2 = PythDataSource { let source_2 = PythDataSource {
emitter: Binary::from([2u8; 32]), emitter: Binary::from(SECONDARY_GOVERNANCE_SOURCE.address.0),
chain_id: 4, chain_id: SECONDARY_GOVERNANCE_SOURCE.chain.into(),
}; };
let test_config = governance_test_config(); let test_config = governance_test_config();
let test_instruction = GovernanceInstruction {
module: Target, let claim_vaa = create_vaa_from_payload(
target_chain_id: test_config.chain_id, &GovernanceInstruction {
action: AuthorizeGovernanceDataSourceTransfer {
claim_vaa: to_binary(&ParsedVAA {
emitter_address: source_2.emitter.to_vec(),
emitter_chain: source_2.chain_id,
sequence: 12,
payload: GovernanceInstruction {
module: Target, module: Target,
target_chain_id: test_config.chain_id, target_chain_id: test_config.chain_id,
action: RequestGovernanceDataSourceTransfer { action: RequestGovernanceDataSourceTransfer {
@ -2212,9 +2132,16 @@ mod test {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
..create_zero_vaa() SECONDARY_GOVERNANCE_SOURCE.address,
}) SECONDARY_GOVERNANCE_SOURCE.chain,
.unwrap(), 12,
);
let test_instruction = GovernanceInstruction {
module: Target,
target_chain_id: test_config.chain_id,
action: AuthorizeGovernanceDataSourceTransfer {
claim_vaa: serde_wormhole::to_vec(&claim_vaa).unwrap().into(),
}, },
}; };
@ -2227,22 +2154,11 @@ mod test {
#[test] #[test]
fn test_authorize_governance_transfer_bad_source_index() { fn test_authorize_governance_transfer_bad_source_index() {
let source_2 = PythDataSource {
emitter: Binary::from([2u8; 32]),
chain_id: 4,
};
let mut test_config = governance_test_config(); let mut test_config = governance_test_config();
test_config.governance_source_index = 10; test_config.governance_source_index = 10;
let test_instruction = GovernanceInstruction {
module: Target, let claim_vaa = create_vaa_from_payload(
target_chain_id: test_config.chain_id, &GovernanceInstruction {
action: AuthorizeGovernanceDataSourceTransfer {
claim_vaa: to_binary(&ParsedVAA {
emitter_address: source_2.emitter.to_vec(),
emitter_chain: source_2.chain_id,
sequence: 12,
payload: GovernanceInstruction {
module: Target, module: Target,
target_chain_id: test_config.chain_id, target_chain_id: test_config.chain_id,
action: RequestGovernanceDataSourceTransfer { action: RequestGovernanceDataSourceTransfer {
@ -2251,9 +2167,16 @@ mod test {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
..create_zero_vaa() SECONDARY_GOVERNANCE_SOURCE.address,
}) SECONDARY_GOVERNANCE_SOURCE.chain,
.unwrap(), 12,
);
let test_instruction = GovernanceInstruction {
module: Target,
target_chain_id: test_config.chain_id,
action: AuthorizeGovernanceDataSourceTransfer {
claim_vaa: serde_wormhole::to_vec(&claim_vaa).unwrap().into(),
}, },
}; };
@ -2266,32 +2189,28 @@ mod test {
#[test] #[test]
fn test_authorize_governance_transfer_bad_target_chain() { fn test_authorize_governance_transfer_bad_target_chain() {
let source_2 = PythDataSource {
emitter: Binary::from([2u8; 32]),
chain_id: 4,
};
let test_config = governance_test_config(); let test_config = governance_test_config();
let test_instruction = GovernanceInstruction {
let claim_vaa = create_vaa_from_payload(
&GovernanceInstruction {
module: Target, module: Target,
target_chain_id: test_config.chain_id, target_chain_id: WRONG_CHAIN_ID.into(),
action: AuthorizeGovernanceDataSourceTransfer {
claim_vaa: to_binary(&ParsedVAA {
emitter_address: source_2.emitter.to_vec(),
emitter_chain: source_2.chain_id,
sequence: 12,
payload: GovernanceInstruction {
module: Target,
target_chain_id: test_config.chain_id + 1,
action: RequestGovernanceDataSourceTransfer { action: RequestGovernanceDataSourceTransfer {
governance_data_source_index: 11, governance_data_source_index: 11,
}, },
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
..create_zero_vaa() SECONDARY_GOVERNANCE_SOURCE.address,
}) SECONDARY_GOVERNANCE_SOURCE.chain,
.unwrap(), 12,
);
let test_instruction = GovernanceInstruction {
module: Target,
target_chain_id: test_config.chain_id,
action: AuthorizeGovernanceDataSourceTransfer {
claim_vaa: serde_wormhole::to_vec(&claim_vaa).unwrap().into(),
}, },
}; };
@ -2354,7 +2273,7 @@ mod test {
let test_instruction = GovernanceInstruction { let test_instruction = GovernanceInstruction {
module: Target, module: Target,
target_chain_id: 5, target_chain_id: DEFAULT_CHAIN_ID.into(),
action: SetFee { val: 6, expo: 1 }, action: SetFee { val: 6, expo: 1 },
}; };
let test_vaa = governance_vaa(&test_instruction); let test_vaa = governance_vaa(&test_instruction);
@ -2366,7 +2285,7 @@ mod test {
let test_instruction = GovernanceInstruction { let test_instruction = GovernanceInstruction {
module: Target, module: Target,
target_chain_id: 5, target_chain_id: DEFAULT_CHAIN_ID.into(),
action: SetFee { val: 6, expo: 0 }, action: SetFee { val: 6, expo: 0 },
}; };
let test_vaa = governance_vaa(&test_instruction); let test_vaa = governance_vaa(&test_instruction);
@ -2384,7 +2303,7 @@ mod test {
let test_instruction = GovernanceInstruction { let test_instruction = GovernanceInstruction {
module: Target, module: Target,
target_chain_id: 5, target_chain_id: DEFAULT_CHAIN_ID.into(),
action: SetValidPeriod { valid_seconds: 20 }, action: SetValidPeriod { valid_seconds: 20 },
}; };
let test_vaa = governance_vaa(&test_instruction); let test_vaa = governance_vaa(&test_instruction);

View File

@ -2239,9 +2239,11 @@ dependencies = [
"hex 0.4.3", "hex 0.4.3",
"rustc_version", "rustc_version",
"serde", "serde",
"serde_wormhole",
"sha3", "sha3",
"slow_primes", "slow_primes",
"thiserror", "thiserror",
"wormhole-sdk",
] ]
[[package]] [[package]]

View File

@ -38,6 +38,7 @@ tokio = { version = "1.23.0", features = ["full"] }
serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", tag="v2.23.37" } serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", tag="v2.23.37" }
workspaces = { version = "0.7.0" } workspaces = { version = "0.7.0" }
wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", tag="v2.23.37" } wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", tag="v2.23.37" }
pythnet-sdk = { path = "../../../pythnet/pythnet_sdk", features = ["test-utils"] }

View File

@ -1,5 +1,4 @@
use { use {
byteorder::BigEndian,
near_sdk::json_types::U128, near_sdk::json_types::U128,
pyth::{ pyth::{
governance::{ governance::{
@ -20,34 +19,17 @@ use {
PriceAttestation, PriceAttestation,
PriceStatus, PriceStatus,
}, },
pythnet_sdk::{ pythnet_sdk::test_utils::{
accumulators::{ create_accumulator_message,
merkle::MerkleTree, create_dummy_price_feed_message,
Accumulator, create_vaa_from_payload,
}, DEFAULT_DATA_SOURCE,
hashers::keccak256_160::Keccak160, DEFAULT_GOVERNANCE_SOURCE,
messages::{ DEFAULT_VALID_TIME_PERIOD,
Message, SECONDARY_DATA_SOURCE,
PriceFeedMessage, SECONDARY_GOVERNANCE_SOURCE,
},
wire::{
to_vec,
v1::{
AccumulatorUpdateData,
MerklePriceUpdate,
Proof,
WormholeMerkleRoot,
WormholeMessage,
WormholePayload,
},
PrefixedVec,
},
}, },
serde_json::json, serde_json::json,
std::io::{
Cursor,
Write,
},
wormhole_sdk::Chain as WormholeChain, wormhole_sdk::Chain as WormholeChain,
}; };
@ -92,10 +74,16 @@ async fn initialize_chain() -> (
.args_json(&json!({ .args_json(&json!({
"wormhole": wormhole.id(), "wormhole": wormhole.id(),
"codehash": codehash, "codehash": codehash,
"initial_source": Source::default(), "initial_source": Source {
"gov_source": Source::default(), emitter: DEFAULT_DATA_SOURCE.address.0,
chain: DEFAULT_DATA_SOURCE.chain.into(),
},
"gov_source": Source {
emitter: DEFAULT_GOVERNANCE_SOURCE.address.0,
chain: DEFAULT_GOVERNANCE_SOURCE.chain.into(),
},
"update_fee": U128::from(1u128), "update_fee": U128::from(1u128),
"stale_threshold": 32, "stale_threshold": DEFAULT_VALID_TIME_PERIOD,
})) }))
.gas(300_000_000_000_000) .gas(300_000_000_000_000)
.transact_async() .transact_async()
@ -112,37 +100,30 @@ async fn test_set_sources() {
let (_, contract, _) = initialize_chain().await; let (_, contract, _) = initialize_chain().await;
// Submit a new Source to the contract, this will trigger a cross-contract call to wormhole // Submit a new Source to the contract, this will trigger a cross-contract call to wormhole
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
sequence: 1,
payload: (),
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).expect("Failed to serialize VAA");
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Any), target: Chain::from(WormholeChain::Any),
module: GovernanceModule::Target, module: GovernanceModule::Target,
action: GovernanceAction::SetDataSources { action: GovernanceAction::SetDataSources {
data_sources: vec![ data_sources: vec![
Source::default(),
Source { Source {
emitter: [1; 32], emitter: DEFAULT_DATA_SOURCE.address.0,
chain: Chain::from(WormholeChain::Solana), chain: DEFAULT_DATA_SOURCE.chain.into(),
},
Source {
emitter: SECONDARY_DATA_SOURCE.address.0,
chain: SECONDARY_DATA_SOURCE.chain.into(),
}, },
], ],
}, },
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.expect("Failed to write Payload"); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 1,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
assert!(contract assert!(contract
.call("execute_governance_instruction") .call("execute_governance_instruction")
@ -164,10 +145,13 @@ async fn test_set_sources() {
serde_json::from_slice::<Vec<Source>>(&contract.view("get_sources").await.unwrap().result) serde_json::from_slice::<Vec<Source>>(&contract.view("get_sources").await.unwrap().result)
.unwrap(), .unwrap(),
&[ &[
Source::default(),
Source { Source {
emitter: [1; 32], emitter: DEFAULT_DATA_SOURCE.address.0,
chain: Chain::from(WormholeChain::Solana), chain: DEFAULT_DATA_SOURCE.chain.into(),
},
Source {
emitter: SECONDARY_DATA_SOURCE.address.0,
chain: SECONDARY_DATA_SOURCE.chain.into(),
}, },
] ]
); );
@ -177,30 +161,9 @@ async fn test_set_sources() {
async fn test_set_governance_source() { async fn test_set_governance_source() {
let (_, contract, _) = initialize_chain().await; let (_, contract, _) = initialize_chain().await;
// Submit a new Source to the contract, this will trigger a cross-contract call to wormhole
let vaa = wormhole_sdk::Vaa {
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
payload: (),
sequence: 2,
..Default::default()
};
let vaa = {
let request_vaa = wormhole_sdk::Vaa {
emitter_chain: wormhole_sdk::Chain::Solana,
emitter_address: wormhole_sdk::Address([1; 32]),
payload: (),
sequence: 1,
..Default::default()
};
// Data Source Upgrades are submitted with an embedded VAA, generate that one here first // Data Source Upgrades are submitted with an embedded VAA, generate that one here first
// before we embed it. // before we embed it.
let request_vaa = { let request_vaa = create_vaa_from_payload(
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &request_vaa).expect("Failed to serialize VAA");
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
@ -210,27 +173,27 @@ async fn test_set_governance_source() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) SECONDARY_GOVERNANCE_SOURCE.address,
.expect("Failed to write Payload"); SECONDARY_GOVERNANCE_SOURCE.chain,
cur.into_inner() 1,
}; );
let mut cur = Cursor::new(Vec::new()); // Submit a new Source to the contract, this will trigger a cross-contract call to wormhole
serde_wormhole::to_writer(&mut cur, &vaa).expect("Failed to serialize VAA"); let vaa = create_vaa_from_payload(
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
action: GovernanceAction::AuthorizeGovernanceDataSourceTransfer { action: GovernanceAction::AuthorizeGovernanceDataSourceTransfer {
claim_vaa: request_vaa, claim_vaa: serde_wormhole::to_vec(&request_vaa).unwrap(),
}, },
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.expect("Failed to write Payload"); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 2,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
assert!(contract assert!(contract
.call("execute_governance_instruction") .call("execute_governance_instruction")
@ -247,37 +210,30 @@ async fn test_set_governance_source() {
.is_empty()); .is_empty());
// An action from the new source should now be accepted. // An action from the new source should now be accepted.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
sequence: 3, // NOTE: Incremented Governance Sequence
emitter_chain: wormhole_sdk::Chain::Solana,
emitter_address: wormhole_sdk::Address([1; 32]),
payload: (),
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).expect("Failed to serialize VAA");
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
action: GovernanceAction::SetDataSources { action: GovernanceAction::SetDataSources {
data_sources: vec![ data_sources: vec![
Source::default(),
Source { Source {
emitter: [2; 32], emitter: DEFAULT_DATA_SOURCE.address.0,
chain: Chain::from(WormholeChain::Solana), chain: DEFAULT_DATA_SOURCE.chain.into(),
},
Source {
emitter: SECONDARY_DATA_SOURCE.address.0,
chain: SECONDARY_DATA_SOURCE.chain.into(),
}, },
], ],
}, },
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) SECONDARY_GOVERNANCE_SOURCE.address,
.expect("Failed to write Payload"); SECONDARY_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 2,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
assert!(contract assert!(contract
.call("execute_governance_instruction") .call("execute_governance_instruction")
@ -295,18 +251,7 @@ async fn test_set_governance_source() {
.is_empty()); .is_empty());
// But not from the old source. // But not from the old source.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
sequence: 4, // NOTE: Incremented Governance Sequence
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
payload: (),
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).expect("Failed to serialize VAA");
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
@ -314,18 +259,24 @@ async fn test_set_governance_source() {
data_sources: vec![ data_sources: vec![
Source::default(), Source::default(),
Source { Source {
emitter: [2; 32], emitter: DEFAULT_DATA_SOURCE.address.0,
chain: Chain::from(WormholeChain::Solana), chain: DEFAULT_DATA_SOURCE.chain.into(),
},
Source {
emitter: SECONDARY_DATA_SOURCE.address.0,
chain: SECONDARY_DATA_SOURCE.chain.into(),
}, },
], ],
}, },
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.expect("Failed to write Payload"); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 4,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
assert!(contract assert!(contract
.call("execute_governance_instruction") .call("execute_governance_instruction")
@ -347,27 +298,16 @@ async fn test_set_governance_source() {
async fn test_stale_threshold() { async fn test_stale_threshold() {
let (_, contract, _) = initialize_chain().await; let (_, contract, _) = initialize_chain().await;
// Submit a Price Attestation to the contract.
let vaa = wormhole_sdk::Vaa {
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
payload: (),
sequence: 1,
..Default::default()
};
// Get current UNIX timestamp and subtract a minute from it to place the price attestation in // Get current UNIX timestamp and subtract a minute from it to place the price attestation in
// the past. This should be accepted but untrusted. // the past. This should be accepted but untrusted.
let now = std::time::SystemTime::now() let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
.expect("Failed to get UNIX timestamp") .expect("Failed to get UNIX timestamp")
.as_secs() .as_secs()
- 60; - DEFAULT_VALID_TIME_PERIOD;
let vaa = { // Submit a Price Attestation to the contract.
let mut cur = Cursor::new(Vec::new()); let vaa = create_vaa_from_payload(
serde_wormhole::to_writer(&mut cur, &vaa).expect("Failed to serialize VAA");
cur.write_all(
&BatchPriceAttestation { &BatchPriceAttestation {
price_attestations: vec![PriceAttestation { price_attestations: vec![PriceAttestation {
product_id: Identifier::default(), product_id: Identifier::default(),
@ -390,10 +330,11 @@ async fn test_stale_threshold() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_DATA_SOURCE.address,
.expect("Failed to write Payload"); DEFAULT_DATA_SOURCE.chain,
hex::encode(cur.into_inner()) 1,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
let update_fee = serde_json::from_slice::<U128>( let update_fee = serde_json::from_slice::<U128>(
&contract &contract
@ -440,18 +381,7 @@ async fn test_stale_threshold() {
// Submit another Price Attestation to the contract with an even older timestamp. Which // Submit another Price Attestation to the contract with an even older timestamp. Which
// should now fail due to the existing newer price. // should now fail due to the existing newer price.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
sequence: 2,
payload: (),
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).expect("Failed to serialize VAA");
cur.write_all(
&BatchPriceAttestation { &BatchPriceAttestation {
price_attestations: vec![PriceAttestation { price_attestations: vec![PriceAttestation {
product_id: Identifier::default(), product_id: Identifier::default(),
@ -474,10 +404,11 @@ async fn test_stale_threshold() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_DATA_SOURCE.address,
.expect("Failed to write Payload"); DEFAULT_DATA_SOURCE.chain,
hex::encode(cur.into_inner()) 2,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
// The update handler should now succeed even if price is old, but simply not update the price. // The update handler should now succeed even if price is old, but simply not update the price.
assert!(contract assert!(contract
@ -516,18 +447,7 @@ async fn test_stale_threshold() {
); );
// Now we extend the staleness threshold with a Governance VAA. // Now we extend the staleness threshold with a Governance VAA.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
sequence: 3,
payload: (),
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).unwrap();
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
@ -535,10 +455,11 @@ async fn test_stale_threshold() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.unwrap(); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 3,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
assert!(contract assert!(contract
.call("execute_governance_instruction") .call("execute_governance_instruction")
@ -586,18 +507,7 @@ async fn test_contract_fees() {
.as_secs(); .as_secs();
// Set a high fee for the contract needed to submit a price. // Set a high fee for the contract needed to submit a price.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
payload: (),
sequence: 1,
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).unwrap();
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
@ -605,10 +515,11 @@ async fn test_contract_fees() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.unwrap(); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 1,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
// Fetch Update fee before changing it. // Fetch Update fee before changing it.
let update_fee = serde_json::from_slice::<U128>( let update_fee = serde_json::from_slice::<U128>(
@ -658,18 +569,7 @@ async fn test_contract_fees() {
); );
// Attempt to update the price feed with a now too low deposit. // Attempt to update the price feed with a now too low deposit.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
sequence: 2,
payload: (),
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).expect("Failed to serialize VAA");
cur.write_all(
&BatchPriceAttestation { &BatchPriceAttestation {
price_attestations: vec![PriceAttestation { price_attestations: vec![PriceAttestation {
product_id: Identifier::default(), product_id: Identifier::default(),
@ -692,10 +592,11 @@ async fn test_contract_fees() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_DATA_SOURCE.address,
.expect("Failed to write Payload"); DEFAULT_DATA_SOURCE.chain,
hex::encode(cur.into_inner()) 2,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
assert!(contract assert!(contract
.call("update_price_feeds") .call("update_price_feeds")
@ -734,18 +635,7 @@ async fn test_same_governance_sequence_fails() {
let (_, contract, _) = initialize_chain().await; let (_, contract, _) = initialize_chain().await;
// Set a high fee for the contract needed to submit a price. // Set a high fee for the contract needed to submit a price.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
payload: (),
sequence: 1,
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).unwrap();
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
@ -753,10 +643,12 @@ async fn test_same_governance_sequence_fails() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.unwrap(); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 1,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
// Attempt our first SetFee. // Attempt our first SetFee.
assert!(contract assert!(contract
@ -798,18 +690,7 @@ async fn test_out_of_order_sequences_fail() {
let (_, contract, _) = initialize_chain().await; let (_, contract, _) = initialize_chain().await;
// Set a high fee for the contract needed to submit a price. // Set a high fee for the contract needed to submit a price.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
payload: (),
sequence: 1,
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).unwrap();
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
@ -817,10 +698,11 @@ async fn test_out_of_order_sequences_fail() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.unwrap(); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 1,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
// Attempt our first SetFee. // Attempt our first SetFee.
assert!(contract assert!(contract
@ -839,18 +721,7 @@ async fn test_out_of_order_sequences_fail() {
.is_empty()); .is_empty());
// Generate another VAA with sequence 3. // Generate another VAA with sequence 3.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
payload: (),
sequence: 3,
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).unwrap();
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
@ -858,10 +729,11 @@ async fn test_out_of_order_sequences_fail() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.unwrap(); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 3,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
// This should succeed. // This should succeed.
assert!(contract assert!(contract
@ -880,18 +752,7 @@ async fn test_out_of_order_sequences_fail() {
.is_empty()); .is_empty());
// Generate another VAA with sequence 2. // Generate another VAA with sequence 2.
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
payload: (),
sequence: 2,
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).unwrap();
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Near), target: Chain::from(WormholeChain::Near),
module: GovernanceModule::Target, module: GovernanceModule::Target,
@ -899,10 +760,11 @@ async fn test_out_of_order_sequences_fail() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.unwrap(); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 2,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
// This should fail due to being out of order. // This should fail due to being out of order.
assert!(!contract assert!(!contract
@ -926,18 +788,7 @@ async fn test_out_of_order_sequences_fail() {
async fn test_governance_target_fails_if_not_near() { async fn test_governance_target_fails_if_not_near() {
let (_, contract, _) = initialize_chain().await; let (_, contract, _) = initialize_chain().await;
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
payload: (),
sequence: 1,
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).unwrap();
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Solana), target: Chain::from(WormholeChain::Solana),
module: GovernanceModule::Target, module: GovernanceModule::Target,
@ -945,10 +796,12 @@ async fn test_governance_target_fails_if_not_near() {
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.unwrap(); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 1,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
// This should fail as the target is Solana, when Near is expected. // This should fail as the target is Solana, when Near is expected.
assert!(!contract assert!(!contract
@ -970,119 +823,27 @@ async fn test_governance_target_fails_if_not_near() {
// A test to check accumulator style updates work as intended. // A test to check accumulator style updates work as intended.
#[tokio::test] #[tokio::test]
async fn test_accumulator_updates() { async fn test_accumulator_updates() {
fn create_dummy_price_feed_message(value: i64) -> Message {
let mut dummy_id = [0; 32];
dummy_id[0] = value as u8;
let msg = PriceFeedMessage {
feed_id: dummy_id,
price: value,
conf: value as u64,
exponent: value as i32,
publish_time: value,
prev_publish_time: value,
ema_price: value,
ema_conf: value as u64,
};
Message::PriceFeedMessage(msg)
}
fn create_accumulator_message_from_updates(
price_updates: Vec<MerklePriceUpdate>,
tree: MerkleTree<Keccak160>,
emitter_address: [u8; 32],
emitter_chain: u16,
) -> Vec<u8> {
let mut root_hash = [0u8; 20];
root_hash.copy_from_slice(&to_vec::<_, BigEndian>(&tree.root).unwrap()[..20]);
let wormhole_message = WormholeMessage::new(WormholePayload::Merkle(WormholeMerkleRoot {
slot: 0,
ring_size: 0,
root: root_hash,
}));
let vaa = wormhole_sdk::Vaa {
emitter_chain: emitter_chain.into(),
emitter_address: wormhole_sdk::Address(emitter_address),
sequence: 2,
payload: (),
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).expect("Failed to serialize VAA");
cur.write_all(&to_vec::<_, BigEndian>(&wormhole_message).unwrap())
.expect("Failed to write Payload");
cur.into_inner()
};
let accumulator_update_data = AccumulatorUpdateData::new(Proof::WormholeMerkle {
vaa: PrefixedVec::from(vaa),
updates: price_updates,
});
to_vec::<_, BigEndian>(&accumulator_update_data).unwrap()
}
fn create_accumulator_message(all_feeds: &[Message], updates: &[Message]) -> Vec<u8> {
let all_feeds_bytes: Vec<_> = all_feeds
.iter()
.map(|f| to_vec::<_, BigEndian>(f).unwrap())
.collect();
let all_feeds_bytes_refs: Vec<_> = all_feeds_bytes.iter().map(|f| f.as_ref()).collect();
let tree = MerkleTree::<Keccak160>::new(all_feeds_bytes_refs.as_slice()).unwrap();
let mut price_updates: Vec<MerklePriceUpdate> = vec![];
for update in updates {
let proof = tree
.prove(&to_vec::<_, BigEndian>(update).unwrap())
.unwrap();
price_updates.push(MerklePriceUpdate {
message: PrefixedVec::from(to_vec::<_, BigEndian>(update).unwrap()),
proof,
});
}
create_accumulator_message_from_updates(
price_updates,
tree,
[1; 32],
wormhole_sdk::Chain::Any.into(),
)
}
let (_, contract, _) = initialize_chain().await; let (_, contract, _) = initialize_chain().await;
// Submit a new Source to the contract, this will trigger a cross-contract call to wormhole // Submit a new Source to the contract, this will trigger a cross-contract call to wormhole
let vaa = wormhole_sdk::Vaa { let vaa = create_vaa_from_payload(
emitter_chain: wormhole_sdk::Chain::Any,
emitter_address: wormhole_sdk::Address([0; 32]),
sequence: 1,
payload: (),
..Default::default()
};
let vaa = {
let mut cur = Cursor::new(Vec::new());
serde_wormhole::to_writer(&mut cur, &vaa).expect("Failed to serialize VAA");
cur.write_all(
&GovernanceInstruction { &GovernanceInstruction {
target: Chain::from(WormholeChain::Any), target: Chain::from(WormholeChain::Any),
module: GovernanceModule::Target, module: GovernanceModule::Target,
action: GovernanceAction::SetDataSources { action: GovernanceAction::SetDataSources {
data_sources: vec![ data_sources: vec![Source {
Source::default(), emitter: DEFAULT_DATA_SOURCE.address.0,
Source { chain: DEFAULT_DATA_SOURCE.chain.into(),
emitter: [1; 32], }],
chain: Chain::from(WormholeChain::Any),
},
],
}, },
} }
.serialize() .serialize()
.unwrap(), .unwrap(),
) DEFAULT_GOVERNANCE_SOURCE.address,
.expect("Failed to write Payload"); DEFAULT_GOVERNANCE_SOURCE.chain,
hex::encode(cur.into_inner()) 1,
}; );
let vaa = hex::encode(serde_wormhole::to_vec(&vaa).unwrap());
assert!(contract assert!(contract
.call("execute_governance_instruction") .call("execute_governance_instruction")
@ -1102,7 +863,7 @@ async fn test_accumulator_updates() {
// Create a couple of test feeds. // Create a couple of test feeds.
let feed_1 = create_dummy_price_feed_message(100); let feed_1 = create_dummy_price_feed_message(100);
let feed_2 = create_dummy_price_feed_message(200); let feed_2 = create_dummy_price_feed_message(200);
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1]); let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1], false);
let message = hex::encode(message); let message = hex::encode(message);
// Call the usual UpdatePriceFeed function. // Call the usual UpdatePriceFeed function.
@ -1197,8 +958,8 @@ async fn test_borsh_field_cmopat() {
assert_eq!( assert_eq!(
decoded_price, decoded_price,
PriceTester { PriceTester {
price: i64::MAX.into(), price: i64::MAX,
conf: u64::MAX.into(), conf: u64::MAX,
expo: 100, expo: 100,
bad_field_name: 100, bad_field_name: 100,
} }