diff --git a/fendermint/app/src/app.rs b/fendermint/app/src/app.rs index 86551a6f..428fba9d 100644 --- a/fendermint/app/src/app.rs +++ b/fendermint/app/src/app.rs @@ -330,10 +330,7 @@ where Genesis = Vec, Output = FvmGenesisOutput, >, - I: ProposalInterpreter< - State = (), // TODO - Message = Vec, - >, + I: ProposalInterpreter>, I: ExecInterpreter< State = (CheckpointPool, FvmExecState), Message = Vec, @@ -517,7 +514,7 @@ where let txs = self .interpreter - .prepare((), txs) + .prepare(self.resolve_pool.clone(), txs) .await .context("failed to prepare proposal")?; @@ -536,7 +533,7 @@ where let accept = self .interpreter - .process((), txs) + .process(self.resolve_pool.clone(), txs) .await .context("failed to process proposal")?; diff --git a/fendermint/vm/interpreter/src/chain.rs b/fendermint/vm/interpreter/src/chain.rs index 395d26e0..b486d468 100644 --- a/fendermint/vm/interpreter/src/chain.rs +++ b/fendermint/vm/interpreter/src/chain.rs @@ -69,9 +69,7 @@ impl ProposalInterpreter for ChainMessageInterpreter where I: Sync + Send, { - // TODO: The state can include the IPLD Resolver mempool, for example by using STM - // to implement a shared memory space. - type State = (); + type State = CheckpointPool; type Message = ChainMessage; /// Check whether there are any "ready" messages in the IPLD resolution mempool which can be appended to the proposal. @@ -83,17 +81,33 @@ where _state: Self::State, msgs: Vec, ) -> anyhow::Result> { - // For now this is just a placeholder. + // TODO #195: Collect resolved CIDs ready to be proposed from the pool. Ok(msgs) } /// Perform finality checks on top-down transactions and availability checks on bottom-up transactions. - async fn process( - &self, - _state: Self::State, - _msgs: Vec, - ) -> anyhow::Result { - // For now this is just a placeholder. + async fn process(&self, state: Self::State, msgs: Vec) -> anyhow::Result { + let pool = state; + for msg in msgs { + if let ChainMessage::Ipc(IpcMessage::BottomUpExec(msg)) = msg { + let item = CheckpointPoolItem::BottomUp(msg); + + // We can just look in memory because when we start the application, we should retrieve any + // pending checkpoints (relayed but not executed) from the ledger, so they should be there. + // We don't have to validate the checkpoint here, because + // 1) we validated it when it was relayed, and + // 2) if a validator proposes something invalid, we can make them pay during execution. + let is_resolved = atomically(|| match pool.get_status(&item)? { + None => Ok(false), + Some(status) => status.is_resolved(), + }) + .await; + + if !is_resolved { + return Ok(false); + } + } + } Ok(true) } }