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 all 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.

22 changes: 11 additions & 11 deletions 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 Expand Up @@ -49,31 +49,31 @@ pub fn get_multisig_ism_test_data() -> MultisigIsmTestData {
};

// checkpoint.signing_hash() is equal to:
// 0x4fc33ff33d5e9305a2d87f7824d1b943ba219cff4c153ae8fd39b0d8620fc332
// 0x5c2b4cbafdd7319d9a3dea4aa078748ae53368e1521494a80cf4259b9c6dba6a

// Validator 0:
// Address: 0xE3DCDBbc248cE191bDc271f3FCcd0d95911BFC5D
// Private Key: 0x788aa7213bd92ff92017d767fde0d75601425818c8e4b21e87314c2a4dcd6091
let validator_0 = H160::from_str("0xE3DCDBbc248cE191bDc271f3FCcd0d95911BFC5D").unwrap();
// > await (new ethers.Wallet('0x788aa7213bd92ff92017d767fde0d75601425818c8e4b21e87314c2a4dcd6091')).signMessage(ethers.utils.arrayify('0x4fc33ff33d5e9305a2d87f7824d1b943ba219cff4c153ae8fd39b0d8620fc332'))
// '0x3a06cc01fef07025ee5ae9e29ae783338fe11f5c21af383fb8cc5878a2ea3616125c230ec07b059eaebb842af0a51040ad3214f9050cccef36b5c21c9c9cc4ba1b'
let signature_0 = hex::decode("3a06cc01fef07025ee5ae9e29ae783338fe11f5c21af383fb8cc5878a2ea3616125c230ec07b059eaebb842af0a51040ad3214f9050cccef36b5c21c9c9cc4ba1b").unwrap();
// > await (new ethers.Wallet('0x788aa7213bd92ff92017d767fde0d75601425818c8e4b21e87314c2a4dcd6091')).signMessage(ethers.utils.arrayify('0x5c2b4cbafdd7319d9a3dea4aa078748ae53368e1521494a80cf4259b9c6dba6a'))
// '0xb8875fb75adf471e43a943b78eb422ffe86a4291fa6324f9f875241605ca831d2b4225358936deee7501cf305aafc1677e3dc9bcfea4caec54f4cde49d416bd91b'
let signature_0 = hex::decode("b8875fb75adf471e43a943b78eb422ffe86a4291fa6324f9f875241605ca831d2b4225358936deee7501cf305aafc1677e3dc9bcfea4caec54f4cde49d416bd91b").unwrap();

// Validator 1:
// Address: 0xb25206874C24733F05CC0dD11924724A8E7175bd
// Private Key: 0x4a599de3915f404d84a2ebe522bfe7032ebb1ca76a65b55d6eb212b129043a0e
let validator_1 = H160::from_str("0xb25206874C24733F05CC0dD11924724A8E7175bd").unwrap();
// > await (new ethers.Wallet('0x4a599de3915f404d84a2ebe522bfe7032ebb1ca76a65b55d6eb212b129043a0e')).signMessage(ethers.utils.arrayify('0x4fc33ff33d5e9305a2d87f7824d1b943ba219cff4c153ae8fd39b0d8620fc332'))
// '0xfd34aac152ec85a79211c990f308c7e719145e2e67e48f2d10db4347d3a9102131254eccbcd0fe389afad96b88d368192b33649336893dfe1bbad43901d1bef71b'
let signature_1 = hex::decode("fd34aac152ec85a79211c990f308c7e719145e2e67e48f2d10db4347d3a9102131254eccbcd0fe389afad96b88d368192b33649336893dfe1bbad43901d1bef71b").unwrap();
// > await (new ethers.Wallet('0x4a599de3915f404d84a2ebe522bfe7032ebb1ca76a65b55d6eb212b129043a0e')).signMessage(ethers.utils.arrayify('0x5c2b4cbafdd7319d9a3dea4aa078748ae53368e1521494a80cf4259b9c6dba6a'))
// '0xfa8d61da2e0ac6f32c8432e75770d90483613efe96b442fbca9ca8d200447bf979f46529c7341879333a9c24a7d3fba08b53d13447618b71cf2ee4734e82f96e1c'
let signature_1 = hex::decode("fa8d61da2e0ac6f32c8432e75770d90483613efe96b442fbca9ca8d200447bf979f46529c7341879333a9c24a7d3fba08b53d13447618b71cf2ee4734e82f96e1c").unwrap();

// Validator 2:
// Address: 0x28b8d0E2bBfeDe9071F8Ff3DaC9CcE3d3176DBd3
// Private Key: 0x2cc76d56db9924ddc3388164454dfea9edd2d5f5da81102fd3594fc7c5281515
let validator_2 = H160::from_str("0x28b8d0E2bBfeDe9071F8Ff3DaC9CcE3d3176DBd3").unwrap();
// > await (new ethers.Wallet('0x2cc76d56db9924ddc3388164454dfea9edd2d5f5da81102fd3594fc7c5281515')).signMessage(ethers.utils.arrayify('0x4fc33ff33d5e9305a2d87f7824d1b943ba219cff4c153ae8fd39b0d8620fc332'))
// '0x85992e471002c40730d2b91831ba40cd8ffcebf4905646c25b7b6abb7575f25d19395045466e833b7700e233bfa5836f0a459da05bf817efd6cb4f55bcaec4b51c'
let signature_2 = hex::decode("85992e471002c40730d2b91831ba40cd8ffcebf4905646c25b7b6abb7575f25d19395045466e833b7700e233bfa5836f0a459da05bf817efd6cb4f55bcaec4b51c").unwrap();
// > await (new ethers.Wallet('0x2cc76d56db9924ddc3388164454dfea9edd2d5f5da81102fd3594fc7c5281515')).signMessage(ethers.utils.arrayify('0x5c2b4cbafdd7319d9a3dea4aa078748ae53368e1521494a80cf4259b9c6dba6a'))
// '0x6c60c3744f6bf779017b8ab9aa8eed60bf53c317cf4d74d765015cc0a7dcad783dee39334bfc7e4baab944355914e7431e4286df8c0557a0c1f6ba867677da421b'
let signature_2 = hex::decode("6c60c3744f6bf779017b8ab9aa8eed60bf53c317cf4d74d765015cc0a7dcad783dee39334bfc7e4baab944355914e7431e4286df8c0557a0c1f6ba867677da421b").unwrap();

MultisigIsmTestData {
message,
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()
.map_err(|_| Error::InvalidMetadata)?;
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
Loading
Loading