From dc6abedc1d7a9a358e84782aefff1d85ae0f2292 Mon Sep 17 00:00:00 2001 From: Nam Chu Hoai Date: Wed, 20 Apr 2022 16:24:53 -0400 Subject: [PATCH] Remove Outbox nonce and checkpointedRoot from dispatch event (#341) * Remove Outbox nonce and checkpointedRoot from dispatch event * Fix db_state * Fix npm build * Fix test * Fix test * Explicitly pass leaf_index to message hash calculation * remove retrying * Update message.json * Remove nonce from AbacusMessage in sdk * Fix test * PR review --- rust/abacus-base/src/contract_sync/mod.rs | 6 - rust/abacus-base/src/outbox.rs | 27 --- rust/abacus-core/src/db/abacus_db.rs | 41 +---- rust/abacus-core/src/test_output.rs | 5 +- rust/abacus-core/src/traits/message.rs | 25 ++- rust/abacus-core/src/traits/outbox.rs | 27 --- rust/abacus-core/src/types/messages.rs | 37 ++-- rust/abacus-test/src/mocks/outbox.rs | 13 -- rust/abacus-test/src/test_utils.rs | 14 +- .../abacus-ethereum/abis/Outbox.abi.json | 31 +--- rust/chains/abacus-ethereum/src/outbox.rs | 6 - rust/config/test/alfajores_config.json | 30 ++-- rust/config/test/fuji_config.json | 21 ++- rust/config/test/kovan_config.json | 21 ++- rust/config/test/mumbai_config.json | 21 ++- rust/tools/abacus-cli/src/commands.rs | 4 +- rust/tools/abacus-cli/src/main.rs | 1 - .../abacus-cli/src/subcommands/db_state.rs | 164 ------------------ rust/tools/abacus-cli/src/subcommands/mod.rs | 2 - .../tools/abacus-cli/src/subcommands/prove.rs | 4 +- solidity/core/contracts/Inbox.sol | 2 +- solidity/core/contracts/Outbox.sol | 32 +--- solidity/core/contracts/test/TestInbox.sol | 4 +- solidity/core/contracts/test/TestMessage.sol | 12 +- solidity/core/libs/Message.sol | 46 +++-- solidity/core/test/inbox.test.ts | 40 ++--- solidity/core/test/message.test.ts | 14 +- solidity/core/test/outbox.test.ts | 29 +--- typescript/hardhat/src/TestAbacusDeploy.ts | 7 +- typescript/sdk/src/core/message.ts | 17 +- typescript/sdk/test/gas/calculator.test.ts | 1 - typescript/utils/src/utils.ts | 12 +- vectors/message.json | 8 +- vectors/messageWithProof.json | 12 +- 34 files changed, 199 insertions(+), 537 deletions(-) delete mode 100644 rust/tools/abacus-cli/src/subcommands/db_state.rs diff --git a/rust/abacus-base/src/contract_sync/mod.rs b/rust/abacus-base/src/contract_sync/mod.rs index 4221e50e2..5e76d918e 100644 --- a/rust/abacus-base/src/contract_sync/mod.rs +++ b/rust/abacus-base/src/contract_sync/mod.rs @@ -597,7 +597,6 @@ mod test { origin: 1000, destination: 2000, sender: H256::from([10; 32]), - nonce: 1, recipient: H256::from([11; 32]), body: [10u8; 5].to_vec(), } @@ -606,26 +605,22 @@ mod test { let first_message = RawCommittedMessage { leaf_index: 0, - committed_root: first_root, message: message_vec.clone(), }; let second_message = RawCommittedMessage { leaf_index: 1, - committed_root: second_root, message: message_vec.clone(), }; let second_message_clone = second_message.clone(); let third_message = RawCommittedMessage { leaf_index: 2, - committed_root: second_root, message: message_vec.clone(), }; let fourth_message = RawCommittedMessage { leaf_index: 3, - committed_root: third_root, message: message_vec.clone(), }; let fourth_message_clone_1 = fourth_message.clone(); @@ -633,7 +628,6 @@ mod test { let fifth_message = RawCommittedMessage { leaf_index: 4, - committed_root: fourth_root, message: message_vec.clone(), }; let fifth_message_clone_1 = fifth_message.clone(); diff --git a/rust/abacus-base/src/outbox.rs b/rust/abacus-base/src/outbox.rs index d04ee238f..de40ea99c 100644 --- a/rust/abacus-base/src/outbox.rs +++ b/rust/abacus-base/src/outbox.rs @@ -88,10 +88,6 @@ impl CachingOutbox { #[async_trait] impl Outbox for CachingOutbox { - async fn nonces(&self, destination: u32) -> Result { - self.outbox.nonces(destination).await - } - async fn dispatch(&self, message: &Message) -> Result { self.outbox.dispatch(message).await } @@ -111,20 +107,6 @@ impl Outbox for CachingOutbox { #[async_trait] impl OutboxEvents for CachingOutbox { - #[tracing::instrument(err, skip(self))] - async fn raw_message_by_nonce( - &self, - destination: u32, - nonce: u32, - ) -> Result, ChainCommunicationError> { - loop { - if let Some(message) = self.db.message_by_nonce(destination, nonce)? { - return Ok(Some(message)); - } - sleep(Duration::from_millis(500)).await; - } - } - #[tracing::instrument(err, skip(self))] async fn raw_message_by_leaf( &self, @@ -252,15 +234,6 @@ impl From> for Outboxes { #[async_trait] impl Outbox for OutboxVariants { - #[instrument(level = "trace", err)] - async fn nonces(&self, destination: u32) -> Result { - match self { - OutboxVariants::Ethereum(outbox) => outbox.nonces(destination).await, - OutboxVariants::Mock(mock_outbox) => mock_outbox.nonces(destination).await, - OutboxVariants::Other(outbox) => outbox.nonces(destination).await, - } - } - #[instrument(level = "trace", err)] async fn dispatch(&self, message: &Message) -> Result { match self { diff --git a/rust/abacus-core/src/db/abacus_db.rs b/rust/abacus-core/src/db/abacus_db.rs index bcdd2b161..d3b1020d8 100644 --- a/rust/abacus-core/src/db/abacus_db.rs +++ b/rust/abacus-core/src/db/abacus_db.rs @@ -1,7 +1,7 @@ use crate::db::{DbError, TypedDB, DB}; use crate::{ - accumulator::merkle::Proof, traits::RawCommittedMessage, utils, AbacusMessage, - CommittedMessage, Decode, + accumulator::merkle::Proof, traits::RawCommittedMessage, AbacusMessage, CommittedMessage, + Decode, }; use color_eyre::Result; use ethers::core::types::H256; @@ -64,7 +64,6 @@ impl AbacusDB { leaf_index = &committed_message.leaf_index, origin = &committed_message.message.origin, destination = &committed_message.message.destination, - nonce = &committed_message.message.nonce, "Stored new message in db.", ); latest_leaf_index = committed_message.leaf_index; @@ -92,7 +91,6 @@ impl AbacusDB { /// Store a raw committed message /// /// Keys --> Values: - /// - `destination_and_nonce` --> `leaf` /// - `leaf_index` --> `leaf` /// - `leaf` --> `message` pub fn store_raw_committed_message(&self, message: &RawCommittedMessage) -> Result<()> { @@ -102,13 +100,11 @@ impl AbacusDB { debug!( leaf = ?leaf, - destination_and_nonce = parsed.destination_and_nonce(), destination = parsed.destination, - nonce = parsed.nonce, leaf_index = message.leaf_index, "storing raw committed message in db" ); - self.store_leaf(message.leaf_index, parsed.destination, parsed.nonce, leaf)?; + self.store_leaf(message.leaf_index, parsed.destination, leaf)?; self.store_keyed_encodable(MESSAGE, &leaf, message)?; Ok(()) } @@ -155,20 +151,12 @@ impl AbacusDB { } /// Store the leaf keyed by leaf_index - fn store_leaf( - &self, - leaf_index: u32, - destination: u32, - nonce: u32, - leaf: H256, - ) -> Result<(), DbError> { + fn store_leaf(&self, leaf_index: u32, destination: u32, leaf: H256) -> Result<(), DbError> { debug!( leaf_index, leaf = ?leaf, - "storing leaf hash keyed by index and dest+nonce" + "storing leaf hash keyed by index" ); - let destination_and_nonce = utils::destination_and_nonce(destination, nonce); - self.store_keyed_encodable(LEAF, &destination_and_nonce, &leaf)?; self.store_keyed_encodable(LEAF, &leaf_index, &leaf)?; self.update_latest_leaf_index(leaf_index)?; self.update_latest_leaf_index_for_destination(destination, leaf_index) @@ -184,25 +172,6 @@ impl AbacusDB { self.retrieve_keyed_decodable(LEAF, &leaf_index) } - /// Retrieve the leaf hash keyed by destination and nonce - pub fn leaf_by_nonce(&self, destination: u32, nonce: u32) -> Result, DbError> { - let dest_and_nonce = utils::destination_and_nonce(destination, nonce); - self.retrieve_keyed_decodable(LEAF, &dest_and_nonce) - } - - /// Retrieve a raw committed message by its leaf hash - pub fn message_by_nonce( - &self, - destination: u32, - nonce: u32, - ) -> Result, DbError> { - let leaf = self.leaf_by_nonce(destination, nonce)?; - match leaf { - None => Ok(None), - Some(leaf) => self.message_by_leaf(leaf), - } - } - /// Retrieve a raw committed message by its leaf index pub fn message_by_leaf_index( &self, diff --git a/rust/abacus-core/src/test_output.rs b/rust/abacus-core/src/test_output.rs index be59314b1..8feab4cad 100644 --- a/rust/abacus-core/src/test_output.rs +++ b/rust/abacus-core/src/test_output.rs @@ -30,7 +30,6 @@ pub mod output_functions { sender: H256::from( H160::from_str("0x1111111111111111111111111111111111111111").unwrap(), ), - nonce: 1, destination: 2000, recipient: H256::from( H160::from_str("0x2222222222222222222222222222222222222222").unwrap(), @@ -38,14 +37,14 @@ pub mod output_functions { body: Vec::from_hex("1234").unwrap(), }; + let leaf_index = 0; let message_json = json!({ "origin": abacus_message.origin, "sender": abacus_message.sender, "destination": abacus_message.destination, "recipient": abacus_message.recipient, - "nonce": abacus_message.nonce, "body": abacus_message.body, - "messageHash": abacus_message.to_leaf(), + "messageHash": abacus_message.to_leaf(0), }); let json = json!([message_json]).to_string(); diff --git a/rust/abacus-core/src/traits/message.rs b/rust/abacus-core/src/traits/message.rs index 58721f454..2c1f42079 100644 --- a/rust/abacus-core/src/traits/message.rs +++ b/rust/abacus-core/src/traits/message.rs @@ -2,15 +2,14 @@ use std::convert::TryFrom; use crate::{AbacusError, AbacusMessage, Decode, Encode}; use color_eyre::Result; -use ethers::{core::types::H256, utils::keccak256}; +use ethers::core::types::H256; +use sha3::{Digest, Keccak256}; /// A Stamped message that has been committed at some leaf index #[derive(Debug, Default, Clone, PartialEq)] pub struct RawCommittedMessage { /// The index at which the message is committed pub leaf_index: u32, - /// The Outbox's current root when the message was committed. - pub committed_root: H256, /// The fully detailed message that was committed pub message: Vec, } @@ -21,7 +20,15 @@ impl RawCommittedMessage { /// The leaf is the keccak256 digest of the message, which is committed /// in the message tree pub fn leaf(&self) -> H256 { - keccak256(&self.message).into() + let buffer = [0u8; 28]; + H256::from_slice( + Keccak256::new() + .chain(&self.message) + .chain(buffer) + .chain(self.leaf_index.to_be_bytes()) + .finalize() + .as_slice(), + ) } } @@ -31,7 +38,6 @@ impl Encode for RawCommittedMessage { W: std::io::Write, { writer.write_all(&self.leaf_index.to_be_bytes())?; - writer.write_all(self.committed_root.as_ref())?; writer.write_all(&self.message)?; Ok(4 + 32 + self.message.len()) } @@ -46,15 +52,11 @@ impl Decode for RawCommittedMessage { let mut idx = [0u8; 4]; reader.read_exact(&mut idx)?; - let mut hash = [0u8; 32]; - reader.read_exact(&mut hash)?; - let mut message = vec![]; reader.read_to_end(&mut message)?; Ok(Self { leaf_index: u32::from_be_bytes(idx), - committed_root: hash.into(), message, }) } @@ -66,8 +68,6 @@ impl Decode for RawCommittedMessage { pub struct CommittedMessage { /// The index at which the message is committed pub leaf_index: u32, - /// The Outbox's current root when the message was committed. - pub committed_root: H256, /// The fully detailed message that was committed pub message: AbacusMessage, } @@ -75,7 +75,7 @@ pub struct CommittedMessage { impl CommittedMessage { /// Return the leaf associated with the message pub fn to_leaf(&self) -> H256 { - self.message.to_leaf() + self.message.to_leaf(self.leaf_index) } } @@ -91,7 +91,6 @@ impl TryFrom for CommittedMessage { fn try_from(raw: RawCommittedMessage) -> Result { Ok(Self { leaf_index: raw.leaf_index, - committed_root: raw.committed_root, message: AbacusMessage::read_from(&mut &raw.message[..])?, }) } diff --git a/rust/abacus-core/src/traits/outbox.rs b/rust/abacus-core/src/traits/outbox.rs index 7985b3cd5..562588c44 100644 --- a/rust/abacus-core/src/traits/outbox.rs +++ b/rust/abacus-core/src/traits/outbox.rs @@ -15,9 +15,6 @@ pub trait Outbox: AbacusCommon + Send + Sync + std::fmt::Debug { /// Fetch the current state. async fn state(&self) -> Result; - /// Fetch the nonce - async fn nonces(&self, destination: u32) -> Result; - /// Gets the current leaf count of the merkle tree async fn count(&self) -> Result; @@ -34,30 +31,6 @@ pub trait Outbox: AbacusCommon + Send + Sync + std::fmt::Debug { /// Interface for retrieving event data emitted specifically by the outbox #[async_trait] pub trait OutboxEvents: Outbox + Send + Sync + std::fmt::Debug { - /// Fetch the message to destination at the nonce (or error). - /// This should fetch events from the chain API. - /// - /// Used by processors to get messages in order - async fn raw_message_by_nonce( - &self, - destination: u32, - nonce: u32, - ) -> Result, ChainCommunicationError>; - - /// Fetch the message to destination at the nonce (or error). - /// This should fetch events from the chain API - async fn message_by_nonce( - &self, - destination: u32, - nonce: u32, - ) -> Result, ChainCommunicationError> { - self.raw_message_by_nonce(destination, nonce) - .await? - .map(CommittedMessage::try_from) - .transpose() - .map_err(Into::into) - } - /// Look up a message by its hash. /// This should fetch events from the chain API async fn raw_message_by_leaf( diff --git a/rust/abacus-core/src/types/messages.rs b/rust/abacus-core/src/types/messages.rs index 84d0da366..e1a5e96d6 100644 --- a/rust/abacus-core/src/types/messages.rs +++ b/rust/abacus-core/src/types/messages.rs @@ -1,8 +1,9 @@ -use ethers::{types::H256, utils::keccak256}; +use ethers::types::H256; +use sha3::{Digest, Keccak256}; -use crate::{utils, AbacusError, Decode, Encode}; +use crate::{AbacusError, Decode, Encode}; -const ABACUS_MESSAGE_PREFIX_LEN: usize = 76; +const ABACUS_MESSAGE_PREFIX_LEN: usize = 72; /// A full Abacus message between chains #[derive(Debug, Default, Clone)] @@ -11,8 +12,6 @@ pub struct AbacusMessage { pub origin: u32, /// 32 Address in Outbox convention pub sender: H256, - /// 4 Count of all previous messages to destination - pub nonce: u32, /// 4 SLIP-44 ID pub destination: u32, /// 32 Address in destination convention @@ -39,7 +38,6 @@ impl Encode for AbacusMessage { { writer.write_all(&self.origin.to_be_bytes())?; writer.write_all(self.sender.as_ref())?; - writer.write_all(&self.nonce.to_be_bytes())?; writer.write_all(&self.destination.to_be_bytes())?; writer.write_all(self.recipient.as_ref())?; writer.write_all(&self.body)?; @@ -58,9 +56,6 @@ impl Decode for AbacusMessage { let mut sender = H256::zero(); reader.read_exact(sender.as_mut())?; - let mut nonce = [0u8; 4]; - reader.read_exact(&mut nonce)?; - let mut destination = [0u8; 4]; reader.read_exact(&mut destination)?; @@ -75,7 +70,6 @@ impl Decode for AbacusMessage { sender, destination: u32::from_be_bytes(destination), recipient, - nonce: u32::from_be_bytes(nonce), body, }) } @@ -83,22 +77,21 @@ impl Decode for AbacusMessage { impl AbacusMessage { /// Convert the message to a leaf - pub fn to_leaf(&self) -> H256 { - keccak256(self.to_vec()).into() - } - - /// Get the encoded destination + nonce - pub fn destination_and_nonce(&self) -> u64 { - utils::destination_and_nonce(self.destination, self.nonce) + pub fn to_leaf(&self, leaf_index: u32) -> H256 { + let buffer = [0u8; 28]; + H256::from_slice( + Keccak256::new() + .chain(&self.to_vec()) + .chain(buffer) + .chain(leaf_index.to_be_bytes()) + .finalize() + .as_slice(), + ) } } impl std::fmt::Display for AbacusMessage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "AbacusMessage {}->{}:{}", - self.origin, self.destination, self.nonce, - ) + write!(f, "AbacusMessage {}->{}", self.origin, self.destination) } } diff --git a/rust/abacus-test/src/mocks/outbox.rs b/rust/abacus-test/src/mocks/outbox.rs index 223cb8fa4..3826c4fe3 100644 --- a/rust/abacus-test/src/mocks/outbox.rs +++ b/rust/abacus-test/src/mocks/outbox.rs @@ -14,25 +14,16 @@ mock! { pub fn _domain_hash(&self) -> H256 {} - pub fn _raw_message_by_nonce( - &self, - destination: u32, - nonce: u32, - ) -> Result, ChainCommunicationError> {} - pub fn _raw_message_by_leaf( &self, leaf: H256, ) -> Result, ChainCommunicationError> {} - pub fn _leaf_by_tree_index( &self, tree_index: usize, ) -> Result, ChainCommunicationError> {} - pub fn _nonces(&self, destination: u32) -> Result {} - pub fn _dispatch(&self, message: &Message) -> Result {} pub fn _count(&self) -> Result {} @@ -62,10 +53,6 @@ impl std::fmt::Debug for MockOutboxContract { #[async_trait] impl Outbox for MockOutboxContract { - async fn nonces(&self, destination: u32) -> Result { - self._nonces(destination) - } - async fn dispatch(&self, message: &Message) -> Result { self._dispatch(message) } diff --git a/rust/abacus-test/src/test_utils.rs b/rust/abacus-test/src/test_utils.rs index 259205920..9e81a2eff 100644 --- a/rust/abacus-test/src/test_utils.rs +++ b/rust/abacus-test/src/test_utils.rs @@ -51,29 +51,23 @@ mod test { let outbox_name = "outbox_1".to_owned(); let db = AbacusDB::new(outbox_name, db); + let leaf_index = 100; let m = AbacusMessage { origin: 10, sender: H256::from_low_u64_be(4), - nonce: 11, destination: 12, recipient: H256::from_low_u64_be(5), body: vec![1, 2, 3], }; let message = RawCommittedMessage { - leaf_index: 100, - committed_root: H256::from_low_u64_be(3), + leaf_index, message: m.to_vec(), }; - assert_eq!(m.to_leaf(), message.leaf()); - db.store_raw_committed_message(&message).unwrap(); + assert_eq!(m.to_leaf(leaf_index), message.leaf()); - let by_nonce = db - .message_by_nonce(m.destination, m.nonce) - .unwrap() - .unwrap(); - assert_eq!(by_nonce, message); + db.store_raw_committed_message(&message).unwrap(); let by_leaf = db.message_by_leaf(message.leaf()).unwrap().unwrap(); assert_eq!(by_leaf, message); diff --git a/rust/chains/abacus-ethereum/abis/Outbox.abi.json b/rust/chains/abacus-ethereum/abis/Outbox.abi.json index 749657580..a315c1000 100644 --- a/rust/chains/abacus-ethereum/abis/Outbox.abi.json +++ b/rust/chains/abacus-ethereum/abis/Outbox.abi.json @@ -46,15 +46,9 @@ }, { "indexed": true, - "internalType": "uint64", - "name": "destinationAndNonce", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "checkpointedRoot", - "type": "bytes32" + "internalType": "uint32", + "name": "destination", + "type": "uint32" }, { "indexed": false, @@ -286,25 +280,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "owner", diff --git a/rust/chains/abacus-ethereum/src/outbox.rs b/rust/chains/abacus-ethereum/src/outbox.rs index 2c5fa674f..383ef47b2 100644 --- a/rust/chains/abacus-ethereum/src/outbox.rs +++ b/rust/chains/abacus-ethereum/src/outbox.rs @@ -138,7 +138,6 @@ where .into_iter() .map(|f| RawCommittedMessage { leaf_index: f.leaf_index.as_u32(), - committed_root: f.checkpointed_root.into(), message: f.message.to_vec(), }) .collect()) @@ -248,11 +247,6 @@ impl Outbox for EthereumOutbox where M: ethers::providers::Middleware + 'static, { - #[tracing::instrument(err, skip(self))] - async fn nonces(&self, destination: u32) -> Result { - Ok(self.contract.nonces(destination).call().await?) - } - #[tracing::instrument(err, skip(self))] async fn dispatch(&self, message: &Message) -> Result { let tx = self.contract.dispatch( diff --git a/rust/config/test/alfajores_config.json b/rust/config/test/alfajores_config.json index 181ede79e..e1a6dc253 100644 --- a/rust/config/test/alfajores_config.json +++ b/rust/config/test/alfajores_config.json @@ -1,18 +1,6 @@ { "environment": "test", "signers": {}, - "outbox": { - "addresses": { - "outbox": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" - }, - "domain": "1000", - "name": "alfajores", - "rpcStyle": "ethereum", - "connection": { - "type": "http", - "url": "" - } - }, "inboxes": { "kovan": { "domain": "3000", @@ -23,7 +11,7 @@ "url": "" }, "addresses": { - "inbox": "0x851356ae760d987E095750cCeb3bC6014560891C", + "inbox": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", "validatorManager": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933" } }, @@ -36,7 +24,7 @@ "url": "" }, "addresses": { - "inbox": "0x7bc06c482DEAd17c0e297aFbC32f6e63d3846650", + "inbox": "0xb7278A61aa25c888815aFC32Ad3cC52fF24fE575", "validatorManager": "0x4c5859f0F772848b2D91F1D83E2Fe57935348029" } }, @@ -49,11 +37,23 @@ "url": "" }, "addresses": { - "inbox": "0x202CCe504e04bEd6fC0521238dDf04Bc9E8E15aB", + "inbox": "0xD8a5a9b31c3C0232E196d518E89Fd8bF83AcAd43", "validatorManager": "0x4C4a2f8c81640e47606d3fd77B353E87Ba015584" } } }, + "outbox": { + "addresses": { + "outbox": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" + }, + "domain": "1000", + "name": "alfajores", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, "tracing": { "level": "debug", "fmt": "json" diff --git a/rust/config/test/fuji_config.json b/rust/config/test/fuji_config.json index 170dc287a..1a1673729 100644 --- a/rust/config/test/fuji_config.json +++ b/rust/config/test/fuji_config.json @@ -3,38 +3,49 @@ "signers": {}, "inboxes": { "alfajores": { - "address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c", "domain": "1000", "name": "alfajores", "rpcStyle": "ethereum", "connection": { "type": "http", "url": "" + }, + "addresses": { + "inbox": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed", + "validatorManager": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE" } }, "kovan": { - "address": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49", "domain": "3000", "name": "kovan", "rpcStyle": "ethereum", "connection": { "type": "http", "url": "" + }, + "addresses": { + "inbox": "0x95401dc811bb5740090279Ba06cfA8fcF6113778", + "validatorManager": "0xf5059a5D33d5853360D16C683c16e67980206f36" } }, "mumbai": { - "address": "0x1429859428C0aBc9C2C47C8Ee9FBaf82cFA0F20f", "domain": "80001", "name": "mumbai", "rpcStyle": "ethereum", "connection": { "type": "http", "url": "" + }, + "addresses": { + "inbox": "0xc351628EB244ec633d5f21fBD6621e1a683B1181", + "validatorManager": "0x7bc06c482DEAd17c0e297aFbC32f6e63d3846650" } } }, "outbox": { - "address": "0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2", + "addresses": { + "outbox": "0x922D6956C99E12DFeB3224DEA977D0939758A1Fe" + }, "domain": "43113", "name": "fuji", "rpcStyle": "ethereum", @@ -48,4 +59,4 @@ "fmt": "json" }, "db": "db_path" -} \ No newline at end of file +} diff --git a/rust/config/test/kovan_config.json b/rust/config/test/kovan_config.json index 55137d115..8c84e4553 100644 --- a/rust/config/test/kovan_config.json +++ b/rust/config/test/kovan_config.json @@ -3,38 +3,49 @@ "signers": {}, "inboxes": { "alfajores": { - "address": "0x0B306BF915C4d645ff596e518fAf3F9669b97016", "domain": "1000", "name": "alfajores", "rpcStyle": "ethereum", "connection": { "type": "http", "url": "" + }, + "addresses": { + "inbox": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0", + "validatorManager": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" } }, "mumbai": { - "address": "0xFD471836031dc5108809D173A067e8486B9047A3", "domain": "80001", "name": "mumbai", "rpcStyle": "ethereum", "connection": { "type": "http", "url": "" + }, + "addresses": { + "inbox": "0x2bdCC0de6bE1f7D2ee689a0342D76F52E8EFABa3", + "validatorManager": "0x82e01223d51Eb87e16A03E24687EDF0F294da6f1" } }, "fuji": { - "address": "0x172076E0166D1F9Cc711C77Adf8488051744980C", "domain": "43113", "name": "fuji", "rpcStyle": "ethereum", "connection": { "type": "http", "url": "" + }, + "addresses": { + "inbox": "0x36b58F5C1969B7b6591D752ea6F5486D069010AB", + "validatorManager": "0x51A1ceB83B83F1985a81C295d1fF28Afef186E02" } } }, "outbox": { - "address": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933", + "addresses": { + "outbox": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f" + }, "domain": "3000", "name": "kovan", "rpcStyle": "ethereum", @@ -48,4 +59,4 @@ "fmt": "json" }, "db": "db_path" -} \ No newline at end of file +} diff --git a/rust/config/test/mumbai_config.json b/rust/config/test/mumbai_config.json index 66e69aadf..a76f7065d 100644 --- a/rust/config/test/mumbai_config.json +++ b/rust/config/test/mumbai_config.json @@ -3,38 +3,49 @@ "signers": {}, "inboxes": { "alfajores": { - "address": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE", "domain": "1000", "name": "alfajores", "rpcStyle": "ethereum", "connection": { "type": "http", "url": "" + }, + "addresses": { + "inbox": "0x0B306BF915C4d645ff596e518fAf3F9669b97016", + "validatorManager": "0x9A676e781A523b5d0C0e43731313A708CB607508" } }, "kovan": { - "address": "0x95401dc811bb5740090279Ba06cfA8fcF6113778", "domain": "3000", "name": "kovan", "rpcStyle": "ethereum", "connection": { "type": "http", "url": "" + }, + "addresses": { + "inbox": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8", + "validatorManager": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9" } }, "fuji": { - "address": "0xBEc49fA140aCaA83533fB00A2BB19bDdd0290f25", "domain": "43113", "name": "fuji", "rpcStyle": "ethereum", "connection": { "type": "http", "url": "" + }, + "addresses": { + "inbox": "0x202CCe504e04bEd6fC0521238dDf04Bc9E8E15aB", + "validatorManager": "0x0355B7B8cb128fA5692729Ab3AAa199C1753f726" } } }, "outbox": { - "address": "0x1291Be112d480055DaFd8a610b7d1e203891C274", + "addresses": { + "outbox": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf" + }, "domain": "80001", "name": "mumbai", "rpcStyle": "ethereum", @@ -48,4 +59,4 @@ "fmt": "json" }, "db": "db_path" -} \ No newline at end of file +} diff --git a/rust/tools/abacus-cli/src/commands.rs b/rust/tools/abacus-cli/src/commands.rs index a878733b1..71d6da7d8 100644 --- a/rust/tools/abacus-cli/src/commands.rs +++ b/rust/tools/abacus-cli/src/commands.rs @@ -1,11 +1,9 @@ use structopt::StructOpt; -use crate::subcommands::{db_state::DbStateCommand, prove::ProveCommand}; +use crate::subcommands::prove::ProveCommand; #[derive(StructOpt)] pub enum Commands { /// Prove a message on an inbox for a given leaf index Prove(ProveCommand), - /// Print the processor's db state - DbState(DbStateCommand), } diff --git a/rust/tools/abacus-cli/src/main.rs b/rust/tools/abacus-cli/src/main.rs index 7ee381b52..aefc60dec 100644 --- a/rust/tools/abacus-cli/src/main.rs +++ b/rust/tools/abacus-cli/src/main.rs @@ -14,6 +14,5 @@ async fn main() -> Result<()> { match command { Commands::Prove(prove) => prove.run().await, - Commands::DbState(db_state) => db_state.run().await, } } diff --git a/rust/tools/abacus-cli/src/subcommands/db_state.rs b/rust/tools/abacus-cli/src/subcommands/db_state.rs deleted file mode 100644 index c52542b51..000000000 --- a/rust/tools/abacus-cli/src/subcommands/db_state.rs +++ /dev/null @@ -1,164 +0,0 @@ -use color_eyre::Result; -use serde_json::{json, Value}; -use std::{collections::HashMap, convert::TryInto, fs::OpenOptions, io::Write}; -use structopt::StructOpt; - -use abacus_core::{ - db::{AbacusDB, DB}, - CommittedMessage, -}; - -use ethers::types::H256; - -#[derive(StructOpt, Debug)] -pub struct DbStateCommand { - /// Path to processor db - #[structopt(long)] - db_path: String, - - /// Name of associated outbox - #[structopt(long)] - outbox_name: String, - - /// Save output to json file - #[structopt(long)] - json: bool, -} - -type OutputVec = Vec<((H256, u64), Vec)>; - -impl DbStateCommand { - pub async fn run(&self) -> Result<()> { - let db = AbacusDB::new(&self.outbox_name, DB::from_path(&self.db_path)?); - - let messages_by_committed_roots = self.create_comitted_root_to_message_map(&db)?; - - let output_vec = self.create_output_vec(&db, messages_by_committed_roots)?; - - if self.json { - DbStateCommand::save_to_json(output_vec)?; - } else { - DbStateCommand::print_output(output_vec); - } - - Ok(()) - } - - fn create_comitted_root_to_message_map( - &self, - db: &AbacusDB, - ) -> Result>> { - let mut messages_by_committed_roots: HashMap> = HashMap::new(); - for index in 0.. { - match db.message_by_leaf_index(index)? { - Some(message) => { - if db.proof_by_leaf_index(index)?.is_none() { - println!("Failed to find proof for leaf index {}!", index); - } - - let committed_root = message.committed_root; - let bucket_opt = messages_by_committed_roots.get_mut(&committed_root); - - // Get reference to bucket for committed root - let bucket = match bucket_opt { - Some(bucket) => bucket, - None => { - messages_by_committed_roots - .insert(committed_root, Vec::::new()); - messages_by_committed_roots - .get_mut(&committed_root) - .unwrap() - } - }; - - // Add message to bucket for committed root - bucket.push(message.try_into()?); - } - None => break, - } - } - - Ok(messages_by_committed_roots) - } - - // TODO: We currently aren't indexing checkpoints, which are the successor - // of updates, so this cannot be implemented right now. Once checkpoint indexing - // is added, we should implement this for Abacus. - // The Optics-specific code is commented out as a reference for the future move - // to Abacus-specific code. - fn create_output_vec( - &self, - _db: &AbacusDB, - _messages_by_committed_roots: HashMap>, - ) -> Result { - // Create mapping of (update root, block_number) to [messages] - let output_map: HashMap<(H256, u64), Vec> = HashMap::new(); - // for (committed_root, bucket) in messages_by_committed_roots { - // let containing_update_opt = db.update_by_previous_root(committed_root)?; - - // match containing_update_opt { - // Some(containing_update) => { - // let new_root = containing_update.update.new_root; - // let update_metadata = - // db.retrieve_update_metadata(new_root)?.unwrap_or_else(|| { - // panic!("Couldn't find metadata for update {:?}", containing_update) - // }); - - // output_map.insert((new_root, update_metadata.block_number), bucket); - // } - // // No more updates left - // None => break, - // } - // } - - // Convert hashmap into vector of k,v pairs and sort the entries by - // update block number - let mut output_vec: Vec<_> = output_map.into_iter().collect(); - output_vec.sort_by(|x, y| x.0 .1.cmp(&y.0 .1)); - - Ok(output_vec) - } - - fn print_output(output_vec: OutputVec) { - for ((update_root, block_number), mut bucket) in output_vec { - println!("Update root: {:?}", update_root); - println!("Block number: {}", block_number); - - bucket.sort_by(|x, y| x.leaf_index.cmp(&y.leaf_index)); - print!("Leaves:"); - for message in bucket { - print!(" {} ", message.leaf_index); - } - - println!("\n"); - } - } - - fn save_to_json(output_vec: OutputVec) -> Result<()> { - let mut json_entries: Vec = Vec::new(); - for ((update_root, block_number), mut bucket) in output_vec { - bucket.sort_by(|x, y| x.leaf_index.cmp(&y.leaf_index)); - let leaf_indexes: Vec<_> = bucket.iter().map(|leaf| leaf.leaf_index).collect(); - - json_entries.push(json!({ - "updateRoot": update_root, - "blockNumber": block_number, - "leaves": leaf_indexes, - })); - } - - let json = json!(json_entries).to_string(); - - let mut file = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open("dbState.json") - .expect("Failed to open/create file"); - - file.write_all(json.as_bytes()) - .expect("Failed to write to file"); - - Ok(()) - } -} diff --git a/rust/tools/abacus-cli/src/subcommands/mod.rs b/rust/tools/abacus-cli/src/subcommands/mod.rs index edb59f8fd..8de45b087 100644 --- a/rust/tools/abacus-cli/src/subcommands/mod.rs +++ b/rust/tools/abacus-cli/src/subcommands/mod.rs @@ -1,5 +1,3 @@ -pub mod db_state; pub mod prove; -pub use db_state::*; pub use prove::*; diff --git a/rust/tools/abacus-cli/src/subcommands/prove.rs b/rust/tools/abacus-cli/src/subcommands/prove.rs index a4df6f146..6336ef46d 100644 --- a/rust/tools/abacus-cli/src/subcommands/prove.rs +++ b/rust/tools/abacus-cli/src/subcommands/prove.rs @@ -71,7 +71,9 @@ impl ProveCommand { let (message, proof) = self.fetch_proof(db)?; let inbox = self.inbox(message.origin, message.destination).await?; - let status = inbox.message_status(message.to_leaf()).await?; + let status = inbox + .message_status(message.to_leaf(self.leaf_index.unwrap())) + .await?; let outcome = match status { MessageStatus::None => inbox.process(&message, &proof).await?, _ => { diff --git a/solidity/core/contracts/Inbox.sol b/solidity/core/contracts/Inbox.sol index 16075741a..061d277a5 100644 --- a/solidity/core/contracts/Inbox.sol +++ b/solidity/core/contracts/Inbox.sol @@ -116,7 +116,7 @@ contract Inbox is IInbox, Version0, Common { require(entered == 1, "!reentrant"); entered = 0; - bytes32 _messageHash = keccak256(_message); + bytes32 _messageHash = keccak256(abi.encodePacked(_message, _index)); // ensure that message has not been processed require( messages[_messageHash] == MessageStatus.None, diff --git a/solidity/core/contracts/Outbox.sol b/solidity/core/contracts/Outbox.sol index 8a9ca7f81..31d5b18fc 100644 --- a/solidity/core/contracts/Outbox.sol +++ b/solidity/core/contracts/Outbox.sol @@ -48,13 +48,11 @@ contract Outbox is IOutbox, Version0, MerkleTreeManager, Common { // Current state of contract States public state; - // domain => next available nonce for the domain - mapping(uint32 => uint32) public nonces; // ============ Upgrade Gap ============ // gap for upgrade safety - uint256[48] private __GAP; + uint256[49] private __GAP; // ============ Events ============ @@ -62,17 +60,13 @@ contract Outbox is IOutbox, Version0, MerkleTreeManager, Common { * @notice Emitted when a new message is dispatched via Abacus * @param messageHash Hash of message; the leaf inserted to the Merkle tree for the message * @param leafIndex Index of message's leaf in merkle tree - * @param destinationAndNonce Destination and destination-specific - * nonce combined in single field ((destination << 32) & nonce) - * @param checkpointedRoot the latest checkpointed root + * @param destination Destination domain * @param message Raw bytes of message */ event Dispatch( bytes32 indexed messageHash, uint256 indexed leafIndex, - uint64 indexed destinationAndNonce, - // Remove checkpointedRoot. - bytes32 checkpointedRoot, + uint32 indexed destination, bytes message ); @@ -116,31 +110,23 @@ contract Outbox is IOutbox, Version0, MerkleTreeManager, Common { bytes memory _messageBody ) external override notFailed returns (uint256) { require(_messageBody.length <= MAX_MESSAGE_BODY_BYTES, "msg too long"); - // get the next nonce for the destination domain, then increment it - uint32 _nonce = nonces[_destinationDomain]; - nonces[_destinationDomain] = _nonce + 1; + // The leaf has not been inserted yet at this point1 + uint256 _leafIndex = count(); // format the message into packed bytes bytes memory _message = Message.formatMessage( localDomain, bytes32(uint256(uint160(msg.sender))), - _nonce, _destinationDomain, _recipientAddress, _messageBody ); - // The leaf has not been inserted yet at this point - uint256 _leafIndex = count(); // insert the hashed message into the Merkle tree - bytes32 _messageHash = keccak256(_message); + bytes32 _messageHash = keccak256( + abi.encodePacked(_message, _leafIndex) + ); tree.insert(_messageHash); // Emit Dispatch event with message information - emit Dispatch( - _messageHash, - _leafIndex, - _destinationAndNonce(_destinationDomain, _nonce), - checkpointedRoot, - _message - ); + emit Dispatch(_messageHash, _leafIndex, _destinationDomain, _message); return _leafIndex; } diff --git a/solidity/core/contracts/test/TestInbox.sol b/solidity/core/contracts/test/TestInbox.sol index b70229b97..ecd65de74 100644 --- a/solidity/core/contracts/test/TestInbox.sol +++ b/solidity/core/contracts/test/TestInbox.sol @@ -22,8 +22,8 @@ contract TestInbox is Inbox { return MerkleLib.branchRoot(leaf, proof, index); } - function testProcess(bytes calldata _message) external { - bytes32 _messageHash = keccak256(_message); + function testProcess(bytes calldata _message, uint256 leafIndex) external { + bytes32 _messageHash = keccak256(abi.encodePacked(_message, leafIndex)); _process(_message, _messageHash); } diff --git a/solidity/core/contracts/test/TestMessage.sol b/solidity/core/contracts/test/TestMessage.sol index e801b7748..ba7270acd 100644 --- a/solidity/core/contracts/test/TestMessage.sol +++ b/solidity/core/contracts/test/TestMessage.sol @@ -21,10 +21,6 @@ contract TestMessage { return _message.ref(0).sender(); } - function nonce(bytes memory _message) external pure returns (uint32) { - return _message.ref(0).nonce(); - } - function destination(bytes memory _message) external pure returns (uint32) { return _message.ref(0).destination(); } @@ -41,7 +37,11 @@ contract TestMessage { return _message.ref(0).recipientAddress(); } - function leaf(bytes memory _message) external view returns (bytes32) { - return _message.ref(0).leaf(); + function leaf(bytes memory _message, uint256 _leafIndex) + external + view + returns (bytes32) + { + return _message.ref(0).leaf(_leafIndex); } } diff --git a/solidity/core/libs/Message.sol b/solidity/core/libs/Message.sol index b96ce0ef9..c87ceda85 100644 --- a/solidity/core/libs/Message.sol +++ b/solidity/core/libs/Message.sol @@ -15,13 +15,12 @@ library Message { using TypedMemView for bytes29; // Number of bytes in formatted message before `body` field - uint256 internal constant PREFIX_LENGTH = 76; + uint256 internal constant PREFIX_LENGTH = 72; /** * @notice Returns formatted (packed) message with provided fields * @param _originDomain Domain of home chain * @param _sender Address of sender as bytes32 - * @param _nonce Destination-specific nonce * @param _destinationDomain Domain of destination chain * @param _recipient Address of recipient on destination chain as bytes32 * @param _messageBody Raw bytes of message body @@ -30,7 +29,6 @@ library Message { function formatMessage( uint32 _originDomain, bytes32 _sender, - uint32 _nonce, uint32 _destinationDomain, bytes32 _recipient, bytes memory _messageBody @@ -39,7 +37,6 @@ library Message { abi.encodePacked( _originDomain, _sender, - _nonce, _destinationDomain, _recipient, _messageBody @@ -50,29 +47,31 @@ library Message { * @notice Returns leaf of formatted message with provided fields. * @param _origin Domain of home chain * @param _sender Address of sender as bytes32 - * @param _nonce Destination-specific nonce number * @param _destination Domain of destination chain * @param _recipient Address of recipient on destination chain as bytes32 * @param _body Raw bytes of message body + * @param _leafIndex Index of the message in the tree * @return Leaf (hash) of formatted message **/ function messageHash( uint32 _origin, bytes32 _sender, - uint32 _nonce, uint32 _destination, bytes32 _recipient, - bytes memory _body + bytes memory _body, + uint256 _leafIndex ) internal pure returns (bytes32) { return keccak256( - formatMessage( - _origin, - _sender, - _nonce, - _destination, - _recipient, - _body + abi.encodePacked( + formatMessage( + _origin, + _sender, + _destination, + _recipient, + _body + ), + _leafIndex ) ); } @@ -87,19 +86,14 @@ library Message { return _message.index(4, 32); } - /// @notice Returns message's nonce field - function nonce(bytes29 _message) internal pure returns (uint32) { - return uint32(_message.indexUint(36, 4)); - } - /// @notice Returns message's destination field function destination(bytes29 _message) internal pure returns (uint32) { - return uint32(_message.indexUint(40, 4)); + return uint32(_message.indexUint(36, 4)); } /// @notice Returns message's recipient field as bytes32 function recipient(bytes29 _message) internal pure returns (bytes32) { - return _message.index(44, 32); + return _message.index(40, 32); } /// @notice Returns message's recipient field as an address @@ -116,15 +110,19 @@ library Message { return _message.slice(PREFIX_LENGTH, _message.len() - PREFIX_LENGTH, 0); } - function leaf(bytes29 _message) internal view returns (bytes32) { + function leaf(bytes29 _message, uint256 _leafIndex) + internal + view + returns (bytes32) + { return messageHash( origin(_message), sender(_message), - nonce(_message), destination(_message), recipient(_message), - TypedMemView.clone(body(_message)) + TypedMemView.clone(body(_message)), + _leafIndex ); } } diff --git a/solidity/core/test/inbox.test.ts b/solidity/core/test/inbox.test.ts index ec121156d..d95df8d27 100644 --- a/solidity/core/test/inbox.test.ts +++ b/solidity/core/test/inbox.test.ts @@ -19,7 +19,7 @@ import { MessageStatus } from '@abacus-network/utils/dist/src/types'; const proveAndProcessTestCases = require('../../../vectors/proveAndProcess.json'); const messageWithProof = require('../../../vectors/messageWithProof.json'); -const localDomain = 2000; +const localDomain = 3000; const remoteDomain = 1000; describe('Inbox', async () => { @@ -149,54 +149,52 @@ describe('Inbox', async () => { const factory = new badRecipientFactories[i](signer); const badRecipient = await factory.deploy(); - const nonce = 0; + const leafIndex = 0; const abacusMessage = utils.formatMessage( remoteDomain, sender.address, - nonce, + localDomain, badRecipient.address, '0x', ); - await expect(inbox.testProcess(abacusMessage)).to.be.reverted; + await expect(inbox.testProcess(abacusMessage, leafIndex)).to.be.reverted; }); } it('Fails to process message with wrong destination Domain', async () => { const [sender, recipient] = await ethers.getSigners(); - const nonce = 0; const body = ethers.utils.formatBytes32String('message'); + const leafIndex = 0; const abacusMessage = utils.formatMessage( remoteDomain, sender.address, - nonce, // Wrong destination Domain localDomain + 5, recipient.address, body, ); - await expect(inbox.testProcess(abacusMessage)).to.be.revertedWith( - '!destination', - ); + await expect( + inbox.testProcess(abacusMessage, leafIndex), + ).to.be.revertedWith('!destination'); }); it('Fails to process message sent to a non-existent contract address', async () => { - const nonce = 0; const body = ethers.utils.formatBytes32String('message'); + const leafIndex = 0; const abacusMessage = utils.formatMessage( remoteDomain, abacusMessageSender.address, - nonce, localDomain, '0x1234567890123456789012345678901234567890', // non-existent contract address body, ); - await expect(inbox.testProcess(abacusMessage)).to.be.reverted; + await expect(inbox.testProcess(abacusMessage, leafIndex)).to.be.reverted; }); it('Fails to process a message for bad handler function', async () => { @@ -205,18 +203,17 @@ describe('Inbox', async () => { const factory = new BadRecipientHandle__factory(recipient); const testRecipient = await factory.deploy(); - const nonce = 0; + const leafIndex = 0; const abacusMessage = utils.formatMessage( remoteDomain, sender.address, - nonce, localDomain, testRecipient.address, '0x', ); // Ensure bad handler function causes process to fail - await expect(inbox.testProcess(abacusMessage)).to.be.reverted; + await expect(inbox.testProcess(abacusMessage, leafIndex)).to.be.reverted; }); it('Processes a message directly', async () => { @@ -225,19 +222,18 @@ describe('Inbox', async () => { const factory = new TestRecipient__factory(recipient); const testRecipient = await factory.deploy(); - const nonce = 0; + const leafIndex = 0; const abacusMessage = utils.formatMessage( remoteDomain, sender.address, - nonce, localDomain, testRecipient.address, '0x', ); - await inbox.testProcess(abacusMessage); + await inbox.testProcess(abacusMessage, leafIndex); - const hash = utils.messageHash(abacusMessage); + const hash = utils.messageHash(abacusMessage, leafIndex); expect(await inbox.messages(hash)).to.eql(MessageStatus.PROCESSED); }); @@ -246,14 +242,12 @@ describe('Inbox', async () => { const testRecipientFactory = new TestRecipient__factory(signer); const testRecipient = await testRecipientFactory.deploy(); - const nonce = 0; - + const leafIndex = 0; // Note that hash of this message specifically matches leaf of 1st // proveAndProcess test case const abacusMessage = utils.formatMessage( remoteDomain, sender.address, - nonce, localDomain, testRecipient.address, '0x', @@ -261,7 +255,7 @@ describe('Inbox', async () => { // Assert above message and test case have matching leaves const { path, index } = proveAndProcessTestCases[0]; - const hash = utils.messageHash(abacusMessage); + const hash = utils.messageHash(abacusMessage, leafIndex); // Set inbox's current root to match newly computed root that includes // the new leaf (normally root will have already been computed and path diff --git a/solidity/core/test/message.test.ts b/solidity/core/test/message.test.ts index 4c3e94917..9329f45f1 100644 --- a/solidity/core/test/message.test.ts +++ b/solidity/core/test/message.test.ts @@ -20,13 +20,11 @@ describe('Message', async () => { it('Returns fields from a message', async () => { const [sender, recipient] = await ethers.getSigners(); - const nonce = 1; const body = ethers.utils.formatBytes32String('message'); const message = utils.formatMessage( remoteDomain, sender.address, - nonce, localDomain, recipient.address, body, @@ -36,7 +34,6 @@ describe('Message', async () => { expect(await messageLib.sender(message)).to.equal( utils.addressToBytes32(sender.address), ); - expect(await messageLib.nonce(message)).to.equal(nonce); expect(await messageLib.destination(message)).to.equal(localDomain); expect(await messageLib.recipient(message)).to.equal( utils.addressToBytes32(recipient.address), @@ -50,15 +47,14 @@ describe('Message', async () => { it('Matches Rust-output AbacusMessage and leaf', async () => { const origin = 1000; const sender = '0x1111111111111111111111111111111111111111'; - const nonce = 1; const destination = 2000; const recipient = '0x2222222222222222222222222222222222222222'; const body = '0x1234'; + const leafIndex = 0; const abacusMessage = utils.formatMessage( origin, sender, - nonce, destination, recipient, body, @@ -67,7 +63,6 @@ describe('Message', async () => { const { origin: testOrigin, sender: testSender, - nonce: testNonce, destination: testDestination, recipient: testRecipient, body: testBody, @@ -76,7 +71,6 @@ describe('Message', async () => { expect(await messageLib.origin(abacusMessage)).to.equal(testOrigin); expect(await messageLib.sender(abacusMessage)).to.equal(testSender); - expect(await messageLib.nonce(abacusMessage)).to.equal(testNonce); expect(await messageLib.destination(abacusMessage)).to.equal( testDestination, ); @@ -84,7 +78,9 @@ describe('Message', async () => { expect(await messageLib.body(abacusMessage)).to.equal( ethers.utils.hexlify(testBody), ); - expect(await messageLib.leaf(abacusMessage)).to.equal(messageHash); - expect(utils.messageHash(abacusMessage)).to.equal(messageHash); + expect(await messageLib.leaf(abacusMessage, leafIndex)).to.equal( + messageHash, + ); + expect(utils.messageHash(abacusMessage, leafIndex)).to.equal(messageHash); }); }); diff --git a/solidity/core/test/outbox.test.ts b/solidity/core/test/outbox.test.ts index e67eb1517..8b96390a7 100644 --- a/solidity/core/test/outbox.test.ts +++ b/solidity/core/test/outbox.test.ts @@ -58,30 +58,23 @@ describe('Outbox', async () => { describe('#dispatch', () => { const testMessageValues = async () => { const message = ethers.utils.formatBytes32String('message'); - const nonce = await outbox.nonces(localDomain); - - // Format data that will be emitted from Dispatch event - const destAndNonce = utils.destinationAndNonce(destDomain, nonce); const abacusMessage = utils.formatMessage( localDomain, signer.address, - nonce, destDomain, recipient.address, message, ); - const hash = utils.messageHash(abacusMessage); const leafIndex = await outbox.tree(); - const [checkpointedRoot] = await outbox.latestCheckpoint(); + const hash = utils.messageHash(abacusMessage, leafIndex.toNumber()); return { message, - destAndNonce, + destDomain, abacusMessage, hash, leafIndex, - checkpointedRoot, }; }; @@ -97,14 +90,8 @@ describe('Outbox', async () => { }); it('Dispatches a message', async () => { - const { - message, - destAndNonce, - abacusMessage, - hash, - leafIndex, - checkpointedRoot, - } = await testMessageValues(); + const { message, destDomain, abacusMessage, hash, leafIndex } = + await testMessageValues(); // Send message with signer address as msg.sender await expect( @@ -117,13 +104,7 @@ describe('Outbox', async () => { ), ) .to.emit(outbox, 'Dispatch') - .withArgs( - hash, - leafIndex, - destAndNonce, - checkpointedRoot, - abacusMessage, - ); + .withArgs(hash, leafIndex, destDomain, abacusMessage); }); it('Returns the leaf index of the dispatched message', async () => { diff --git a/typescript/hardhat/src/TestAbacusDeploy.ts b/typescript/hardhat/src/TestAbacusDeploy.ts index 9fa25ed8d..8239a7257 100644 --- a/typescript/hardhat/src/TestAbacusDeploy.ts +++ b/typescript/hardhat/src/TestAbacusDeploy.ts @@ -176,13 +176,16 @@ export class TestAbacusDeploy extends TestDeploy< const dispatchFilter = outbox.filters.Dispatch(); const dispatches = await outbox.queryFilter(dispatchFilter); for (const dispatch of dispatches) { - const destination = dispatch.args.destinationAndNonce.shr(32).toNumber(); + const destination = dispatch.args.destination; if (destination === origin) throw new Error("Dispatched message to local domain"); const inbox = this.inbox(origin, destination); const status = await inbox.messages(dispatch.args.messageHash); if (status !== types.MessageStatus.PROCESSED) { - const response = await inbox.testProcess(dispatch.args.message); + const response = await inbox.testProcess( + dispatch.args.message, + dispatch.args.leafIndex.toNumber() + ); let destinationResponses = responses.get(destination) || []; destinationResponses.push(response); responses.set(destination, destinationResponses); diff --git a/typescript/sdk/src/core/message.ts b/typescript/sdk/src/core/message.ts index 0c1ac4ea8..51c4a7063 100644 --- a/typescript/sdk/src/core/message.ts +++ b/typescript/sdk/src/core/message.ts @@ -26,7 +26,6 @@ import { export type ParsedMessage = { origin: number; sender: string; - nonce: number; destination: number; recipient: string; body: string; @@ -66,11 +65,10 @@ export function parseMessage(message: string): ParsedMessage { const buf = Buffer.from(arrayify(message)); const origin = buf.readUInt32BE(0); const sender = hexlify(buf.slice(4, 36)); - const nonce = buf.readUInt32BE(36); - const destination = buf.readUInt32BE(40); - const recipient = hexlify(buf.slice(44, 76)); - const body = hexlify(buf.slice(76)); - return { origin, sender, nonce, destination, recipient, body }; + const destination = buf.readUInt32BE(36); + const recipient = hexlify(buf.slice(40, 72)); + const body = hexlify(buf.slice(72)); + return { origin, sender, destination, recipient, body }; } /** @@ -437,13 +435,6 @@ export class AbacusMessage { return this.message.sender; } - /** - * The domain nonce for this message - */ - get nonce(): number { - return this.message.nonce; - } - /** * The destination domain for this message */ diff --git a/typescript/sdk/test/gas/calculator.test.ts b/typescript/sdk/test/gas/calculator.test.ts index 404c16841..d2eab66e2 100644 --- a/typescript/sdk/test/gas/calculator.test.ts +++ b/typescript/sdk/test/gas/calculator.test.ts @@ -73,7 +73,6 @@ describe('InterchainGasCalculator', () => { const message: ParsedMessage = { origin: originDomain, sender: zeroAddressBytes32, - nonce: 0, destination: destinationDomain, recipient: zeroAddressBytes32, body: '0x12345678', diff --git a/typescript/utils/src/utils.ts b/typescript/utils/src/utils.ts index 48ae716ea..d6ccacdcd 100644 --- a/typescript/utils/src/utils.ts +++ b/typescript/utils/src/utils.ts @@ -51,7 +51,6 @@ export function formatCallData< export const formatMessage = ( localDomain: Domain, senderAddr: Address, - sequence: number, destinationDomain: Domain, recipientAddr: Address, body: HexString, @@ -60,13 +59,16 @@ export const formatMessage = ( recipientAddr = addressToBytes32(recipientAddr); return ethers.utils.solidityPack( - ['uint32', 'bytes32', 'uint32', 'uint32', 'bytes32', 'bytes'], - [localDomain, senderAddr, sequence, destinationDomain, recipientAddr, body], + ['uint32', 'bytes32', 'uint32', 'bytes32', 'bytes'], + [localDomain, senderAddr, destinationDomain, recipientAddr, body], ); }; -export function messageHash(message: HexString): string { - return ethers.utils.solidityKeccak256(['bytes'], [message]); +export function messageHash(message: HexString, leafIndex: number): string { + return ethers.utils.solidityKeccak256( + ['bytes', 'uint256'], + [message, leafIndex], + ); } export function destinationAndNonce( diff --git a/vectors/message.json b/vectors/message.json index 907f72ce6..a54e2e85f 100644 --- a/vectors/message.json +++ b/vectors/message.json @@ -1,12 +1,8 @@ [ { - "body": [ - 18, - 52 - ], + "body": [18, 52], "destination": 2000, - "messageHash": "0x31def026c93f999e8beacc858eb138c6ed85e1d6db7928786a5f72cb70836316", - "nonce": 1, + "messageHash": "0xab444826d49ee7fa7521d4a1587b4b25197edd8a43b42307160afb4bf4232157", "origin": 1000, "recipient": "0x0000000000000000000000002222222222222222222222222222222222222222", "sender": "0x0000000000000000000000001111111111111111111111111111111111111111" diff --git a/vectors/messageWithProof.json b/vectors/messageWithProof.json index 0e7f706e3..4862d7d12 100644 --- a/vectors/messageWithProof.json +++ b/vectors/messageWithProof.json @@ -1,10 +1,10 @@ { - "leaf": "0x07e012e0b6de0a26db2267eecb0c677ac48e581d8141c2e76bbfa453bba2871e", + "leaf": "0x2355bc79d0a43a0e3f3872b88c71899ad3a1eec150168f66643226464da8df63", "index": 0, "proof": [ - "0xd617f1d4e0e7162d7d484ad95a2e4ba4fc4b532b97b04dd0545d16d8ad99dd79", - "0x5ab30f4218ff80164db21b0f917c2b219cf46c781b4b09739caf1238a8ab9f91", - "0x5be03a46bfae6872cd3833b65a5fde75cad34ea5b33f84d5ab452cdeeaac0020", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5", + "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", @@ -35,6 +35,6 @@ "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" ], - "message": "0x000003e8000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000007d00000000000000000000000002b0d36facd61b71cc05ab8f3d2355ec3631c0dd51234", - "root": "0x4832efe713a444c06636cd38325c9be3ab06061db0489ecf18a97ec25d12bd22" + "message": "0x000003e8000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000bb8000000000000000000000000172076e0166d1f9cc711c77adf8488051744980c", + "root": "0xf190f8550f2b978bd0aac64d393a1f7721b1c593e4f3751356b7a020d00d5963" }