Skip to content

Commit

Permalink
Merge branch 'v3' into testnet4-deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
yorhodes committed Oct 10, 2023
2 parents aceae4d + c6cea78 commit c477250
Show file tree
Hide file tree
Showing 23 changed files with 228 additions and 272 deletions.
15 changes: 0 additions & 15 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ Inflector = "0.11.4"
anyhow = "1.0"
async-trait = "0.1"
auto_impl = "1.0"
backoff = { version = "0.4.0", features = ["tokio"] }
backtrace = "0.3"
base64 = "0.21.2"
bincode = "1.3"
Expand Down
1 change: 0 additions & 1 deletion rust/agents/relayer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ version.workspace = true

[dependencies]
async-trait.workspace = true
backoff.workspace = true
config.workspace = true
convert_case.workspace = true
derive-new.workspace = true
Expand Down
24 changes: 12 additions & 12 deletions rust/agents/relayer/src/merkle_tree/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ pub enum MerkleTreeBuilderError {
/// DB Error
#[error("{0}")]
DbError(#[from] DbError),
/// Some other error occured.
#[error("Failed to build the merkle tree: {0}")]
Other(String),
}

impl MerkleTreeBuilder {
Expand All @@ -81,16 +78,19 @@ impl MerkleTreeBuilder {
message_nonce: u32,
root_index: u32,
) -> Result<Option<Proof>, MerkleTreeBuilderError> {
let Some(leaf_index) = self
.db
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())
else {
return Ok(None);
};
self.prover
.prove_against_previous(leaf_index as usize, root_index as usize)
.map(Option::from)
.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)
}

Expand Down
59 changes: 20 additions & 39 deletions rust/agents/relayer/src/msg/metadata/base.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::{collections::HashMap, fmt::Debug, str::FromStr, sync::Arc};

use async_trait::async_trait;
use backoff::Error as BackoffError;
use backoff::{future::retry, ExponentialBackoff};
use derive_new::new;
use eyre::{Context, Result};
use hyperlane_base::db::HyperlaneRocksDB;
Expand All @@ -19,7 +17,7 @@ use tokio::sync::RwLock;
use tracing::{debug, info, instrument, warn};

