Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix: e2e working with aggregation 2/2 of message_id and merkle_root #2861

Merged
merged 24 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a834bfd
Set 2/2 aggregationISM on test
nambrot Oct 26, 2023
e037f6b
Set only MerkleTreeISM in test
nambrot Oct 26, 2023
de62d0c
console log stuff
aroralanuk Oct 31, 2023
228c698
intermediate
aroralanuk Nov 1, 2023
9751ce5
nonce -> leaf_index builder.get_proof
aroralanuk Nov 2, 2023
b5d05cb
Merge branch 'v3' into nambrot/repro-only-merkle-tree
aroralanuk Nov 2, 2023
f02d834
reenable yarn install and build
aroralanuk Nov 2, 2023
75024d1
rm trace
aroralanuk Nov 2, 2023
5d9590c
cleanup
aroralanuk Nov 2, 2023
29820bf
aggregation log for invalid isms
aroralanuk Nov 3, 2023
614da35
reenable yarn install
aroralanuk Nov 3, 2023
b6c33c7
Merge branch 'v3' into nambrot/repro-only-merkle-tree
aroralanuk Nov 3, 2023
08c7144
Merge branch 'v3' into nambrot/repro-only-merkle-tree
aroralanuk Nov 3, 2023
159c880
lint fixes
aroralanuk Nov 3, 2023
64ab08f
Merge remote-tracking branch 'origin/nambrot/repro-only-merkle-tree' …
aroralanuk Nov 3, 2023
7ff416e
switch to build_ism_and_metadata
aroralanuk Nov 6, 2023
46873ab
get_proof doesn't return option
aroralanuk Nov 7, 2023
97660b1
Merge branch 'v3' into nambrot/repro-only-merkle-tree
aroralanuk Nov 7, 2023
be099d0
don't revert on mismatch
aroralanuk Nov 7, 2023
409a2fa
Merge remote-tracking branch 'refs/remotes/origin/nambrot/repro-only-…
aroralanuk Nov 7, 2023
27b3fa3
remove db everywhere
aroralanuk Nov 7, 2023
e6b5cbd
cover case of err and return none as option<moduleType>
aroralanuk Nov 7, 2023
f1976b5
Merge branch 'v3' into nambrot/repro-only-merkle-tree
aroralanuk Nov 7, 2023
c4431e5
lint-rs fix
aroralanuk Nov 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 7 additions & 20 deletions rust/agents/relayer/src/merkle_tree/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt::Display;
use eyre::{Context, Result};
use tracing::{debug, error, instrument};

