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
pull/354/head
Nam Chu Hoai 3 years ago committed by GitHub
parent 0216d28dcf
commit dc6abedc1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      rust/abacus-base/src/contract_sync/mod.rs
  2. 27
      rust/abacus-base/src/outbox.rs
  3. 41
      rust/abacus-core/src/db/abacus_db.rs
  4. 5
      rust/abacus-core/src/test_output.rs
  5. 25
      rust/abacus-core/src/traits/message.rs
  6. 27
      rust/abacus-core/src/traits/outbox.rs
  7. 37
      rust/abacus-core/src/types/messages.rs
  8. 13
      rust/abacus-test/src/mocks/outbox.rs
  9. 14
      rust/abacus-test/src/test_utils.rs
  10. 31
      rust/chains/abacus-ethereum/abis/Outbox.abi.json
  11. 6
      rust/chains/abacus-ethereum/src/outbox.rs
  12. 30
      rust/config/test/alfajores_config.json
  13. 21
      rust/config/test/fuji_config.json
  14. 21
      rust/config/test/kovan_config.json
  15. 21
      rust/config/test/mumbai_config.json
  16. 4
      rust/tools/abacus-cli/src/commands.rs
  17. 1
      rust/tools/abacus-cli/src/main.rs
  18. 164
      rust/tools/abacus-cli/src/subcommands/db_state.rs
  19. 2
      rust/tools/abacus-cli/src/subcommands/mod.rs
  20. 4
      rust/tools/abacus-cli/src/subcommands/prove.rs
  21. 2
      solidity/core/contracts/Inbox.sol
  22. 32
      solidity/core/contracts/Outbox.sol
  23. 4
      solidity/core/contracts/test/TestInbox.sol
  24. 12
      solidity/core/contracts/test/TestMessage.sol
  25. 46
      solidity/core/libs/Message.sol
  26. 40
      solidity/core/test/inbox.test.ts
  27. 14
      solidity/core/test/message.test.ts
  28. 29
      solidity/core/test/outbox.test.ts
  29. 7
      typescript/hardhat/src/TestAbacusDeploy.ts
  30. 17
      typescript/sdk/src/core/message.ts
  31. 1
      typescript/sdk/test/gas/calculator.test.ts
  32. 12
      typescript/utils/src/utils.ts
  33. 8
      vectors/message.json
  34. 12
      vectors/messageWithProof.json

@ -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();

