Remove vestigial agent files (#1324)
parent
12f1305817
commit
5e7ff47857
@ -1,78 +0,0 @@ |
||||
use std::sync::Arc; |
||||
|
||||
use async_trait::async_trait; |
||||
use ethers::core::types::H256; |
||||
use eyre::Result; |
||||
|
||||
use abacus_core::{ |
||||
db::AbacusDB, AbacusChain, AbacusCommon, AbacusContract, Address, ChainCommunicationError, |
||||
Inbox, MessageStatus, |
||||
}; |
||||
|
||||
/// Caching inbox type.
|
||||
#[derive(Debug, Clone)] |
||||
pub struct CachingInbox { |
||||
inbox: Arc<dyn Inbox>, |
||||
db: AbacusDB, |
||||
} |
||||
|
||||
impl std::fmt::Display for CachingInbox { |
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||
write!(f, "{:?}", self) |
||||
} |
||||
} |
||||
|
||||
impl CachingInbox { |
||||
/// Instantiate new CachingInbox
|
||||
pub fn new(inbox: Arc<dyn Inbox>, db: AbacusDB) -> Self { |
||||
Self { inbox, db } |
||||
} |
||||
|
||||
/// Return handle on inbox object
|
||||
pub fn inbox(&self) -> &Arc<dyn Inbox> { |
||||
&self.inbox |
||||
} |
||||
|
||||
/// Return handle on AbacusDB
|
||||
pub fn db(&self) -> &AbacusDB { |
||||
&self.db |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl Inbox for CachingInbox { |
||||
fn remote_domain(&self) -> u32 { |
||||
self.inbox.remote_domain() |
||||
} |
||||
|
||||
async fn message_status(&self, leaf: H256) -> Result<MessageStatus, ChainCommunicationError> { |
||||
self.inbox.message_status(leaf).await |
||||
} |
||||
|
||||
fn contract_address(&self) -> Address { |
||||
self.inbox.contract_address() |
||||
} |
||||
} |
||||
|
||||
impl AbacusChain for CachingInbox { |
||||
fn chain_name(&self) -> &str { |
||||
self.inbox.chain_name() |
||||
} |
||||
|
||||
fn local_domain(&self) -> u32 { |
||||
self.inbox.local_domain() |
||||
} |
||||
} |
||||
|
||||
impl AbacusContract for CachingInbox { |
||||
fn address(&self) -> H256 { |
||||
self.inbox.address() |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl AbacusCommon for CachingInbox { |
||||
async fn validator_manager(&self) -> Result<H256, ChainCommunicationError> { |
||||
self.inbox.validator_manager().await |
||||
} |
||||
} |
@ -1,169 +0,0 @@ |
||||
use std::fmt::Debug; |
||||
use std::sync::Arc; |
||||
|
||||
use async_trait::async_trait; |
||||
use ethers::core::types::H256; |
||||
use eyre::Result; |
||||
use futures_util::future::select_all; |
||||
use tokio::task::JoinHandle; |
||||
use tokio::time::{sleep, Duration}; |
||||
use tracing::instrument::Instrumented; |
||||
use tracing::{info_span, Instrument}; |
||||
|
||||
use abacus_core::db::AbacusDB; |
||||
use abacus_core::{ |
||||
AbacusChain, AbacusCommon, AbacusContract, ChainCommunicationError, Checkpoint, Message, |
||||
Outbox, OutboxEvents, OutboxIndexer, OutboxState, RawCommittedMessage, TxOutcome, |
||||
}; |
||||
|
||||
use crate::{ContractSync, ContractSyncMetrics, IndexSettings}; |
||||
|
||||
/// Caching Outbox type
|
||||
#[derive(Debug, Clone)] |
||||
pub struct CachingOutbox { |
||||
outbox: Arc<dyn Outbox>, |
||||
db: AbacusDB, |
||||
indexer: Arc<dyn OutboxIndexer>, |
||||
} |
||||
|
||||
impl std::fmt::Display for CachingOutbox { |
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||
write!(f, "{:?}", self) |
||||
} |
||||
} |
||||
|
||||
impl CachingOutbox { |
||||
/// Instantiate new CachingOutbox
|
||||
pub fn new(outbox: Arc<dyn Outbox>, db: AbacusDB, indexer: Arc<dyn OutboxIndexer>) -> Self { |
||||
Self { |
||||
outbox, |
||||
db, |
||||
indexer, |
||||
} |
||||
} |
||||
|
||||
/// Return handle on outbox object
|
||||
pub fn outbox(&self) -> &Arc<dyn Outbox> { |
||||
&self.outbox |
||||
} |
||||
|
||||
/// Return handle on AbacusDB
|
||||
pub fn db(&self) -> &AbacusDB { |
||||
&self.db |
||||
} |
||||
|
||||
/// Spawn a task that syncs the CachingOutbox's db with the on-chain event
|
||||
/// data
|
||||
pub fn sync( |
||||
&self, |
||||
index_settings: IndexSettings, |
||||
metrics: ContractSyncMetrics, |
||||
) -> Instrumented<JoinHandle<Result<()>>> { |
||||
let span = info_span!("OutboxContractSync", self = %self); |
||||
|
||||
let sync = ContractSync::new( |
||||
self.outbox.chain_name().into(), |
||||
self.db.clone(), |
||||
self.indexer.clone(), |
||||
index_settings, |
||||
metrics, |
||||
); |
||||
|
||||
tokio::spawn(async move { |
||||
let tasks = vec![sync.sync_outbox_messages()]; |
||||
|
||||
let (_, _, remaining) = select_all(tasks).await; |
||||
for task in remaining.into_iter() { |
||||
cancel_task!(task); |
||||
} |
||||
|
||||
Ok(()) |
||||
}) |
||||
.instrument(span) |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl Outbox for CachingOutbox { |
||||
async fn state(&self) -> Result<OutboxState, ChainCommunicationError> { |
||||
self.outbox.state().await |
||||
} |
||||
|
||||
async fn count(&self) -> Result<u32, ChainCommunicationError> { |
||||
self.outbox.count().await |
||||
} |
||||
|
||||
async fn dispatch(&self, message: &Message) -> Result<TxOutcome, ChainCommunicationError> { |
||||
self.outbox.dispatch(message).await |
||||
} |
||||
|
||||
async fn cache_checkpoint(&self) -> Result<TxOutcome, ChainCommunicationError> { |
||||
self.outbox.cache_checkpoint().await |
||||
} |
||||
|
||||
async fn latest_cached_root(&self) -> Result<H256, ChainCommunicationError> { |
||||
self.outbox.latest_cached_root().await |
||||
} |
||||
|
||||
async fn latest_cached_checkpoint(&self) -> Result<Checkpoint, ChainCommunicationError> { |
||||
self.outbox.latest_cached_checkpoint().await |
||||
} |
||||
|
||||
async fn latest_checkpoint( |
||||
&self, |
||||
maybe_lag: Option<u64>, |
||||
) -> Result<Checkpoint, ChainCommunicationError> { |
||||
self.outbox.latest_checkpoint(maybe_lag).await |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl OutboxEvents for CachingOutbox { |
||||
#[tracing::instrument(err, skip(self))] |
||||
async fn raw_message_by_leaf( |
||||
&self, |
||||
leaf: H256, |
||||
) -> Result<Option<RawCommittedMessage>, ChainCommunicationError> { |
||||
loop { |
||||
if let Some(message) = self.db.message_by_leaf(leaf)? { |
||||
return Ok(Some(message)); |
||||
} |
||||
sleep(Duration::from_millis(500)).await; |
||||
} |
||||
} |
||||
|
||||
async fn leaf_by_tree_index( |
||||
&self, |
||||
tree_index: usize, |
||||
) -> Result<Option<H256>, ChainCommunicationError> { |
||||
loop { |
||||
if let Some(leaf) = self.db.leaf_by_leaf_index(tree_index as u32)? { |
||||
return Ok(Some(leaf)); |
||||
} |
||||
sleep(Duration::from_millis(500)).await; |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl AbacusChain for CachingOutbox { |
||||
fn chain_name(&self) -> &str { |
||||
self.outbox.chain_name() |
||||
} |
||||
|
||||
fn local_domain(&self) -> u32 { |
||||
self.outbox.local_domain() |
||||
} |
||||
} |
||||
|
||||
impl AbacusContract for CachingOutbox { |
||||
fn address(&self) -> H256 { |
||||
self.outbox.address() |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl AbacusCommon for CachingOutbox { |
||||
async fn validator_manager(&self) -> Result<H256, ChainCommunicationError> { |
||||
self.outbox.validator_manager().await |
||||
} |
||||
} |
@ -1,25 +0,0 @@ |
||||
use std::fmt::Debug; |
||||
|
||||
use async_trait::async_trait; |
||||
use auto_impl::auto_impl; |
||||
use ethers::core::types::H256; |
||||
use eyre::Result; |
||||
|
||||
use crate::{ |
||||
traits::{AbacusCommon, ChainCommunicationError}, |
||||
Address, MessageStatus, |
||||
}; |
||||
|
||||
/// Interface for on-chain inboxes
|
||||
#[async_trait] |
||||
#[auto_impl(Box, Arc)] |
||||
pub trait Inbox: AbacusCommon + Send + Sync + Debug { |
||||
/// Return the domain of the inbox's linked outbox
|
||||
fn remote_domain(&self) -> u32; |
||||
|
||||
/// Fetch the status of a message
|
||||
async fn message_status(&self, leaf: H256) -> Result<MessageStatus, ChainCommunicationError>; |
||||
|
||||
/// The on-chain address of the inbox contract.
|
||||
fn contract_address(&self) -> Address; |
||||
} |
@ -1,240 +0,0 @@ |
||||
#![allow(clippy::enum_variant_names)] |
||||
#![allow(missing_docs)] |
||||
|
||||
use std::collections::HashMap; |
||||
use std::fmt::{self, Debug, Display}; |
||||
use std::sync::Arc; |
||||
|
||||
use async_trait::async_trait; |
||||
use ethers::prelude::*; |
||||
use eyre::Result; |
||||
use tracing::instrument; |
||||
|
||||
use abacus_core::{ |
||||
AbacusAbi, AbacusChain, AbacusCommon, AbacusContract, Address, ChainCommunicationError, |
||||
ContractLocator, Inbox, InboxIndexer, Indexer, MessageStatus, |
||||
}; |
||||
|
||||
use crate::contracts::inbox::{Inbox as EthereumInboxInternal, INBOX_ABI}; |
||||
use crate::trait_builder::MakeableWithProvider; |
||||
|
||||
impl<M> Display for EthereumInboxInternal<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
write!(f, "{:?}", self) |
||||
} |
||||
} |
||||
|
||||
pub struct InboxBuilder {} |
||||
|
||||
#[async_trait] |
||||
impl MakeableWithProvider for InboxBuilder { |
||||
type Output = Box<dyn Inbox>; |
||||
|
||||
async fn make_with_provider<M: Middleware + 'static>( |
||||
&self, |
||||
provider: M, |
||||
locator: &ContractLocator, |
||||
) -> Self::Output { |
||||
Box::new(EthereumInbox::new(Arc::new(provider), locator).await) |
||||
} |
||||
} |
||||
|
||||
pub struct InboxIndexerBuilder { |
||||
pub finality_blocks: u32, |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl MakeableWithProvider for InboxIndexerBuilder { |
||||
type Output = Box<dyn InboxIndexer>; |
||||
|
||||
async fn make_with_provider<M: Middleware + 'static>( |
||||
&self, |
||||
provider: M, |
||||
locator: &ContractLocator, |
||||
) -> Self::Output { |
||||
Box::new(EthereumInboxIndexer::new( |
||||
Arc::new(provider), |
||||
locator, |
||||
self.finality_blocks, |
||||
)) |
||||
} |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
pub struct EthereumInboxIndexer<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
contract: Arc<EthereumInboxInternal<M>>, |
||||
provider: Arc<M>, |
||||
finality_blocks: u32, |
||||
} |
||||
|
||||
impl<M> EthereumInboxIndexer<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
pub fn new(provider: Arc<M>, locator: &ContractLocator, finality_blocks: u32) -> Self { |
||||
let contract = Arc::new(EthereumInboxInternal::new( |
||||
&locator.address, |
||||
provider.clone(), |
||||
)); |
||||
Self { |
||||
contract, |
||||
provider, |
||||
finality_blocks, |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> Indexer for EthereumInboxIndexer<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
async fn get_finalized_block_number(&self) -> Result<u32> { |
||||
Ok(self |
||||
.provider |
||||
.get_block_number() |
||||
.await? |
||||
.as_u32() |
||||
.saturating_sub(self.finality_blocks)) |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> InboxIndexer for EthereumInboxIndexer<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
#[instrument(err, skip(self))] |
||||
async fn fetch_processed_messages( |
||||
&self, |
||||
from: u32, |
||||
to: u32, |
||||
) -> Result<Vec<(H256, abacus_core::LogMeta)>> { |
||||
Ok(self |
||||
.contract |
||||
.process_filter() |
||||
.from_block(from) |
||||
.to_block(to) |
||||
.query_with_meta() |
||||
.await? |
||||
.into_iter() |
||||
.map(|(event, meta)| (H256::from(event.message_hash), meta.into())) |
||||
.collect()) |
||||
} |
||||
} |
||||
|
||||
/// A struct that provides access to an Ethereum inbox contract
|
||||
#[derive(Debug)] |
||||
pub struct EthereumInbox<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
contract: Arc<EthereumInboxInternal<M>>, |
||||
remote_domain: u32, |
||||
chain_name: String, |
||||
local_domain: u32, |
||||
} |
||||
|
||||
impl<M> EthereumInbox<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
/// Create a reference to a inbox at a specific Ethereum address on some
|
||||
/// chain
|
||||
pub async fn new( |
||||
provider: Arc<M>, |
||||
ContractLocator { |
||||
chain_name, |
||||
domain, |
||||
address, |
||||
}: &ContractLocator, |
||||
) -> Self { |
||||
let contract = Arc::new(EthereumInboxInternal::new(address, provider)); |
||||
let remote_domain = contract |
||||
.remote_domain() |
||||
.call() |
||||
.await |
||||
.expect("Failed to get inbox's local_domain"); |
||||
debug_assert_eq!( |
||||
contract |
||||
.local_domain() |
||||
.call() |
||||
.await |
||||
.expect("Failed to get inbox's remote_domain"), |
||||
*domain |
||||
); |
||||
Self { |
||||
contract, |
||||
remote_domain, |
||||
local_domain: *domain, |
||||
chain_name: chain_name.to_owned(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl<M> AbacusChain for EthereumInbox<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
fn chain_name(&self) -> &str { |
||||
&self.chain_name |
||||
} |
||||
|
||||
fn local_domain(&self) -> u32 { |
||||
self.local_domain |
||||
} |
||||
} |
||||
|
||||
impl<M> AbacusContract for EthereumInbox<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
fn address(&self) -> H256 { |
||||
self.contract.address().into() |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> AbacusCommon for EthereumInbox<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
#[tracing::instrument(err)] |
||||
async fn validator_manager(&self) -> Result<H256, ChainCommunicationError> { |
||||
Ok(self.contract.validator_manager().call().await?.into()) |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> Inbox for EthereumInbox<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
fn remote_domain(&self) -> u32 { |
||||
self.remote_domain |
||||
} |
||||
|
||||
#[tracing::instrument(err)] |
||||
async fn message_status(&self, leaf: H256) -> Result<MessageStatus, ChainCommunicationError> { |
||||
let status = self.contract.messages(leaf.into()).call().await?; |
||||
Ok(MessageStatus::try_from(status).expect("Bad status from solidity")) |
||||
} |
||||
|
||||
fn contract_address(&self) -> Address { |
||||
self.contract.address().into() |
||||
} |
||||
} |
||||
|
||||
pub struct EthereumInboxAbi; |
||||
|
||||
impl AbacusAbi for EthereumInboxAbi { |
||||
fn fn_map() -> HashMap<Selector, &'static str> { |
||||
super::extract_fn_map(&INBOX_ABI) |
||||
} |
||||
} |
@ -1,323 +0,0 @@ |
||||
#![allow(clippy::enum_variant_names)] |
||||
#![allow(missing_docs)] |
||||
|
||||
use std::collections::HashMap; |
||||
use std::sync::Arc; |
||||
|
||||
use async_trait::async_trait; |
||||
use ethers::prelude::*; |
||||
use eyre::Result; |
||||
use tracing::instrument; |
||||
|
||||
use abacus_core::{ |
||||
AbacusAbi, AbacusChain, AbacusCommon, AbacusContract, ChainCommunicationError, Checkpoint, |
||||
ContractLocator, Indexer, LogMeta, Message, Outbox, OutboxIndexer, OutboxState, |
||||
RawCommittedMessage, TxOutcome, |
||||
}; |
||||
|
||||
use crate::contracts::outbox::{Outbox as EthereumOutboxInternal, OUTBOX_ABI}; |
||||
use crate::trait_builder::MakeableWithProvider; |
||||
use crate::tx::report_tx; |
||||
|
||||
impl<M> std::fmt::Display for EthereumOutboxInternal<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||
write!(f, "{:?}", self) |
||||
} |
||||
} |
||||
|
||||
pub struct OutboxIndexerBuilder { |
||||
pub finality_blocks: u32, |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl MakeableWithProvider for OutboxIndexerBuilder { |
||||
type Output = Box<dyn OutboxIndexer>; |
||||
|
||||
async fn make_with_provider<M: Middleware + 'static>( |
||||
&self, |
||||
provider: M, |
||||
locator: &ContractLocator, |
||||
) -> Self::Output { |
||||
Box::new(EthereumOutboxIndexer::new( |
||||
Arc::new(provider), |
||||
locator, |
||||
self.finality_blocks, |
||||
)) |
||||
} |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
/// Struct that retrieves event data for an Ethereum outbox
|
||||
pub struct EthereumOutboxIndexer<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
contract: Arc<EthereumOutboxInternal<M>>, |
||||
provider: Arc<M>, |
||||
finality_blocks: u32, |
||||
outbox_domain: u32, |
||||
} |
||||
|
||||
impl<M> EthereumOutboxIndexer<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
/// Create new EthereumOutboxIndexer
|
||||
pub fn new(provider: Arc<M>, locator: &ContractLocator, finality_blocks: u32) -> Self { |
||||
let contract = Arc::new(EthereumOutboxInternal::new( |
||||
&locator.address, |
||||
provider.clone(), |
||||
)); |
||||
Self { |
||||
contract, |
||||
provider, |
||||
finality_blocks, |
||||
outbox_domain: locator.domain, |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> Indexer for EthereumOutboxIndexer<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
#[instrument(err, skip(self))] |
||||
async fn get_finalized_block_number(&self) -> Result<u32> { |
||||
Ok(self |
||||
.provider |
||||
.get_block_number() |
||||
.await? |
||||
.as_u32() |
||||
.saturating_sub(self.finality_blocks)) |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> OutboxIndexer for EthereumOutboxIndexer<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
#[instrument(err, skip(self))] |
||||
async fn fetch_sorted_messages( |
||||
&self, |
||||
from: u32, |
||||
to: u32, |
||||
) -> Result<Vec<(RawCommittedMessage, LogMeta)>> { |
||||
let mut events: Vec<(RawCommittedMessage, LogMeta)> = self |
||||
.contract |
||||
.dispatch_filter() |
||||
.from_block(from) |
||||
.to_block(to) |
||||
.query_with_meta() |
||||
.await? |
||||
.into_iter() |
||||
.map(|(event, meta)| { |
||||
( |
||||
RawCommittedMessage { |
||||
leaf_index: event.leaf_index.as_u32(), |
||||
message: event.message.to_vec(), |
||||
}, |
||||
meta.into(), |
||||
) |
||||
}) |
||||
.collect(); |
||||
events.sort_by(|a, b| a.0.leaf_index.cmp(&b.0.leaf_index)); |
||||
Ok(events) |
||||
} |
||||
|
||||
#[instrument(err, skip(self))] |
||||
async fn fetch_sorted_cached_checkpoints( |
||||
&self, |
||||
from: u32, |
||||
to: u32, |
||||
) -> Result<Vec<(Checkpoint, LogMeta)>> { |
||||
let mut events: Vec<(Checkpoint, LogMeta)> = self |
||||
.contract |
||||
.checkpoint_cached_filter() |
||||
.from_block(from) |
||||
.to_block(to) |
||||
.query_with_meta() |
||||
.await? |
||||
.into_iter() |
||||
.map(|(event, meta)| { |
||||
( |
||||
Checkpoint { |
||||
outbox_domain: self.outbox_domain, |
||||
root: event.root.into(), |
||||
index: event.index.as_u32(), |
||||
}, |
||||
meta.into(), |
||||
) |
||||
}) |
||||
.collect(); |
||||
events.sort_by(|a, b| a.1.cmp(&b.1)); |
||||
Ok(events) |
||||
} |
||||
} |
||||
|
||||
pub struct OutboxBuilder {} |
||||
|
||||
#[async_trait] |
||||
impl MakeableWithProvider for OutboxBuilder { |
||||
type Output = Box<dyn Outbox>; |
||||
|
||||
async fn make_with_provider<M: Middleware + 'static>( |
||||
&self, |
||||
provider: M, |
||||
locator: &ContractLocator, |
||||
) -> Self::Output { |
||||
Box::new(EthereumOutbox::new(Arc::new(provider), locator)) |
||||
} |
||||
} |
||||
|
||||
/// A reference to an Outbox contract on some Ethereum chain
|
||||
#[derive(Debug)] |
||||
pub struct EthereumOutbox<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
contract: Arc<EthereumOutboxInternal<M>>, |
||||
domain: u32, |
||||
chain_name: String, |
||||
provider: Arc<M>, |
||||
} |
||||
|
||||
impl<M> EthereumOutbox<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
/// Create a reference to a outbox at a specific Ethereum address on some
|
||||
/// chain
|
||||
pub fn new(provider: Arc<M>, locator: &ContractLocator) -> Self { |
||||
Self { |
||||
contract: Arc::new(EthereumOutboxInternal::new( |
||||
&locator.address, |
||||
provider.clone(), |
||||
)), |
||||
domain: locator.domain, |
||||
chain_name: locator.chain_name.to_owned(), |
||||
provider, |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl<M> AbacusChain for EthereumOutbox<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
fn chain_name(&self) -> &str { |
||||
&self.chain_name |
||||
} |
||||
|
||||
fn local_domain(&self) -> u32 { |
||||
self.domain |
||||
} |
||||
} |
||||
|
||||
impl<M> AbacusContract for EthereumOutbox<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
fn address(&self) -> H256 { |
||||
self.contract.address().into() |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> AbacusCommon for EthereumOutbox<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
#[tracing::instrument(err, skip(self))] |
||||
async fn validator_manager(&self) -> Result<H256, ChainCommunicationError> { |
||||
Ok(self.contract.validator_manager().call().await?.into()) |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> Outbox for EthereumOutbox<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
#[tracing::instrument(err, skip(self))] |
||||
async fn dispatch(&self, message: &Message) -> Result<TxOutcome, ChainCommunicationError> { |
||||
let tx = self.contract.dispatch( |
||||
message.destination, |
||||
message.recipient.to_fixed_bytes(), |
||||
message.body.clone().into(), |
||||
); |
||||
|
||||
Ok(report_tx(tx).await?.into()) |
||||
} |
||||
|
||||
#[tracing::instrument(err, skip(self))] |
||||
async fn state(&self) -> Result<OutboxState, ChainCommunicationError> { |
||||
let state = self.contract.state().call().await?; |
||||
Ok(OutboxState::try_from(state).expect("Invalid state received from contract")) |
||||
} |
||||
|
||||
#[tracing::instrument(err, skip(self))] |
||||
async fn count(&self) -> Result<u32, ChainCommunicationError> { |
||||
Ok(self.contract.count().call().await?.as_u32()) |
||||
} |
||||
|
||||
#[tracing::instrument(err, skip(self))] |
||||
async fn cache_checkpoint(&self) -> Result<TxOutcome, ChainCommunicationError> { |
||||
let tx = self.contract.cache_checkpoint(); |
||||
|
||||
Ok(report_tx(tx).await?.into()) |
||||
} |
||||
|
||||
#[tracing::instrument(err, skip(self))] |
||||
async fn latest_cached_root(&self) -> Result<H256, ChainCommunicationError> { |
||||
Ok(self.contract.latest_cached_root().call().await?.into()) |
||||
} |
||||
|
||||
#[tracing::instrument(err, skip(self))] |
||||
async fn latest_cached_checkpoint(&self) -> Result<Checkpoint, ChainCommunicationError> { |
||||
let (root, index) = self.contract.latest_cached_checkpoint().call().await?; |
||||
Ok(Checkpoint { |
||||
outbox_domain: self.domain, |
||||
root: root.into(), |
||||
index: index.as_u32(), |
||||
}) |
||||
} |
||||
|
||||
#[tracing::instrument(err, skip(self))] |
||||
async fn latest_checkpoint( |
||||
&self, |
||||
maybe_lag: Option<u64>, |
||||
) -> Result<Checkpoint, ChainCommunicationError> { |
||||
let base_call = self.contract.latest_checkpoint(); |
||||
let call_with_lag = match maybe_lag { |
||||
Some(lag) => { |
||||
let tip = self |
||||
.provider |
||||
.get_block_number() |
||||
.await |
||||
.map_err(|x| ChainCommunicationError::CustomError(Box::new(x)))? |
||||
.as_u64(); |
||||
base_call.block(if lag > tip { 0 } else { tip - lag }) |
||||
} |
||||
None => base_call, |
||||
}; |
||||
let (root, index) = call_with_lag.call().await?; |
||||
Ok(Checkpoint { |
||||
outbox_domain: self.domain, |
||||
root: root.into(), |
||||
index: index.as_u32(), |
||||
}) |
||||
} |
||||
} |
||||
|
||||
pub struct EthereumOutboxAbi; |
||||
|
||||
impl AbacusAbi for EthereumOutboxAbi { |
||||
fn fn_map() -> HashMap<Selector, &'static str> { |
||||
super::extract_fn_map(&OUTBOX_ABI) |
||||
} |
||||
} |
@ -1,208 +0,0 @@ |
||||
#![allow(clippy::enum_variant_names)] |
||||
#![allow(missing_docs)] |
||||
|
||||
use std::fmt::Display; |
||||
use std::sync::Arc; |
||||
|
||||
use abacus_core::TxCostEstimate; |
||||
use async_trait::async_trait; |
||||
use ethers::abi::AbiEncode; |
||||
use ethers::prelude::*; |
||||
use ethers_contract::builders::ContractCall; |
||||
use eyre::{eyre, Result}; |
||||
|
||||
use abacus_core::{ |
||||
accumulator::merkle::Proof, AbacusMessage, ChainCommunicationError, ContractLocator, Encode, |
||||
InboxValidatorManager, MultisigSignedCheckpoint, TxOutcome, |
||||
}; |
||||
|
||||
use crate::contracts::inbox_validator_manager::{ |
||||
InboxValidatorManager as EthereumInboxValidatorManagerInternal, ProcessCall, |
||||
}; |
||||
use crate::trait_builder::MakeableWithProvider; |
||||
use crate::tx::report_tx; |
||||
|
||||
pub use crate::contracts::inbox_validator_manager::INBOXVALIDATORMANAGER_ABI; |
||||
|
||||
impl<M> Display for EthereumInboxValidatorManagerInternal<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||
write!(f, "{:?}", self) |
||||
} |
||||
} |
||||
|
||||
pub struct InboxValidatorManagerBuilder { |
||||
pub inbox_address: Address, |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl MakeableWithProvider for InboxValidatorManagerBuilder { |
||||
type Output = Box<dyn InboxValidatorManager>; |
||||
|
||||
async fn make_with_provider<M: Middleware + 'static>( |
||||
&self, |
||||
provider: M, |
||||
locator: &ContractLocator, |
||||
) -> Self::Output { |
||||
Box::new(EthereumInboxValidatorManager::new( |
||||
Arc::new(provider), |
||||
locator, |
||||
self.inbox_address, |
||||
)) |
||||
} |
||||
} |
||||
|
||||
/// A struct that provides access to an Ethereum InboxValidatorManager contract
|
||||
#[derive(Debug)] |
||||
pub struct EthereumInboxValidatorManager<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
contract: Arc<EthereumInboxValidatorManagerInternal<M>>, |
||||
#[allow(unused)] |
||||
domain: u32, |
||||
#[allow(unused)] |
||||
chain_name: String, |
||||
#[allow(unused)] |
||||
provider: Arc<M>, |
||||
inbox_address: Address, |
||||
} |
||||
|
||||
impl<M> EthereumInboxValidatorManager<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
/// Create a reference to a inbox at a specific Ethereum address on some
|
||||
/// chain
|
||||
pub fn new(provider: Arc<M>, locator: &ContractLocator, inbox_address: Address) -> Self { |
||||
Self { |
||||
contract: Arc::new(EthereumInboxValidatorManagerInternal::new( |
||||
&locator.address, |
||||
provider.clone(), |
||||
)), |
||||
domain: locator.domain, |
||||
chain_name: locator.chain_name.to_owned(), |
||||
provider, |
||||
inbox_address, |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> InboxValidatorManager for EthereumInboxValidatorManager<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
#[tracing::instrument(skip(self))] |
||||
async fn process( |
||||
&self, |
||||
multisig_signed_checkpoint: &MultisigSignedCheckpoint, |
||||
message: &AbacusMessage, |
||||
proof: &Proof, |
||||
tx_gas_limit: Option<U256>, |
||||
) -> Result<TxOutcome, ChainCommunicationError> { |
||||
let contract_call = self |
||||
.process_contract_call(multisig_signed_checkpoint, message, proof, tx_gas_limit) |
||||
.await?; |
||||
let receipt = report_tx(contract_call).await?; |
||||
Ok(receipt.into()) |
||||
} |
||||
|
||||
async fn process_estimate_costs( |
||||
&self, |
||||
multisig_signed_checkpoint: &MultisigSignedCheckpoint, |
||||
message: &AbacusMessage, |
||||
proof: &Proof, |
||||
) -> Result<TxCostEstimate> { |
||||
let contract_call = self |
||||
.process_contract_call(multisig_signed_checkpoint, message, proof, None) |
||||
.await?; |
||||
|
||||
let gas_limit = contract_call |
||||
.tx |
||||
.gas() |
||||
.ok_or_else(|| eyre!("Expected gas limit for process contract call"))?; |
||||
let gas_price = self.provider.get_gas_price().await?; |
||||
|
||||
Ok(TxCostEstimate { |
||||
gas_limit: *gas_limit, |
||||
gas_price, |
||||
}) |
||||
} |
||||
|
||||
fn process_calldata( |
||||
&self, |
||||
multisig_signed_checkpoint: &MultisigSignedCheckpoint, |
||||
message: &AbacusMessage, |
||||
proof: &Proof, |
||||
) -> Vec<u8> { |
||||
let mut sol_proof: [[u8; 32]; 32] = Default::default(); |
||||
sol_proof |
||||
.iter_mut() |
||||
.enumerate() |
||||
.for_each(|(i, elem)| *elem = proof.path[i].to_fixed_bytes()); |
||||
|
||||
let process_call = ProcessCall { |
||||
inbox: self.inbox_address, |
||||
root: multisig_signed_checkpoint.checkpoint.root.to_fixed_bytes(), |
||||
index: multisig_signed_checkpoint.checkpoint.index.into(), |
||||
signatures: multisig_signed_checkpoint |
||||
.signatures |
||||
.iter() |
||||
.map(|s| s.to_vec().into()) |
||||
.collect(), |
||||
message: message.to_vec().into(), |
||||
proof: sol_proof, |
||||
leaf_index: proof.index.into(), |
||||
}; |
||||
|
||||
process_call.encode() |
||||
} |
||||
|
||||
fn contract_address(&self) -> abacus_core::Address { |
||||
self.contract.address().into() |
||||
} |
||||
} |
||||
|
||||
impl<M> EthereumInboxValidatorManager<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
/// Returns a ContractCall that processes the provided message.
|
||||
/// If the provided tx_gas_limit is None, gas estimation occurs.
|
||||
async fn process_contract_call( |
||||
&self, |
||||
multisig_signed_checkpoint: &MultisigSignedCheckpoint, |
||||
message: &AbacusMessage, |
||||
proof: &Proof, |
||||
tx_gas_limit: Option<U256>, |
||||
) -> Result<ContractCall<M, ()>, ChainCommunicationError> { |
||||
let mut sol_proof: [[u8; 32]; 32] = Default::default(); |
||||
sol_proof |
||||
.iter_mut() |
||||
.enumerate() |
||||
.for_each(|(i, elem)| *elem = proof.path[i].to_fixed_bytes()); |
||||
|
||||
let tx = self.contract.process( |
||||
self.inbox_address, |
||||
multisig_signed_checkpoint.checkpoint.root.to_fixed_bytes(), |
||||
multisig_signed_checkpoint.checkpoint.index.into(), |
||||
multisig_signed_checkpoint |
||||
.signatures |
||||
.iter() |
||||
.map(|s| s.to_vec().into()) |
||||
.collect(), |
||||
message.to_vec().into(), |
||||
sol_proof, |
||||
proof.index.into(), |
||||
); |
||||
let gas_limit = if let Some(gas_limit) = tx_gas_limit { |
||||
gas_limit |
||||
} else { |
||||
tx.estimate_gas().await?.saturating_add(U256::from(100000)) |
||||
}; |
||||
Ok(tx.gas(gas_limit)) |
||||
} |
||||
} |
Loading…
Reference in new issue