use hyperlane_base::db::{DbError, HyperlaneRocksDB};
use hyperlane_base::db::DbError;
use hyperlane_core::{
accumulator::{incremental::IncrementalMerkle, merkle::Proof},
ChainCommunicationError, H256,
Expand All @@ -14,7 +14,6 @@ use crate::prover::{Prover, ProverError};
/// Struct to sync prover.
#[derive(Debug)]
pub struct MerkleTreeBuilder {
db: HyperlaneRocksDB,
prover: Prover,
incremental: IncrementalMerkle,
}
Expand Down Expand Up @@ -62,36 +61,24 @@ pub enum MerkleTreeBuilderError {
}

impl MerkleTreeBuilder {
pub fn new(db: HyperlaneRocksDB) -> Self {
pub fn new() -> Self {
let prover = Prover::default();
let incremental = IncrementalMerkle::default();
Self {
prover,
incremental,
db,
}
}

#[instrument(err, skip(self), level="debug", fields(prover_latest_index=self.count()-1))]
pub fn get_proof(
&self,
message_nonce: u32,
leaf_index: u32,
root_index: u32,
) -> Result<Option<Proof>, MerkleTreeBuilderError> {
self.db
.retrieve_message_id_by_nonce(&message_nonce)?
.and_then(|message_id| {
self.db
.retrieve_merkle_leaf_index_by_message_id(&message_id)
.ok()
.flatten()
})
.map(|leaf_index| {
self.prover
.prove_against_previous(leaf_index as usize, root_index as usize)
})
.transpose()
.map_err(Into::into)
) -> Result<Proof, MerkleTreeBuilderError> {
self.prover
.prove_against_previous(leaf_index as usize, root_index as usize)
.map_err(MerkleTreeBuilderError::from)
}

pub fn count(&self) -> u32 {
Expand Down
51 changes: 26 additions & 25 deletions rust/agents/relayer/src/msg/metadata/aggregation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use futures_util::future::join_all;

use derive_new::new;
use eyre::Context;
use itertools::{Either, Itertools};
use tracing::{info, instrument};

use hyperlane_core::{HyperlaneMessage, InterchainSecurityModule, H256, U256};
use hyperlane_core::{HyperlaneMessage, InterchainSecurityModule, ModuleType, H256, U256};

use super::{BaseMetadataBuilder, MetadataBuilder};
use super::{base::IsmWithMetadataAndType, BaseMetadataBuilder, MetadataBuilder};
use eyre::ErrReport;

/// Bytes used to store one member of the (start, end) range tuple
/// Copied from `AggregationIsmMetadata.sol`
Expand Down Expand Up @@ -90,15 +92,15 @@ impl AggregationIsmMetadataBuilder {
sub_modules: Vec<IsmAndMetadata>,
message: &HyperlaneMessage,
threshold: usize,
err_isms: Vec<(H256, Option<ModuleType>)>,
) -> Option<Vec<SubModuleMetadata>> {
let gas_cost_results: Vec<_> = join_all(
sub_modules
.iter()
.map(|module| module.ism.dry_run_verify(message, &(module.meta.metadata))),
)
.await;

// Filter out the ISMs without a gas cost estimate
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
// Filter out the ISMs with a gas cost estimate
let metas_and_gas: Vec<_> = sub_modules
.into_iter()
.zip(gas_cost_results.into_iter())
Expand All @@ -107,7 +109,7 @@ impl AggregationIsmMetadataBuilder {

let metas_and_gas_count = metas_and_gas.len();
if metas_and_gas_count < threshold {
info!("Could not fetch all metadata: Found {metas_and_gas_count} of the {threshold} required ISM metadata pieces");
info!(?err_isms, %metas_and_gas_count, %threshold, message_id=message.id().to_string(), "Could not fetch all metadata, ISM metadata count did not reach aggregation threshold");
return None;
}
Some(Self::n_cheapest_metas(metas_and_gas, threshold))
Expand All @@ -127,34 +129,33 @@ impl MetadataBuilder for AggregationIsmMetadataBuilder {
let (ism_addresses, threshold) = ism.modules_and_threshold(message).await.context(CTX)?;
let threshold = threshold as usize;

let metas = join_all(
ism_addresses
.iter()
.map(|ism_address| self.base.build(*ism_address, message)),
)
.await;

let sub_modules = join_all(
let sub_modules_and_metas = join_all(
ism_addresses
.iter()
.map(|ism_address| self.base.build_ism(*ism_address)),
.map(|ism_address| self.base.build_ism_and_metadata(*ism_address, message)),
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
)
.await;

let filtered_sub_module_metas = metas
// Partitions things into
// 1. ok_sub_modules: ISMs with metadata with valid metadata
// 2. err_sub_modules: ISMs with invalid metadata
let (ok_sub_modules, err_sub_modules): (Vec<_>, Vec<_>) = sub_modules_and_metas
.into_iter()
.zip(ism_addresses.iter())
.enumerate()
.zip(sub_modules.into_iter())
.filter_map(|((index, meta_result), sub_module_result)| {
match (meta_result, sub_module_result) {
(Ok(Some(meta)), Ok(ism)) => Some(IsmAndMetadata::new(ism, index, meta)),
_ => None,
}
})
.collect();

.partition_map(|(index, (result, ism_address))| match result {
Ok(sub_module_and_meta) => match sub_module_and_meta.metadata {
Some(metadata) => Either::Left(IsmAndMetadata::new(
sub_module_and_meta.ism,
index,
metadata,
)),
None => Either::Right((*ism_address, Some(sub_module_and_meta.module_type))),
},
Err(_) => Either::Right((*ism_address, None)),
});
let maybe_aggregation_metadata =
Self::cheapest_valid_metas(filtered_sub_module_metas, message, threshold)
Self::cheapest_valid_metas(ok_sub_modules, message, threshold, err_sub_modules)
.await
.map(|mut metas| Self::format_metadata(&mut metas, ism_addresses.len()));
Ok(maybe_aggregation_metadata)
Expand Down
118 changes: 68 additions & 50 deletions rust/agents/relayer/src/msg/metadata/base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
use std::{collections::HashMap, fmt::Debug, str::FromStr, sync::Arc};

use crate::{
merkle_tree::builder::MerkleTreeBuilder,
msg::metadata::{
multisig::{MerkleRootMultisigMetadataBuilder, MessageIdMultisigMetadataBuilder},
AggregationIsmMetadataBuilder, CcipReadIsmMetadataBuilder, NullMetadataBuilder,
RoutingIsmMetadataBuilder,
},
};
use async_trait::async_trait;
use derive_new::new;
use eyre::{Context, Result};
Expand All @@ -16,15 +24,6 @@ use hyperlane_core::{
use tokio::sync::RwLock;
use tracing::{debug, info, instrument, warn};

use crate::{
merkle_tree::builder::MerkleTreeBuilder,
msg::metadata::{
multisig::{MerkleRootMultisigMetadataBuilder, MessageIdMultisigMetadataBuilder},
AggregationIsmMetadataBuilder, CcipReadIsmMetadataBuilder, NullMetadataBuilder,
RoutingIsmMetadataBuilder,
},
};

#[derive(Debug, thiserror::Error)]
pub enum MetadataBuilderError {
#[error("Unknown or invalid module type ({0})")]
Expand All @@ -33,6 +32,12 @@ pub enum MetadataBuilderError {
MaxDepthExceeded(u32),
}

pub struct IsmWithMetadataAndType {
pub ism: Box<dyn InterchainSecurityModule>,
pub metadata: Option<Vec<u8>>,
pub module_type: ModuleType,
}

#[async_trait]
pub trait MetadataBuilder: Send + Sync {
#[allow(clippy::async_yields_async)]
Expand Down Expand Up @@ -73,31 +78,9 @@ impl MetadataBuilder for BaseMetadataBuilder {
ism_address: H256,
message: &HyperlaneMessage,
) -> Result<Option<Vec<u8>>> {
let ism = self
.build_ism(ism_address)
.await
.context("When building ISM")?;
let module_type = ism
.module_type()
.await
.context("When fetching module type")?;
let base = self.clone_with_incremented_depth()?;

let metadata_builder: Box<dyn MetadataBuilder> = match module_type {
ModuleType::MerkleRootMultisig => {
Box::new(MerkleRootMultisigMetadataBuilder::new(base))
}
ModuleType::MessageIdMultisig => Box::new(MessageIdMultisigMetadataBuilder::new(base)),
ModuleType::Routing => Box::new(RoutingIsmMetadataBuilder::new(base)),
ModuleType::Aggregation => Box::new(AggregationIsmMetadataBuilder::new(base)),
ModuleType::Null => Box::new(NullMetadataBuilder::new()),
ModuleType::CcipRead => Box::new(CcipReadIsmMetadataBuilder::new(base)),
_ => return Err(MetadataBuilderError::UnsupportedModuleType(module_type).into()),
};
metadata_builder
.build(ism_address, message)
self.build_ism_and_metadata(ism_address, message)
.await
.context("When building metadata")
.map(|ism_with_metadata| ism_with_metadata.metadata)
}
}

Expand All @@ -116,26 +99,22 @@ impl BaseMetadataBuilder {
}
}

pub async fn get_proof(&self, nonce: u32, checkpoint: Checkpoint) -> Result<Option<Proof>> {
pub async fn get_proof(&self, leaf_index: u32, checkpoint: Checkpoint) -> Result<Proof> {
const CTX: &str = "When fetching message proof";
let proof = self.origin_prover_sync
let proof = self
.origin_prover_sync
.read()
.await
.get_proof(nonce, checkpoint.index)
.context(CTX)?
.and_then(|proof| {
// checkpoint may be fraudulent if the root does not
// match the canonical root at the checkpoint's index
if proof.root() == checkpoint.root {
return Some(proof)
}
info!(
?checkpoint,
canonical_root = ?proof.root(),
"Could not fetch metadata: checkpoint root does not match canonical root from merkle proof"
);
None
});
.get_proof(leaf_index, checkpoint.index)
.context(CTX)?;

if proof.root() != checkpoint.root {
info!(
?checkpoint,
canonical_root = ?proof.root(),
"Could not fetch metadata: checkpoint root does not match canonical root from merkle proof"
);
}
Ok(proof)
}

Expand Down Expand Up @@ -244,4 +223,43 @@ impl BaseMetadataBuilder {
}
Ok(MultisigCheckpointSyncer::new(checkpoint_syncers))
}

#[instrument(err, skip(self), fields(domain=self.domain().name()))]
pub async fn build_ism_and_metadata(
&self,
ism_address: H256,
message: &HyperlaneMessage,
) -> Result<IsmWithMetadataAndType> {
let ism: Box<dyn InterchainSecurityModule> = self
.build_ism(ism_address)
.await
.context("When building ISM")?;

let module_type = ism
.module_type()
.await
.context("When fetching module type")?;
let base = self.clone_with_incremented_depth()?;

let metadata_builder: Box<dyn MetadataBuilder> = match module_type {
ModuleType::MerkleRootMultisig => {
Box::new(MerkleRootMultisigMetadataBuilder::new(base))
}
ModuleType::MessageIdMultisig => Box::new(MessageIdMultisigMetadataBuilder::new(base)),
ModuleType::Routing => Box::new(RoutingIsmMetadataBuilder::new(base)),
ModuleType::Aggregation => Box::new(AggregationIsmMetadataBuilder::new(base)),
ModuleType::Null => Box::new(NullMetadataBuilder::new()),
ModuleType::CcipRead => Box::new(CcipReadIsmMetadataBuilder::new(base)),
_ => return Err(MetadataBuilderError::UnsupportedModuleType(module_type).into()),
};
let meta = metadata_builder
.build(ism_address, message)
.await
.context("When building metadata");
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
Ok(IsmWithMetadataAndType {
ism,
metadata: meta?,
module_type,
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,10 @@ impl MultisigIsmMetadataBuilder for MerkleRootMultisigMetadataBuilder {
highest_leaf_index, "Couldn't get checkpoint in range"
)
);
unwrap_or_none_result!(
proof,
self.get_proof(leaf_index, quorum_checkpoint.checkpoint.checkpoint)
.await
.context(CTX)?,
debug!(leaf_index, checkpoint=?quorum_checkpoint, "Couldn't get proof")
);
let proof = self
.get_proof(leaf_index, quorum_checkpoint.checkpoint.checkpoint)
.await
.context(CTX)?;
Ok(Some(MultisigMetadata::new(
quorum_checkpoint,
leaf_index,
Expand Down
2 changes: 1 addition & 1 deletion rust/agents/relayer/src/msg/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ mod test {
let core_metrics = CoreMetrics::new("dummy_relayer", 37582, Registry::new()).unwrap();
BaseMetadataBuilder::new(
destination_chain_conf.clone(),
Arc::new(RwLock::new(MerkleTreeBuilder::new(db.clone()))),
Arc::new(RwLock::new(MerkleTreeBuilder::new())),
Arc::new(MockValidatorAnnounceContract::default()),
false,
Arc::new(core_metrics),
Expand Down
3 changes: 1 addition & 2 deletions rust/agents/relayer/src/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,9 @@ impl BaseAgent for Relayer {
.origin_chains
.iter()
.map(|origin| {
let db = dbs.get(origin).unwrap().clone();
(
origin.clone(),
Arc::new(RwLock::new(MerkleTreeBuilder::new(db))),
Arc::new(RwLock::new(MerkleTreeBuilder::new())),
)
})
.collect::<HashMap<_, _>>();
Expand Down
1 change: 0 additions & 1 deletion rust/agents/validator/src/submit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,6 @@ impl ValidatorSubmitter {
);
continue;
}

let signed_checkpoint = self.signer.sign(queued_checkpoint).await?;
self.checkpoint_syncer
.write_checkpoint(&signed_checkpoint)
Expand Down
1 change: 0 additions & 1 deletion rust/chains/hyperlane-ethereum/tests/signer_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{fs::OpenOptions, io::Write, str::FromStr};
use hex::FromHex;
use serde_json::{json, Value};

use ethers::signers::Signer;
use hyperlane_core::{
accumulator::{
merkle::{merkle_root_from_branch, MerkleTree},
Expand Down
4 changes: 2 additions & 2 deletions rust/hyperlane-base/src/types/multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;

use derive_new::new;
use eyre::Result;
use tracing::{debug, instrument, trace};
use tracing::{debug, instrument};

use hyperlane_core::{MultisigSignedCheckpoint, SignedCheckpointWithMessageId, H160, H256};

Expand Down Expand Up @@ -46,7 +46,7 @@ impl MultisigCheckpointSyncer {
// Gracefully handle errors getting the latest_index
match checkpoint_syncer.latest_index().await {
Ok(Some(index)) => {
trace!(?address, ?index, "Validator returned latest index");
debug!(?address, ?index, "Validator returned latest index");
latest_indices.push(index);
}
err => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ export const aggregationIsm = (validatorKey: string): AggregationIsmConfig => {
merkleRootMultisig(validatorKey),
messageIdMultisig(validatorKey),
],
threshold: 1,
threshold: 2,
};
};