From e65d9f1549296ffdd6bc1a2428b984bc9437c3ee Mon Sep 17 00:00:00 2001
From: cryptoAtwill <willes.lau@protocol.ai>
Date: Fri, 27 Oct 2023 13:34:08 +0800
Subject: [PATCH] query event

---
 ipc/provider/src/checkpoint.rs          | 29 +++++++++++++++++--------
 ipc/provider/src/manager/evm/manager.rs | 28 +++++++++++++++++++++---
 ipc/provider/src/manager/subnet.rs      |  4 +++-
 ipc/sdk/src/checkpoint.rs               |  9 ++++++++
 4 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/ipc/provider/src/checkpoint.rs b/ipc/provider/src/checkpoint.rs
index db2f218e..9967cc45 100644
--- a/ipc/provider/src/checkpoint.rs
+++ b/ipc/provider/src/checkpoint.rs
@@ -156,16 +156,27 @@ impl<T: BottomUpCheckpointRelayer + Send + Sync + 'static> BottomUpCheckpointMan
             return Ok(());
         }
 
-        let bundle = self
-            .child_handler
-            .checkpoint_bundle_at(next_submission_height)
-            .await?;
-        log::debug!("bottom up bundle: {bundle:?}");
+        let prev_submission_height = next_submission_height - self.checkpoint_period();
 
-        self.parent_handler
-            .submit_checkpoint(submitter, bundle)
-            .await
-            .map_err(|e| anyhow!("cannot submit bottom up checkpoint due to: {e:}"))?;
+        for h in (prev_submission_height + 1)..=current_height {
+            let events = self.child_handler.quorum_reached_events(h).await?;
+            if events.is_empty() {
+                continue;
+            }
+
+            for event in events {
+                let bundle = self
+                    .child_handler
+                    .checkpoint_bundle_at(event.height)
+                    .await?;
+                log::debug!("bottom up bundle: {bundle:?}");
+
+                self.parent_handler
+                    .submit_checkpoint(submitter, bundle)
+                    .await
+                    .map_err(|e| anyhow!("cannot submit bottom up checkpoint due to: {e:}"))?;
+            }
+        }
 
         Ok(())
     }
diff --git a/ipc/provider/src/manager/evm/manager.rs b/ipc/provider/src/manager/evm/manager.rs
index 8f06ccee..b7075d1c 100644
--- a/ipc/provider/src/manager/evm/manager.rs
+++ b/ipc/provider/src/manager/evm/manager.rs
@@ -7,8 +7,8 @@ use std::time::Duration;
 
 use ethers::types::H256;
 use ipc_actors_abis::{
-    gateway_getter_facet, gateway_manager_facet, gateway_messenger_facet, lib_staking_change_log,
-    subnet_actor_getter_facet, subnet_actor_manager_facet, subnet_registry,
+    gateway_getter_facet, gateway_manager_facet, gateway_messenger_facet, gateway_router_facet,
+    lib_staking_change_log, subnet_actor_getter_facet, subnet_actor_manager_facet, subnet_registry,
 };
 use ipc_sdk::evm::{fil_to_eth_amount, payload_to_evm_address, subnet_id_to_evm_addresses};
 use ipc_sdk::validator::from_contract_validators;
@@ -33,7 +33,7 @@ use ethers::types::{BlockId, Eip1559TransactionRequest, I256, U256};
 use fvm_shared::clock::ChainEpoch;
 use fvm_shared::{address::Address, econ::TokenAmount};
 use ipc_identity::{EthKeyAddress, EvmKeyStore, PersistentKeyStore};
-use ipc_sdk::checkpoint::{BottomUpCheckpoint, BottomUpCheckpointBundle};
+use ipc_sdk::checkpoint::{BottomUpCheckpoint, BottomUpCheckpointBundle, QuorumReachedEvent};
 use ipc_sdk::cross::CrossMsg;
 use ipc_sdk::gateway::Status;
 use ipc_sdk::staking::StakingChangeRequest;
