diff --git a/Cargo.lock b/Cargo.lock index dd9f53d3..9f996fb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2694,7 +2694,7 @@ dependencies = [ [[package]] name = "ipc_actors_abis" version = "0.1.0" -source = "git+https://github.com/consensus-shipyard/ipc-solidity-actors.git?branch=dev#ad80d9b29c98473042c42b8f9cae5c7453620c25" +source = "git+https://github.com/consensus-shipyard/ipc-solidity-actors.git?branch=dev#7a396cf0a72a96b5e3b2e457b9ca7e42e5c6b924" dependencies = [ "anyhow", "ethers", diff --git a/ipc/provider/src/checkpoint.rs b/ipc/provider/src/checkpoint.rs index 25b75f87..72319c4a 100644 --- a/ipc/provider/src/checkpoint.rs +++ b/ipc/provider/src/checkpoint.rs @@ -101,6 +101,47 @@ impl BottomUpCheckpointMan /// Submit the checkpoint from the target validator address pub async fn submit_checkpoint(&self, validator: &Address) -> Result<()> { + self.submit_last_epoch(validator).await?; + self.submit_next_epoch(validator).await + } + + async fn next_submission_height(&self) -> Result { + let last_checkpoint_epoch = self + .parent_handler + .last_bottom_up_checkpoint_height(&self.metadata.child.id) + .await + .map_err(|e| { + anyhow!("cannot obtain the last bottom up checkpoint height due to: {e:}") + })?; + Ok(last_checkpoint_epoch + self.checkpoint_period()) + } + + async fn submit_last_epoch(&self, validator: &Address) -> Result<()> { + let subnet = &self.metadata.child.id; + if self + .child_handler + .has_submitted_in_last_checkpoint_height(subnet, validator) + .await? + { + return Ok(()); + } + + let height = self + .child_handler + .last_bottom_up_checkpoint_height(subnet) + .await?; + let bundle = self.child_handler.checkpoint_bundle_at(height).await?; + log::debug!("bottom up bundle: {bundle:?}"); + + self.parent_handler + .submit_checkpoint(validator, bundle) + .await + .map_err(|e| anyhow!("cannot submit bottom up checkpoint due to: {e:}"))?; + + Ok(()) + } + + async fn submit_next_epoch(&self, validator: &Address) -> Result<()> { let next_submission_height = self.next_submission_height().await?; let current_height = self.child_handler.current_epoch().await?; @@ -121,15 +162,4 @@ impl BottomUpCheckpointMan Ok(()) } - - async fn next_submission_height(&self) -> Result { - let last_checkpoint_epoch = self - .parent_handler - .last_bottom_up_checkpoint_height(&self.metadata.child.id) - .await - .map_err(|e| { - anyhow!("cannot obtain the last bottom up checkpoint height due to: {e:}") - })?; - Ok(last_checkpoint_epoch + self.checkpoint_period()) - } } diff --git a/ipc/provider/src/manager/evm/manager.rs b/ipc/provider/src/manager/evm/manager.rs index eeaf6782..dd0fe34d 100644 --- a/ipc/provider/src/manager/evm/manager.rs +++ b/ipc/provider/src/manager/evm/manager.rs @@ -841,6 +841,23 @@ impl BottomUpCheckpointRelayer for EthSubnetManager { Ok(epoch as ChainEpoch) } + async fn has_submitted_in_last_checkpoint_height( + &self, + subnet_id: &SubnetID, + submitter: &Address, + ) -> Result { + let address = contract_address_from_subnet(subnet_id)?; + let contract = subnet_actor_getter_facet::SubnetActorGetterFacet::new( + address, + Arc::new(self.ipc_contract_info.provider.clone()), + ); + let addr = payload_to_evm_address(submitter.payload())?; + Ok(contract + .has_submitted_in_last_bottom_up_checkpoint_height(addr) + .call() + .await?) + } + async fn checkpoint_period(&self, subnet_id: &SubnetID) -> anyhow::Result { let address = contract_address_from_subnet(subnet_id)?; let contract = subnet_actor_getter_facet::SubnetActorGetterFacet::new( diff --git a/ipc/provider/src/manager/subnet.rs b/ipc/provider/src/manager/subnet.rs index bf3f3999..1952db9b 100644 --- a/ipc/provider/src/manager/subnet.rs +++ b/ipc/provider/src/manager/subnet.rs @@ -165,6 +165,12 @@ pub trait BottomUpCheckpointRelayer: Send + Sync { ) -> Result<()>; /// The last confirmed/submitted checkpoint height. async fn last_bottom_up_checkpoint_height(&self, subnet_id: &SubnetID) -> Result; + /// Check if the submitter has already submitted in the `last_bottom_up_checkpoint_height` + async fn has_submitted_in_last_checkpoint_height( + &self, + subnet_id: &SubnetID, + submitter: &Address, + ) -> Result; /// Get the checkpoint period, i.e the number of blocks to submit bottom up checkpoints. async fn checkpoint_period(&self, subnet_id: &SubnetID) -> Result; /// Get the checkpoint at a specific height. If it does not exist, it will through error.