Skip to content

Commit

Permalink
feat(minor-multisig-prover): encode ApproveMessages function calldata (
Browse files Browse the repository at this point in the history
…axelarnetwork#387)

Co-authored-by: Sammy <[email protected]>
  • Loading branch information
haiyizxx and fish-sammy authored May 9, 2024
1 parent 69f5e65 commit 3e23d98
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 48 deletions.
4 changes: 1 addition & 3 deletions contracts/multisig-prover/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,8 +626,6 @@ mod tests {
assert!(event.is_some());
}

/// TODO: remove ignore flag
#[ignore = "construct proof is temporarily broken during the multisig prover amplifier gateway migration"]
#[test]
fn test_query_proof() {
let mut deps = setup_test_case();
Expand All @@ -641,7 +639,7 @@ mod tests {
assert_eq!(res.message_ids.len(), 1);
match res.status {
ProofStatus::Completed { execute_data } => {
assert_eq!(execute_data, test_data::execute_data());
assert_eq!(execute_data, test_data::approve_messages_calldata());
}
_ => panic!("Expected proof status to be completed"), // multisig mock will always return completed multisig
}
Expand Down
111 changes: 85 additions & 26 deletions contracts/multisig-prover/src/encoding/abi2/execute_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use axelar_wasm_std::hash::Hash;
use multisig::{key::Signature, msg::SignerWithSig, worker_set::WorkerSet};

use crate::{
encoding::abi2::{evm_address, Proof, WeightedSigners},
encoding::abi2::{evm_address, Message, Proof, WeightedSigners},
error::ContractError,
payload::Payload,
};

Expand Down Expand Up @@ -41,6 +42,18 @@ impl From<Proof> for IAxelarAmplifierGateway::Proof {
}
}

impl From<Message> for IAxelarAmplifierGateway::Message {
fn from(message: Message) -> Self {
IAxelarAmplifierGateway::Message {
messageId: message.messageId,
sourceChain: message.sourceChain,
sourceAddress: message.sourceAddress,
contractAddress: message.contractAddress,
payloadHash: message.payloadHash,
}
}
}

impl Proof {
/// Proof contains the entire worker set and optimized signatures. Signatures are sorted in ascending order based on the signer's address.
pub fn new(worker_set: &WorkerSet, mut signers_with_sigs: Vec<SignerWithSig>) -> Self {
Expand All @@ -65,20 +78,32 @@ pub fn encode(
signers: Vec<SignerWithSig>,
payload_digest: &Hash,
payload: &Payload,
) -> HexBinary {
) -> Result<HexBinary, ContractError> {
let signers = to_recoverable(payload_digest.as_slice(), signers);

let proof = Proof::new(worker_set, signers);

match payload {
Payload::Messages(_) => todo!(),
let data = match payload {
Payload::Messages(messages) => {
let messages: Vec<_> = messages
.iter()
.map(|msg| Message::try_from(msg).map(IAxelarAmplifierGateway::Message::from))
.collect::<Result<Vec<_>, _>>()?;

IAxelarAmplifierGateway::approveMessagesCall::new((messages, proof.into()))
.abi_encode()
.into()
}
Payload::WorkerSet(new_worker_set) => {
let new_worker_set = WeightedSigners::from(new_worker_set);

IAxelarAmplifierGateway::rotateSignersCall::new((new_worker_set.into(), proof.into()))
.abi_encode()
.into()
}
}
};

Ok(data)
}

// Convert non-recoverable ECDSA signatures to recoverable ones.
Expand Down Expand Up @@ -120,6 +145,7 @@ mod tests {

use axelar_wasm_std::hash::Hash;
use multisig::key::{KeyType, KeyTyped, Signature};
use multisig::msg::{Signer, SignerWithSig};

use crate::{
encoding::abi2::{
Expand All @@ -128,7 +154,7 @@ mod tests {
payload_hash_to_sign,
},
payload::Payload,
test::test_data::{curr_worker_set, worker_set_from_pub_keys},
test::test_data::{curr_worker_set, domain_separator, messages, worker_set_from_pub_keys},
};

#[test]
Expand All @@ -138,11 +164,7 @@ mod tests {
HexBinary::from_hex("52c65e01d464f6e440ebff7561b09edc1c9ff7754dd8bdaaa0410a952b9824cb")
.unwrap();

let domain_separator: [u8; 32] =
HexBinary::from_hex("3593643a7d7e917a099eef6c52d1420bb4f33eb074b16439556de5984791262b")
.unwrap()
.to_array()
.unwrap();
let domain_separator = domain_separator();

let new_pub_keys = vec![
"0352a321079b435a4566ac8c92ab18584d8537d563f6c2c0bbbf58246ad047c611",
Expand All @@ -162,20 +184,7 @@ mod tests {
"7c685ecc8a42da4cd9d6de7860b0fddebb4e2e934357500257c1070b1a15be5e27f13b627cf9fa44f59d535af96be0a5ec214d988c48e2b5aaf3ba537d0215bb1b",
].into_iter().map(|sig| HexBinary::from_hex(sig).unwrap()).collect();

let signers_with_sigs = worker_set
.signers
.values()
.sorted_by(|s1, s2| {
Ord::cmp(
&evm_address(&s1.pub_key).unwrap(),
&evm_address(&s2.pub_key).unwrap(),
)
})
.zip(sigs)
.map(|(signer, sig)| {
signer.with_sig(Signature::try_from((signer.pub_key.key_type(), sig)).unwrap())
})
.collect();
let signers_with_sigs = signers_with_sigs(worker_set.signers.values(), sigs);

let payload = Payload::WorkerSet(new_worker_set);
let payload_hash: Hash = payload_hash_to_sign(&domain_separator, &worker_set, &payload)
Expand All @@ -184,7 +193,7 @@ mod tests {
.try_into()
.unwrap();

let execute_data = encode(&worker_set, signers_with_sigs, &payload_hash, &payload);
let execute_data = encode(&worker_set, signers_with_sigs, &payload_hash, &payload).unwrap();
let data_hash = Keccak256::digest(execute_data.as_slice());

assert_eq!(HexBinary::from(data_hash.as_slice()), expected_data_hash);
Expand Down Expand Up @@ -226,4 +235,54 @@ mod tests {
panic!("Invalid signature type")
}
}

#[test]
fn approve_messages_function_data() {
// ApproveMessages function calldata hash generated by axelar-gmp-sdk-solidity unit tests
let expected_data_hash =
HexBinary::from_hex("cf6200f6889b7157af0bfcb2eaaabc03d89b94428dcbe613f5844f4f593c050d")
.unwrap();

let domain_separator = domain_separator();
let worker_set = curr_worker_set();

// Generated signatures are already sorted by weight and evm address
let sigs: Vec<_> = vec![
"6e320a96a33260b488c6c4a2fa007345a4db974bf9d94a9568edf79452ee0e805eedb7c4e67ce16fb5cc0691b04b5caf3b0014e1133d5175a9bc47d917f57e251c",
"fdd7269bbc41946f73ca744a4037fd1e9fcf2d2a93db8cfe2143c2b0ea52bd96300c7f61803cebaff1590bc137ca0503697a502d06a1c4998aaceb77c0a91c6b1c",
"01363790ed71e5070be5d79277350b3300cbba90b1141dbcf49103eaf113178c30947ff9fb293d23860aa33150b883e0852faae0fad1218550a8c730ac9961fc1b",
].into_iter().map(|sig| HexBinary::from_hex(sig).unwrap()).collect();

let signers_with_sigs = signers_with_sigs(worker_set.signers.values(), sigs);

let payload = Payload::Messages(messages());
let payload_hash: Hash = payload_hash_to_sign(&domain_separator, &worker_set, &payload)
.unwrap()
.as_slice()
.try_into()
.unwrap();

let execute_data = encode(&worker_set, signers_with_sigs, &payload_hash, &payload).unwrap();
let data_hash = Keccak256::digest(execute_data.as_slice());

assert_eq!(HexBinary::from(data_hash.as_slice()), expected_data_hash);
}

fn signers_with_sigs<'a>(
signers: impl Iterator<Item = &'a Signer>,
sigs: Vec<HexBinary>,
) -> Vec<SignerWithSig> {
signers
.sorted_by(|s1, s2| {
Ord::cmp(
&evm_address(&s1.pub_key).unwrap(),
&evm_address(&s2.pub_key).unwrap(),
)
})
.zip(sigs)
.map(|(signer, sig)| {
signer.with_sig(Signature::try_from((signer.pub_key.key_type(), sig)).unwrap())
})
.collect()
}
}
16 changes: 5 additions & 11 deletions contracts/multisig-prover/src/encoding/abi2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ mod tests {
use crate::{
encoding::abi2::{payload_hash_to_sign, CommandType, Message, WeightedSigners},
payload::Payload,
test::test_data::{curr_worker_set, messages, new_worker_set, worker_set_from_pub_keys},
test::test_data::{
curr_worker_set, domain_separator, messages, new_worker_set, worker_set_from_pub_keys,
},
};

#[test]
Expand Down Expand Up @@ -186,11 +188,7 @@ mod tests {
HexBinary::from_hex("fbb9a154bbafd0be9469d7c83bfe5807d916ec7430f5232f29b967240880f327")
.unwrap();

let domain_separator: [u8; 32] =
HexBinary::from_hex("3593643a7d7e917a099eef6c52d1420bb4f33eb074b16439556de5984791262b")
.unwrap()
.to_array()
.unwrap();
let domain_separator = domain_separator();

let new_pub_keys = vec![
"02de8b0cc10de1becab121cb1254a7b4075866b6e040d5a4cdd38c7ea6c68c7d0a",
Expand Down Expand Up @@ -254,11 +252,7 @@ mod tests {
HexBinary::from_hex("2ab230ae08c9fc5e9110c08061a9dffe928a1093133a6f157316fb9c90bf825c")
.unwrap();

let domain_separator: [u8; 32] =
HexBinary::from_hex("3593643a7d7e917a099eef6c52d1420bb4f33eb074b16439556de5984791262b")
.unwrap()
.to_array()
.unwrap();
let domain_separator = domain_separator();

let digest = payload_hash_to_sign(
&domain_separator,
Expand Down
9 changes: 3 additions & 6 deletions contracts/multisig-prover/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,9 @@ impl Payload {
let payload_hash = payload.digest(encoder, domain_separator, worker_set)?;

match encoder {
Encoder::Abi => Ok(abi2::execute_data::encode(
worker_set,
signers_with_sigs,
&payload_hash,
payload,
)),
Encoder::Abi => {
abi2::execute_data::encode(worker_set, signers_with_sigs, &payload_hash, payload)
}
Encoder::Bcs => todo!(),
}
}
Expand Down
12 changes: 12 additions & 0 deletions contracts/multisig-prover/src/test/test_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ pub fn execute_data() -> HexBinary {
HexBinary::from_hex("09c5eabe000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000007600000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000000539000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000101d9a96970a852fe24dad94e05c4c8c5eab33d027cb7d381c2745c390d75e998000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000013617070726f7665436f6e747261637443616c6c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000a4f10f76b86e01b98daf66a3d02a65e14adb07678c3685dc41c2eca11426f8035742fb97ea9f14931152670a5703f18fe8b392f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000967616e616368652d310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307835323434346631383335416463303230383663333743623232363536313630356532453136393962000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000050000000000000000000000004ef5c8d81b6417fa80c320b5fc1d3900506dff540000000000000000000000006c51eec96bf0a8ec799cdd0bbcb4512f8334afe80000000000000000000000007aeb4eebf1e8dcde3016d4e1dca52b4538cf7aaf000000000000000000000000c5b95c99d883c3204cfc2e73669ce3aa7437f4a6000000000000000000000000ffffde829096dfe8b833997e939865ff57422ea90000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000004172b242d7247fc31d14ce82b32f3ea911808f6f600f362150f9904c974315942927c25f9388cecdbbb0b3723164eea92206775870cd28e1ffd8f1cb9655fb3c4a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004186909155a6ba27f173edf15d283da6a0019fb6afe6b223ca68530464813f468f356e70788faf6d1d9ff7bfcfd9021b560d72408bef4c86c66e3a94b9dee0a34a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419b2d986652fdebe67554f1b33ae6161b205ea84e0dacb07ffde0889791bcab2e5be3b8229eae01f2c22805c87f15cb7f9642e9cba951489edcac5d12ace399391b00000000000000000000000000000000000000000000000000000000000000").unwrap()
}

pub fn approve_messages_calldata() -> HexBinary {
HexBinary::from_hex("64f1d85a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000a4f10f76b86e01b98daf66a3d02a65e14adb07678c3685dc41c2eca11426f8035742fb97ea9f14931152670a5703f18fe8b392f000000000000000000000000000000000000000000000000000000000000000443078666638323263383838303738353966663232366235386532346632343937346137306630346239343432353031616533386664363635623363363866333833342d3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000967616e616368652d310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307835323434346631383335416463303230383663333743623232363536313630356532453136393962000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000003010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000004ef5c8d81b6417fa80c320b5fc1d3900506dff5400000000000000000000000000000000000000000000000000000000000000010000000000000000000000006c51eec96bf0a8ec799cdd0bbcb4512f8334afe800000000000000000000000000000000000000000000000000000000000000010000000000000000000000007aeb4eebf1e8dcde3016d4e1dca52b4538cf7aaf0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c5b95c99d883c3204cfc2e73669ce3aa7437f4a60000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ffffde829096dfe8b833997e939865ff57422ea900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000004172b242d7247fc31d14ce82b32f3ea911808f6f600f362150f9904c974315942927c25f9388cecdbbb0b3723164eea92206775870cd28e1ffd8f1cb9655fb3c4a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004186909155a6ba27f173edf15d283da6a0019fb6afe6b223ca68530464813f468f356e70788faf6d1d9ff7bfcfd9021b560d72408bef4c86c66e3a94b9dee0a34a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419b2d986652fdebe67554f1b33ae6161b205ea84e0dacb07ffde0889791bcab2e5be3b8229eae01f2c22805c87f15cb7f9642e9cba951489edcac5d12ace399391b00000000000000000000000000000000000000000000000000000000000000").unwrap()
}

pub fn threshold() -> MajorityThreshold {
let numerator: nonempty::Uint64 = Uint64::from(2u8).try_into().unwrap();
let denominator: nonempty::Uint64 = Uint64::from(3u8).try_into().unwrap();
Expand Down Expand Up @@ -235,3 +239,11 @@ pub fn worker_set_from_pub_keys(pub_keys: Vec<&str>) -> WorkerSet {
.collect();
WorkerSet::new(participants, Uint256::from_u128(3), 0)
}

// Domain separator matches axelar-gmp-sdk-solidity repo test data
pub fn domain_separator() -> [u8; 32] {
HexBinary::from_hex("3593643a7d7e917a099eef6c52d1420bb4f33eb074b16439556de5984791262b")
.unwrap()
.to_array()
.unwrap()
}
2 changes: 0 additions & 2 deletions integration-tests/tests/message_routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ pub mod test_utils;
/// Tests that a single message can be routed fully through the protocol. Submits a message to the
/// gateway, votes on the poll, routes the message to the outgoing gateway, triggers signing at the prover
/// and signs via multisig. Also tests that rewards are distributed as expected for voting and signing.
/// TODO: remove ignore flag
#[ignore = "verify messages is temporarily broken during the multisig prover amplifier gateway migration"]
#[test]
fn single_message_can_be_verified_and_routed_and_proven_and_rewards_are_distributed() {
let test_utils::TestCase {
Expand Down

0 comments on commit 3e23d98

Please sign in to comment.