@@ -965,6 +965,28 @@ impl BottomUpCheckpointRelayer for EthSubnetManager {
         })
     }
 
+    async fn quorum_reached_events(&self, height: ChainEpoch) -> Result<Vec<QuorumReachedEvent>> {
+        let contract = gateway_router_facet::GatewayRouterFacet::new(
+            self.ipc_contract_info.gateway_addr,
+            Arc::new(self.ipc_contract_info.provider.clone()),
+        );
+
+        let ev = contract
+            .event::<gateway_router_facet::QuorumReachedFilter>()
+            .from_block(height as u64)
+            .to_block(height as u64);
+
+        let mut events = vec![];
+        for (event, _meta) in ev.query_with_meta().await? {
+            events.push(QuorumReachedEvent {
+                height: event.height as ChainEpoch,
+                checkpoint: event.checkpoint.to_vec(),
+                quorum_weight: eth_to_fil_amount(&event.quorum_weight)?,
+            });
+        }
+
+        Ok(events)
+    }
     async fn current_epoch(&self) -> Result<ChainEpoch> {
         let epoch = self
             .ipc_contract_info
diff --git a/ipc/provider/src/manager/subnet.rs b/ipc/provider/src/manager/subnet.rs
index 7377072a..7455302d 100644
--- a/ipc/provider/src/manager/subnet.rs
+++ b/ipc/provider/src/manager/subnet.rs
@@ -7,7 +7,7 @@ use anyhow::Result;
 use async_trait::async_trait;
 use fvm_shared::clock::ChainEpoch;
 use fvm_shared::{address::Address, econ::TokenAmount};
-use ipc_sdk::checkpoint::BottomUpCheckpointBundle;
+use ipc_sdk::checkpoint::{BottomUpCheckpointBundle, QuorumReachedEvent};
 use ipc_sdk::cross::CrossMsg;
 use ipc_sdk::staking::StakingChangeRequest;
 use ipc_sdk::subnet::ConstructParams;
@@ -195,6 +195,8 @@ pub trait BottomUpCheckpointRelayer: Send + Sync {
     async fn checkpoint_period(&self, subnet_id: &SubnetID) -> Result<ChainEpoch>;
     /// Get the checkpoint bundle at a specific height. If it does not exist, it will through error.
     async fn checkpoint_bundle_at(&self, height: ChainEpoch) -> Result<BottomUpCheckpointBundle>;
+    /// Queries the quorum reached events at target height.
+    async fn quorum_reached_events(&self, height: ChainEpoch) -> Result<Vec<QuorumReachedEvent>>;
     /// Get the current epoch in the current subnet
     async fn current_epoch(&self) -> Result<ChainEpoch>;
 }
diff --git a/ipc/sdk/src/checkpoint.rs b/ipc/sdk/src/checkpoint.rs
index 7db89e67..7c6ef350 100644
--- a/ipc/sdk/src/checkpoint.rs
+++ b/ipc/sdk/src/checkpoint.rs
@@ -10,6 +10,7 @@ use cid::Cid;
 use fvm_ipld_encoding::DAG_CBOR;
 use fvm_shared::address::Address;
 use fvm_shared::clock::ChainEpoch;
+use fvm_shared::econ::TokenAmount;
 use lazy_static::lazy_static;
 use serde::{Deserialize, Serialize};
 
@@ -23,6 +24,14 @@ lazy_static! {
 
 pub type Signature = Vec<u8>;
 
+/// The event emitted
+#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
+pub struct QuorumReachedEvent {
+    pub height: ChainEpoch,
+    pub checkpoint: Vec<u8>,
+    pub quorum_weight: TokenAmount,
+}
+
 /// The collection of items for the bottom up checkpoint submission
 #[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
 pub struct BottomUpCheckpointBundle {