use crate::{
merkle_tree::builder::{MerkleTreeBuilder, MerkleTreeBuilderError},
merkle_tree::builder::MerkleTreeBuilder,
msg::metadata::{
multisig::{
LegacyMultisigMetadataBuilder, MerkleRootMultisigMetadataBuilder,
Expand Down Expand Up @@ -102,15 +100,6 @@ impl MetadataBuilder for BaseMetadataBuilder {
}
}

fn constant_backoff() -> ExponentialBackoff {
ExponentialBackoff {
initial_interval: std::time::Duration::from_secs(1),
multiplier: 1.0,
max_elapsed_time: None,
..ExponentialBackoff::default()
}
}

impl BaseMetadataBuilder {
pub fn domain(&self) -> &HyperlaneDomain {
&self.destination_chain_setup.domain
Expand All @@ -128,33 +117,25 @@ impl BaseMetadataBuilder {

pub async fn get_proof(&self, nonce: u32, checkpoint: Checkpoint) -> Result<Option<Proof>> {
const CTX: &str = "When fetching message proof";
let proof = retry(constant_backoff(), || async {
self.origin_prover_sync
.read()
.await
.get_proof(nonce, checkpoint.index)
.context(CTX)
// If no proof is found, `get_proof(...)` returns `Ok(None)`,
// so errors should break the retry loop.
.map_err(BackoffError::permanent)?
.ok_or(MerkleTreeBuilderError::Other("No proof found in DB".into()))
.context(CTX)
// Transient errors are retried
.map_err(BackoffError::transient)
})
.await?;
// checkpoint may be fraudulent if the root does not
// match the canonical root at the checkpoint's index
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(None)
} else {
Ok(Some(proof))
}
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
});
Ok(proof)
}

pub async fn highest_known_nonce(&self) -> Option<u32> {
Expand Down
18 changes: 10 additions & 8 deletions rust/agents/relayer/src/msg/metadata/multisig/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ use crate::msg::metadata::MetadataBuilder;
pub struct MultisigMetadata {
checkpoint: Checkpoint,
signatures: Vec<SignatureWithSigner>,
merkle_leaf_id: Option<u32>,
merkle_leaf_index: Option<u32>,
message_id: Option<H256>,
proof: Option<Proof>,
}

#[derive(Debug, Display, PartialEq, Eq, Clone)]
pub enum MetadataToken {
MerkleRoot,
CheckpointMerkleRoot,
CheckpointIndex,
CheckpointMerkleTree,
CheckpointMerkleTreeHook,
MessageId,
MerkleProof,
MerkleIndex,
MessageMerkleLeafIndex,
Threshold,
Signatures,
Validators,
Expand All @@ -57,16 +57,18 @@ pub trait MultisigIsmMetadataBuilder: AsRef<BaseMetadataBuilder> + Send + Sync {
) -> Result<Vec<u8>> {
let build_token = |token: &MetadataToken| -> Result<Vec<u8>> {
match token {
MetadataToken::MerkleRoot => Ok(metadata.checkpoint.root.to_fixed_bytes().into()),
MetadataToken::MerkleIndex => Ok(metadata
.merkle_leaf_id
MetadataToken::CheckpointMerkleRoot => {
Ok(metadata.checkpoint.root.to_fixed_bytes().into())
}
MetadataToken::MessageMerkleLeafIndex => Ok(metadata
.merkle_leaf_index
.ok_or(eyre::eyre!("Failed to fetch metadata"))?
.to_be_bytes()
.into()),
MetadataToken::CheckpointIndex => {
Ok(metadata.checkpoint.index.to_be_bytes().into())
}
MetadataToken::CheckpointMerkleTree => Ok(metadata
MetadataToken::CheckpointMerkleTreeHook => Ok(metadata
.checkpoint
.merkle_tree_hook_address
.to_fixed_bytes()
Expand Down
50 changes: 22 additions & 28 deletions rust/agents/relayer/src/msg/metadata/multisig/legacy_multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use derive_new::new;

use eyre::{Context, Result};
use hyperlane_base::MultisigCheckpointSyncer;
use hyperlane_core::{HyperlaneMessage, H256};
use hyperlane_core::{unwrap_or_none_result, HyperlaneMessage, H256};

use crate::msg::metadata::BaseMetadataBuilder;

Expand All @@ -19,9 +19,9 @@ pub struct LegacyMultisigMetadataBuilder(BaseMetadataBuilder);
impl MultisigIsmMetadataBuilder for LegacyMultisigMetadataBuilder {
fn token_layout(&self) -> Vec<MetadataToken> {
vec![
MetadataToken::MerkleRoot,
MetadataToken::CheckpointMerkleRoot,
MetadataToken::CheckpointIndex,
MetadataToken::CheckpointMerkleTree,
MetadataToken::CheckpointMerkleTreeHook,
MetadataToken::MerkleProof,
MetadataToken::Threshold,
MetadataToken::Signatures,
Expand All @@ -37,31 +37,25 @@ impl MultisigIsmMetadataBuilder for LegacyMultisigMetadataBuilder {
checkpoint_syncer: &MultisigCheckpointSyncer,
) -> Result<Option<MultisigMetadata>> {
const CTX: &str = "When fetching LegacyMultisig metadata";
let Some(highest_nonce) = self.highest_known_nonce().await
else {
return Ok(None);
};
let Some(quorum_checkpoint) = checkpoint_syncer
.legacy_fetch_checkpoint_in_range(
validators,
threshold as usize,
message.nonce,
highest_nonce,
)
.await
.context(CTX)?
else {
return Ok(None);
};

let Some(proof) = self
.get_proof(message.nonce, quorum_checkpoint.checkpoint)
.await
.context(CTX)?
else {
return Ok(None);
};

unwrap_or_none_result!(highest_nonce, self.highest_known_nonce().await);
unwrap_or_none_result!(
quorum_checkpoint,
checkpoint_syncer
.legacy_fetch_checkpoint_in_range(
validators,
threshold as usize,
message.nonce,
highest_nonce,
)
.await
.context(CTX)?
);
unwrap_or_none_result!(
proof,
self.get_proof(message.nonce, quorum_checkpoint.checkpoint)
.await
.context(CTX)?
);
Ok(Some(MultisigMetadata::new(
quorum_checkpoint.checkpoint,
quorum_checkpoint.signatures,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use derive_new::new;

use eyre::{Context, Result};
use hyperlane_base::MultisigCheckpointSyncer;
use hyperlane_core::{HyperlaneMessage, H256};
use hyperlane_core::{unwrap_or_none_result, HyperlaneMessage, H256};

use crate::msg::metadata::BaseMetadataBuilder;

Expand All @@ -18,8 +18,8 @@ pub struct MerkleRootMultisigMetadataBuilder(BaseMetadataBuilder);
impl MultisigIsmMetadataBuilder for MerkleRootMultisigMetadataBuilder {
fn token_layout(&self) -> Vec<MetadataToken> {
vec![
MetadataToken::CheckpointMerkleTree,
MetadataToken::MerkleIndex,
MetadataToken::CheckpointMerkleTreeHook,
MetadataToken::MessageMerkleLeafIndex,
MetadataToken::MessageId,
MetadataToken::MerkleProof,
MetadataToken::CheckpointIndex,
Expand All @@ -35,35 +35,35 @@ impl MultisigIsmMetadataBuilder for MerkleRootMultisigMetadataBuilder {
checkpoint_syncer: &MultisigCheckpointSyncer,
) -> Result<Option<MultisigMetadata>> {
const CTX: &str = "When fetching MerkleRootMultisig metadata";
let Some(highest_nonce) = self.highest_known_nonce().await
else {
return Ok(None);
};
let Some(quorum_checkpoint) = checkpoint_syncer
.fetch_checkpoint_in_range(validators, threshold as usize, message.nonce, highest_nonce)
.await
.context(CTX)?
else {
return Ok(None);
};

let Some(proof) = self
.get_proof(message.nonce, quorum_checkpoint.checkpoint.checkpoint)
.await
.context(CTX)?
else {
return Ok(None);
};

let merkle_leaf_id = self
.get_merkle_leaf_id_by_message_id(message.id())
.await
.context(CTX)?;

unwrap_or_none_result!(highest_nonce, self.highest_known_nonce().await);
unwrap_or_none_result!(
quorum_checkpoint,
checkpoint_syncer
.fetch_checkpoint_in_range(
validators,
threshold as usize,
message.nonce,
highest_nonce
)
.await
.context(CTX)?
);
unwrap_or_none_result!(
proof,
self.get_proof(message.nonce, quorum_checkpoint.checkpoint.checkpoint)
.await
.context(CTX)?
);
unwrap_or_none_result!(
merkle_leaf_id,
self.get_merkle_leaf_id_by_message_id(message.id())
.await
.context(CTX)?
);
Ok(Some(MultisigMetadata::new(
quorum_checkpoint.checkpoint.checkpoint,
quorum_checkpoint.signatures,
merkle_leaf_id,
Some(merkle_leaf_id),
Some(quorum_checkpoint.checkpoint.message_id),
Some(proof),
)))
Expand Down
Loading

0 comments on commit c477250

Please sign in to comment.