Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sealevel v3 contracts #3048

Merged
merged 7 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/sealevel/libraries/multisig-ism/src/test_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const DESTINATION_DOMAIN: u32 = 4321u32;

pub fn get_multisig_ism_test_data() -> MultisigIsmTestData {
let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 69,
origin: ORIGIN_DOMAIN,
sender: H256::from_str(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ async fn test_transfer_remote(spl_token_program_id: Pubkey) {
.unwrap();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: LOCAL_DOMAIN,
sender: program_id.to_bytes().into(),
Expand Down Expand Up @@ -869,7 +869,7 @@ async fn transfer_from_remote(
);

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: origin_override.unwrap_or(REMOTE_DOMAIN),
// Default to the remote router as the sender
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ async fn test_transfer_remote() {
.unwrap();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: LOCAL_DOMAIN,
sender: program_id.to_bytes().into(),
Expand Down Expand Up @@ -616,7 +616,7 @@ async fn transfer_from_remote(
let recipient: H256 = recipient_pubkey.to_bytes().into();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: origin_override.unwrap_or(REMOTE_DOMAIN),
// Default to the remote router as the sender
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ async fn transfer_from_remote(
);

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: origin_override.unwrap_or(REMOTE_DOMAIN),
// Default to the remote router as the sender
Expand Down Expand Up @@ -783,7 +783,7 @@ async fn test_transfer_remote() {
.unwrap();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: LOCAL_DOMAIN,
sender: program_id.to_bytes().into(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ serializable-account-meta = { path = "../../../libraries/serializable-account-me
[dev-dependencies]
hyperlane-sealevel-multisig-ism-message-id = { path = "../multisig-ism-message-id" }
hyperlane-test-utils = { path = "../../../libraries/test-utils" }
multisig-ism = { path = "../../../libraries/multisig-ism", features = ["test-data"] }
solana-program-test.workspace = true
solana-sdk.workspace = true
hex.workspace = true
multisig-ism = { path = "../../../libraries/multisig-ism", features = ["test-data"] }
# Can't have as a workspace dep, because this is already in the dep tree twice: once as
# an older solana one, once as a newer one used more generally.
rand = "0.8.5"

[lib]
crate-type = ["cdylib", "lib"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ use crate::error::Error;
pub struct MultisigIsmMessageIdMetadata {
pub origin_merkle_tree_hook: H256,
pub merkle_root: H256,
pub merkle_index: u32,
pub validator_signatures: Vec<EcdsaSignature>,
}

const ORIGIN_MAILBOX_OFFSET: usize = 0;
const MERKLE_ROOT_OFFSET: usize = 32;
const SIGNATURES_OFFSET: usize = 64;
const MERKLE_INDEX_OFFSET: usize = 64;
const SIGNATURES_OFFSET: usize = 68;
const SIGNATURE_LENGTH: usize = 65;

/// Format of metadata:
Expand All @@ -32,7 +34,12 @@ impl TryFrom<Vec<u8>> for MultisigIsmMessageIdMetadata {
}

let origin_mailbox = H256::from_slice(&bytes[ORIGIN_MAILBOX_OFFSET..MERKLE_ROOT_OFFSET]);
let merkle_root = H256::from_slice(&bytes[MERKLE_ROOT_OFFSET..SIGNATURES_OFFSET]);
let merkle_root = H256::from_slice(&bytes[MERKLE_ROOT_OFFSET..MERKLE_INDEX_OFFSET]);
// This cannot panic since SIGNATURES_OFFSET - MERKLE_INDEX_OFFSET is 4.
let merkle_index_bytes: [u8; 4] = bytes[MERKLE_INDEX_OFFSET..SIGNATURES_OFFSET]
.try_into()
.unwrap();
daniel-savu marked this conversation as resolved.
Show resolved Hide resolved
let merkle_index = u32::from_be_bytes(merkle_index_bytes);

let signature_bytes_len = bytes_len - SIGNATURES_OFFSET;
// Require the signature bytes to be a multiple of the signature length.
Expand All @@ -55,6 +62,7 @@ impl TryFrom<Vec<u8>> for MultisigIsmMessageIdMetadata {
Ok(Self {
origin_merkle_tree_hook: origin_mailbox,
merkle_root,
merkle_index,
validator_signatures,
})
}
Expand All @@ -68,6 +76,7 @@ impl Encode for MultisigIsmMessageIdMetadata {
let mut bytes_written = 0;
bytes_written += writer.write(self.origin_merkle_tree_hook.as_ref())?;
bytes_written += writer.write(self.merkle_root.as_ref())?;
bytes_written += writer.write(&self.merkle_index.to_be_bytes())?;
for signature in &self.validator_signatures {
bytes_written += writer.write(&signature.as_fixed_bytes()[..])?;
}
Expand All @@ -78,11 +87,21 @@ impl Encode for MultisigIsmMessageIdMetadata {
#[cfg(test)]
mod test {
use super::*;
use rand::Rng;

// Provide a default test implementation
fn dummy_metadata_with_sigs(sigs: Vec<EcdsaSignature>) -> MultisigIsmMessageIdMetadata {
let mut rng = rand::thread_rng();
MultisigIsmMessageIdMetadata {
origin_merkle_tree_hook: H256::random(),
merkle_root: H256::random(),
merkle_index: rng.gen(),
validator_signatures: sigs,
}
}

#[test]
fn test_decode_correctly_formatted_metadata() {
let origin_mailbox = H256::random();
let merkle_root = H256::random();
let validator_signatures = vec![
EcdsaSignature {
serialized_rs: [11u8; 64],
Expand All @@ -97,43 +116,49 @@ mod test {
recovery_id: 0,
},
];
let mut metadata_bytes = origin_mailbox.as_bytes().to_vec();
metadata_bytes.extend_from_slice(merkle_root.as_bytes());
for signature in &validator_signatures {
metadata_bytes.extend_from_slice(&signature.as_fixed_bytes()[..]);
}

let metadata = MultisigIsmMessageIdMetadata::try_from(metadata_bytes).unwrap();
assert_eq!(metadata.origin_merkle_tree_hook, origin_mailbox);
assert_eq!(metadata.merkle_root, merkle_root);
assert_eq!(metadata.validator_signatures, validator_signatures);
let test_meta = dummy_metadata_with_sigs(validator_signatures);
let encoded_meta = test_meta.to_vec();
let metadata = MultisigIsmMessageIdMetadata::try_from(encoded_meta.clone()).unwrap();
assert_eq!(
metadata.origin_merkle_tree_hook,
test_meta.origin_merkle_tree_hook
);
assert_eq!(metadata.merkle_root, test_meta.merkle_root);
assert_eq!(metadata.merkle_index, test_meta.merkle_index);
assert_eq!(
metadata.validator_signatures,
test_meta.validator_signatures
);
}

#[test]
fn test_decode_no_signatures_is_err() {
let origin_mailbox = H256::random();
let merkle_root = H256::random();
let metadata_bytes = origin_mailbox
.as_bytes()
.iter()
.chain(merkle_root.as_bytes().iter())
.cloned()
.collect::<Vec<u8>>();

let result = MultisigIsmMessageIdMetadata::try_from(metadata_bytes);
let test_meta = dummy_metadata_with_sigs(vec![]);
let encoded_meta = test_meta.to_vec();
let result = MultisigIsmMessageIdMetadata::try_from(encoded_meta);
assert!(result.unwrap_err() == Error::InvalidMetadata);
}

#[test]
fn test_decode_incorrect_signature_length_is_err() {
let origin_mailbox = H256::random();
let merkle_root = H256::random();
let mut metadata_bytes = origin_mailbox.as_bytes().to_vec();
metadata_bytes.extend_from_slice(merkle_root.as_bytes());
// 64 byte signature instead of 65.
metadata_bytes.extend_from_slice(&[1u8; 64]);

let result = MultisigIsmMessageIdMetadata::try_from(metadata_bytes);
let sigs = vec![EcdsaSignature {
serialized_rs: [1u8; 64],
recovery_id: 0,
}];
let test_meta = dummy_metadata_with_sigs(sigs);
let encoded_meta = test_meta.to_vec();
// remove the last byte from the encoded signature
let faulty_encoded_meta = encoded_meta[..encoded_meta.len() - 1].to_vec();
let result = MultisigIsmMessageIdMetadata::try_from(faulty_encoded_meta);
assert!(result.unwrap_err() == Error::InvalidMetadata);
MultisigIsmMessageIdMetadata::try_from(encoded_meta).expect("Decoding should succeed");
}

#[test]
fn test_decode_real_meta() {
// multisig ism message id metadata from this tx:
// https://arbiscan.io//tx/0xe558f04ad446b1d9ec4d4a1284661869b73daff38ec9fb7e809be652732fff30#txninfo
let bytes = hex::decode("000000000000000000000000149db7afd694722747035d5aec7007ccb6f8f112fb91807ccda2db543bfbd013242643553bc1238f891ae9d0abb3b8b46c5a89990000017addc429c97ca8bcd6ad86ef4461379374b0d545308a1f47db246a6c028f74d7af521dd9355afd2f2a02565a24f22ac7b7e388cbd1f2a931acc97ce689be5456851b4d22f1aece05d293e574e38edcda9f2db64f1dc5b69a89a6a5989e7aaa4f443c137e593bb794eb211de719ed0f466a0778c4d204cc275f54c0936eee918ae1651c").unwrap();
MultisigIsmMessageIdMetadata::try_from(bytes).expect("Decoding should succeed");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ pub mod test {
metadata: MultisigIsmMessageIdMetadata {
origin_merkle_tree_hook: checkpoint.merkle_tree_hook_address,
merkle_root: checkpoint.root,
merkle_index: checkpoint.index,
validator_signatures: vec![
EcdsaSignature::from_bytes(&signatures[0]).unwrap(),
EcdsaSignature::from_bytes(&signatures[1]).unwrap(),
Expand All @@ -626,6 +627,7 @@ pub mod test {
metadata: MultisigIsmMessageIdMetadata {
origin_merkle_tree_hook: checkpoint.merkle_tree_hook_address,
merkle_root: checkpoint.root,
merkle_index: checkpoint.index,
validator_signatures: vec![
EcdsaSignature::from_bytes(&signatures[1]).unwrap(),
EcdsaSignature::from_bytes(&signatures[0]).unwrap(),
Expand Down Expand Up @@ -654,6 +656,7 @@ pub mod test {
metadata: MultisigIsmMessageIdMetadata {
origin_merkle_tree_hook: checkpoint.merkle_tree_hook_address,
merkle_root: checkpoint.root,
merkle_index: checkpoint.index,
validator_signatures: vec![
EcdsaSignature::from_bytes(&signatures[0]).unwrap(),
EcdsaSignature::from_bytes(&signatures[2]).unwrap(),
Expand All @@ -678,6 +681,7 @@ pub mod test {
metadata: MultisigIsmMessageIdMetadata {
origin_merkle_tree_hook: checkpoint.merkle_tree_hook_address,
merkle_root: checkpoint.root,
merkle_index: checkpoint.index,
validator_signatures: vec![
EcdsaSignature::from_bytes(&signatures[0]).unwrap(),
EcdsaSignature::from_bytes(&signatures[1]).unwrap(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ async fn test_set_validators_and_threshold_creates_pda_account() {
// to fetch the account metas required for the instruction.

let test_message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: domain,
sender: H256::random(),
Expand Down Expand Up @@ -421,6 +421,7 @@ async fn test_ism_verify() {
metadata: MultisigIsmMessageIdMetadata {
origin_merkle_tree_hook: checkpoint.merkle_tree_hook_address,
merkle_root: checkpoint.root,
merkle_index: checkpoint.index,
validator_signatures: vec![
EcdsaSignature::from_bytes(&signatures[0]).unwrap(),
EcdsaSignature::from_bytes(&signatures[1]).unwrap(),
Expand Down
22 changes: 11 additions & 11 deletions rust/sealevel/programs/mailbox-test/src/functional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ async fn test_dispatch_from_eoa() {
.unwrap();

let expected_message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: LOCAL_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down Expand Up @@ -238,7 +238,7 @@ async fn test_dispatch_from_eoa() {
.unwrap();

let expected_message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 1,
origin: LOCAL_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down Expand Up @@ -300,7 +300,7 @@ async fn test_dispatch_from_program() {
.unwrap();

let expected_message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: LOCAL_DOMAIN,
// The sender should be the program ID because its dispatch authority signed
Expand Down Expand Up @@ -389,7 +389,7 @@ async fn test_dispatch_returns_message_id() {
message_body: message_body.clone(),
};
let expected_message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: LOCAL_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down Expand Up @@ -574,7 +574,7 @@ async fn test_process_successful_verify_and_handle() {
let recipient_id = hyperlane_sealevel_test_send_receiver::id();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: REMOTE_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down Expand Up @@ -605,7 +605,7 @@ async fn test_process_successful_verify_and_handle() {

// Send another to illustrate that the sequence is incremented
let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: REMOTE_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down Expand Up @@ -647,7 +647,7 @@ async fn test_process_errors_if_message_already_processed() {
let recipient_id = hyperlane_sealevel_test_send_receiver::id();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: REMOTE_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down Expand Up @@ -697,7 +697,7 @@ async fn test_process_errors_if_ism_verify_fails() {
test_ism.set_accept(false).await.unwrap();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: REMOTE_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down Expand Up @@ -743,7 +743,7 @@ async fn test_process_errors_if_recipient_handle_fails() {
.unwrap();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: REMOTE_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down Expand Up @@ -784,7 +784,7 @@ async fn test_process_errors_if_incorrect_destination_domain() {
let recipient_id = hyperlane_sealevel_test_send_receiver::id();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: REMOTE_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down Expand Up @@ -905,7 +905,7 @@ async fn test_process_errors_if_reentrant() {
let recipient_id = hyperlane_sealevel_test_send_receiver::id();

let message = HyperlaneMessage {
version: 0,
version: 3,
nonce: 0,
origin: REMOTE_DOMAIN,
sender: payer.pubkey().to_bytes().into(),
Expand Down
2 changes: 1 addition & 1 deletion rust/sealevel/programs/mailbox/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use solana_program::{
use crate::{mailbox_inbox_pda_seeds, mailbox_outbox_pda_seeds};

/// The current message version.
pub const VERSION: u8 = 0;
pub const VERSION: u8 = 3;

/// Maximum bytes per message = 2 KiB (somewhat arbitrarily set to begin).
pub const MAX_MESSAGE_BODY_BYTES: usize = 2 * 2_usize.pow(10);
Expand Down
Loading