@ -88,10 +88,6 @@ impl CachingOutbox {
#[async_trait]
impl Outbox for CachingOutbox {
async fn nonces(&self, destination: u32) -> Result<u32, ChainCommunicationError> {
self.outbox.nonces(destination).await
}
async fn dispatch(&self, message: &Message) -> Result<TxOutcome, ChainCommunicationError> {
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<Option<RawCommittedMessage>, 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<Box<dyn Outbox>> for Outboxes {
#[async_trait]
impl Outbox for OutboxVariants {
#[instrument(level = "trace", err)]
async fn nonces(&self, destination: u32) -> Result<u32, ChainCommunicationError> {
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<TxOutcome, ChainCommunicationError> {
match self {

@ -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<Option<H256>, 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<Option<RawCommittedMessage>, 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,

@ -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();

@ -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<u8>,
}
@ -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<RawCommittedMessage> for CommittedMessage {
fn try_from(raw: RawCommittedMessage) -> Result<Self, Self::Error> {
Ok(Self {
leaf_index: raw.leaf_index,
committed_root: raw.committed_root,
message: AbacusMessage::read_from(&mut &raw.message[..])?,
})
}

@ -15,9 +15,6 @@ pub trait Outbox: AbacusCommon + Send + Sync + std::fmt::Debug {
/// Fetch the current state.
async fn state(&self) -> Result<State, ChainCommunicationError>;
/// Fetch the nonce
async fn nonces(&self, destination: u32) -> Result<u32, ChainCommunicationError>;
/// Gets the current leaf count of the merkle tree
async fn count(&self) -> Result<u32, ChainCommunicationError>;
@ -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<Option<RawCommittedMessage>, 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<Option<CommittedMessage>, 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(

@ -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)
}
}

@ -14,25 +14,16 @@ mock! {
pub fn _domain_hash(&self) -> H256 {}
pub fn _raw_message_by_nonce(
&self,
destination: u32,
nonce: u32,
) -> Result<Option<RawCommittedMessage>, ChainCommunicationError> {}
pub fn _raw_message_by_leaf(
&self,
leaf: H256,
) -> Result<Option<RawCommittedMessage>, ChainCommunicationError> {}
pub fn _leaf_by_tree_index(
&self,
tree_index: usize,
) -> Result<Option<H256>, ChainCommunicationError> {}
pub fn _nonces(&self, destination: u32) -> Result<u32, ChainCommunicationError> {}
pub fn _dispatch(&self, message: &Message) -> Result<TxOutcome, ChainCommunicationError> {}
pub fn _count(&self) -> Result<u32, ChainCommunicationError> {}
@ -62,10 +53,6 @@ impl std::fmt::Debug for MockOutboxContract {
#[async_trait]
impl Outbox for MockOutboxContract {
async fn nonces(&self, destination: u32) -> Result<u32, ChainCommunicationError> {
self._nonces(destination)
}
async fn dispatch(&self, message: &Message) -> Result<TxOutcome, ChainCommunicationError> {
self._dispatch(message)
}

@ -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);

@ -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",

@ -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<M> Outbox for EthereumOutbox<M>
where
M: ethers::providers::Middleware + 'static,
{
#[tracing::instrument(err, skip(self))]
async fn nonces(&self, destination: u32) -> Result<u32, ChainCommunicationError> {
Ok(self.contract.nonces(destination).call().await?)
}
#[tracing::instrument(err, skip(self))]
async fn dispatch(&self, message: &Message) -> Result<TxOutcome, ChainCommunicationError> {
let tx = self.contract.dispatch(

@ -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"

@ -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"
}
}

@ -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"
}
}

@ -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"
}
}

@ -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),
}

@ -14,6 +14,5 @@ async fn main() -> Result<()> {
match command {
Commands::Prove(prove) => prove.run().await,
Commands::DbState(db_state) => db_state.run().await,
}
}

@ -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<CommittedMessage>)>;
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<HashMap<H256, Vec<CommittedMessage>>> {
let mut messages_by_committed_roots: HashMap<H256, Vec<CommittedMessage>> = 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::<CommittedMessage>::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<H256, Vec<CommittedMessage>>,
) -> Result<OutputVec> {
// Create mapping of (update root, block_number) to [messages]
let output_map: HashMap<(H256, u64), Vec<CommittedMessage>> = 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<Value> = 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(())
}
}

@ -1,5 +1,3 @@
pub mod db_state;
pub mod prove;
pub use db_state::*;
pub use prove::*;

@ -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?,
_ => {

@ -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,

@ -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;
}

@ -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);
}

@ -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);
}
}

@ -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
);
}
}

@ -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

@ -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);
});
});

@ -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 () => {

@ -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);

@ -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
*/

@ -73,7 +73,6 @@ describe('InterchainGasCalculator', () => {
const message: ParsedMessage = {
origin: originDomain,
sender: zeroAddressBytes32,
nonce: 0,
destination: destinationDomain,
recipient: zeroAddressBytes32,
body: '0x12345678',

@ -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(

@ -1,12 +1,8 @@
[
{
"body": [
18,
52
],
"body": [18, 52],
"destination": 2000,
"messageHash": "0x31def026c93f999e8beacc858eb138c6ed85e1d6db7928786a5f72cb70836316",
"nonce": 1,
"messageHash": "0xab444826d49ee7fa7521d4a1587b4b25197edd8a43b42307160afb4bf4232157",
"origin": 1000,
"recipient": "0x0000000000000000000000002222222222222222222222222222222222222222",
"sender": "0x0000000000000000000000001111111111111111111111111111111111111111"

@ -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"
}

Loading…
Cancel
Save