From 2b3b82a87d47fa659d1e8317e58764ffe964599b Mon Sep 17 00:00:00 2001
From: smtmfft <smtm@taiko.xyz>
Date: Fri, 26 Jul 2024 13:28:01 +0800
Subject: [PATCH] use forked verifier set together with taiko hard forks

Signed-off-by: smtmfft <smtm@taiko.xyz>
---
 core/src/lib.rs                          |  16 ++--
 core/src/preflight.rs                    |   1 -
 host/config/chain_spec_list_default.json |  59 ++++++++----
 lib/src/builder.rs                       |  35 ++++++-
 lib/src/consts.rs                        | 112 +++++++++++++++++++++--
 lib/src/input.rs                         |  16 ++++
 lib/src/protocol_instance.rs             |  54 +++++------
 provers/sgx/setup/src/app_args.rs        |   4 +
 provers/sgx/setup/src/setup_bootstrap.rs |  10 +-
 9 files changed, 236 insertions(+), 71 deletions(-)

diff --git a/core/src/lib.rs b/core/src/lib.rs
index 0f0c143e8..18e48afd0 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -16,6 +16,7 @@ use raiko_lib::{
     input::{GuestInput, GuestOutput, TaikoProverData},
     prover::{IdStore, IdWrite},
 };
+use reth_primitives::revm_primitives::SpecId;
 use reth_primitives::Header;
 use serde_json::Value;
 use std::{collections::HashMap, hint::black_box};
@@ -52,8 +53,11 @@ impl Raiko {
         provider: BDP,
     ) -> RaikoResult<GuestInput> {
         //TODO: read fork from config
-        if self.request.block_number <= 999999999 {
-            preflight(
+        match self
+            .taiko_chain_spec
+            .active_fork(self.request.block_number, 0)?
+        {
+            SpecId::HEKLA => preflight(
                 provider,
                 self.request.block_number,
                 self.l1_chain_spec.to_owned(),
@@ -65,9 +69,8 @@ impl Raiko {
                 self.request.blob_proof_type.clone(),
             )
             .await
-            .map_err(Into::<RaikoError>::into)
-        } else {
-            crate::preflight::ontake::preflight(
+            .map_err(Into::<RaikoError>::into),
+            SpecId::ONTAKE => crate::preflight::ontake::preflight(
                 provider,
                 self.request.block_number,
                 self.request.block_number,
@@ -80,7 +83,8 @@ impl Raiko {
                 self.request.blob_proof_type.clone(),
             )
             .await
-            .map_err(Into::<RaikoError>::into)
+            .map_err(Into::<RaikoError>::into),
+            _ => Err(RaikoError::Preflight("Unsupported fork".to_owned())),
         }
     }
 
diff --git a/core/src/preflight.rs b/core/src/preflight.rs
index 71c405cb2..e00bfe032 100644
--- a/core/src/preflight.rs
+++ b/core/src/preflight.rs
@@ -38,7 +38,6 @@ pub mod ontake;
 
 pub use hekla::*;
 
-
 // block_time_to_block_slot returns the slots of the given timestamp.
 fn block_time_to_block_slot(
     block_time: u64,
diff --git a/host/config/chain_spec_list_default.json b/host/config/chain_spec_list_default.json
index 37921d266..5aac0a615 100644
--- a/host/config/chain_spec_list_default.json
+++ b/host/config/chain_spec_list_default.json
@@ -27,10 +27,12 @@
         "l2_contract": null,
         "rpc": "https://rpc.ankr.com/eth",
         "beacon_rpc": "https://ethereum-beacon-api.publicnode.com",
-        "verifier_address": {
-            "SGX":"0x532efbf6d62720d0b2a2bb9d11066e8588cae6d9",
-            "SP1":null,
-            "RISC0":"0x0000000000000000000000000000000000000000"
+        "verifier_address_forks": {
+            "FRONTIER": {
+                "SGX": "0x532efbf6d62720d0b2a2bb9d11066e8588cae6d9",
+                "SP1": null,
+                "RISC0": "0x0000000000000000000000000000000000000000"
+            }
         },
         "genesis_time": 1606824023,
         "seconds_per_slot": 12,
@@ -61,10 +63,12 @@
         "l2_contract": null,
         "rpc": "https://ethereum-holesky-rpc.publicnode.com",
         "beacon_rpc": "https://fabled-weathered-cherry.ethereum-holesky.quiknode.pro/8f1c66935fa5f9afbda0db43318fe3c9e7b061e1/",
-        "verifier_address": {
-            "SGX":"0x532efbf6d62720d0b2a2bb9d11066e8588cae6d9",
-            "SP1":null,
-            "RISC0":"0x0000000000000000000000000000000000000000"
+        "verifier_address_forks": {
+            "FRONTIER": {
+                "SGX": "0x532efbf6d62720d0b2a2bb9d11066e8588cae6d9",
+                "SP1": null,
+                "RISC0": "0x0000000000000000000000000000000000000000"
+            }
         },
         "genesis_time": 1695902400,
         "seconds_per_slot": 12,
@@ -73,11 +77,14 @@
     {
         "name": "taiko_a7",
         "chain_id": 167009,
-        "max_spec_id": "SHANGHAI",
+        "max_spec_id": "ONTAKE",
         "hard_forks": {
-            "SHANGHAI": {
+            "HEKLA": {
                 "Block": 0
             },
+            "ONTAKE": {
+                "Block": 999999
+            },
             "CANCUN": "TBD"
         },
         "eip_1559_constants": {
@@ -90,10 +97,17 @@
         "l2_contract": "0x1670090000000000000000000000000000010001",
         "rpc": "https://rpc.hekla.taiko.xyz",
         "beacon_rpc": null,
-        "verifier_address":{
-            "SGX":"0x532efbf6d62720d0b2a2bb9d11066e8588cae6d9",
-            "SP1":null,
-            "RISC0":"0x0000000000000000000000000000000000000000"
+        "verifier_address_forks": {
+            "HEKLA": {
+                "SGX": "0x532efbf6d62720d0b2a2bb9d11066e8588cae6d9",
+                "SP1": null,
+                "RISC0": "0x0000000000000000000000000000000000000000"
+            },
+            "ONTAKE": {
+                "SGX": "0xf6d620d0b2a2bb9d11066e8532efb72588cae6d9",
+                "SP1": null,
+                "RISC0": "0x0000000000000000000000000000000000000000"
+            }
         },
         "genesis_time": 0,
         "seconds_per_slot": 1,
@@ -102,11 +116,14 @@
     {
         "name": "taiko_mainnet",
         "chain_id": 167000,
-        "max_spec_id": "SHANGHAI",
+        "max_spec_id": "ONTAKE",
         "hard_forks": {
-            "SHANGHAI": {
+            "HEKLA": {
                 "Block": 0
             },
+            "ONTAKE": {
+                "Block": 999999
+            },
             "CANCUN": "TBD"
         },
         "eip_1559_constants": {
@@ -119,10 +136,12 @@
         "l2_contract": "0x1670000000000000000000000000000000010001",
         "rpc": "https://rpc.mainnet.taiko.xyz",
         "beacon_rpc": null,
-        "verifier_address": {
-            "SGX":"0xb0f3186FC1963f774f52ff455DC86aEdD0b31F81",
-            "SP1":null,
-            "RISC0":"0x0000000000000000000000000000000000000000"
+        "verifier_address_forks": {
+            "HEKLA": {
+                "SGX": "0xb0f3186FC1963f774f52ff455DC86aEdD0b31F81",
+                "SP1": null,
+                "RISC0": "0x0000000000000000000000000000000000000000"
+            }
         },
         "genesis_time": 0,
         "seconds_per_slot": 1,
diff --git a/lib/src/builder.rs b/lib/src/builder.rs
index bc662681e..bd4d91972 100644
--- a/lib/src/builder.rs
+++ b/lib/src/builder.rs
@@ -12,7 +12,9 @@ use crate::{
     CycleTracker,
 };
 use anyhow::{bail, ensure, Result};
-use reth_chainspec::{ChainSpecBuilder, HOLESKY, MAINNET, TAIKO_A7, TAIKO_DEV, TAIKO_MAINNET};
+use reth_chainspec::{
+    ChainSpecBuilder, Hardfork, HOLESKY, MAINNET, TAIKO_A7, TAIKO_DEV, TAIKO_MAINNET,
+};
 use reth_evm::execute::{BlockExecutionOutput, BlockValidationError, Executor, ProviderError};
 use reth_evm_ethereum::execute::{
     validate_block_post_execution, Consensus, EthBeaconConsensus, EthExecutorProvider,
@@ -20,7 +22,7 @@ use reth_evm_ethereum::execute::{
 use reth_evm_ethereum::taiko::TaikoData;
 use reth_primitives::revm_primitives::db::{Database, DatabaseCommit};
 use reth_primitives::revm_primitives::{
-    Account, AccountInfo, AccountStatus, Bytecode, Bytes, HashMap,
+    Account, AccountInfo, AccountStatus, Bytecode, Bytes, HashMap, SpecId,
 };
 use reth_primitives::{Address, BlockWithSenders, Header, B256, KECCAK_EMPTY, U256};
 use tracing::debug;
@@ -96,6 +98,35 @@ impl<DB: Database<Error = ProviderError> + DatabaseCommit + OptimisticDatabase>
             _ => unimplemented!(),
         };
 
+        if reth_chain_spec.is_taiko() {
+            let block_num = self.input.taiko.block_proposed.block_number();
+            let block_timestamp = 0u64; // self.input.taiko.block_proposed.block_timestamp();
+            let taiko_fork = self
+                .input
+                .chain_spec
+                .spec_id(block_num, block_timestamp)
+                .unwrap();
+            match taiko_fork {
+                SpecId::HEKLA => {
+                    assert!(
+                        reth_chain_spec
+                            .fork(Hardfork::Ontake)
+                            .active_at_block(block_num),
+                        "evm fork is not active, please update the chain spec"
+                    );
+                }
+                SpecId::ONTAKE => {
+                    assert!(
+                        reth_chain_spec
+                            .fork(Hardfork::Ontake)
+                            .active_at_block(block_num),
+                        "evm fork is not active, please update the chain spec"
+                    );
+                }
+                _ => unimplemented!(),
+            }
+        }
+
         // Generate the transactions from the tx list
         let mut block = self.input.block.clone();
         block.body = generate_transactions(
diff --git a/lib/src/consts.rs b/lib/src/consts.rs
index bc941fd1e..6ebd88a28 100644
--- a/lib/src/consts.rs
+++ b/lib/src/consts.rs
@@ -148,7 +148,7 @@ pub struct ChainSpec {
     pub l2_contract: Option<Address>,
     pub rpc: String,
     pub beacon_rpc: Option<String>,
-    pub verifier_address: BTreeMap<VerifierType, Option<Address>>,
+    pub verifier_address_forks: BTreeMap<SpecId, BTreeMap<VerifierType, Option<Address>>>,
     pub genesis_time: u64,
     pub seconds_per_slot: u64,
     pub is_taiko: bool,
@@ -173,7 +173,7 @@ impl ChainSpec {
             l2_contract: None,
             rpc: "".to_string(),
             beacon_rpc: None,
-            verifier_address: BTreeMap::new(),
+            verifier_address_forks: BTreeMap::new(),
             genesis_time: 0u64,
             seconds_per_slot: 1u64,
             is_taiko,
@@ -204,7 +204,7 @@ impl ChainSpec {
         &self.eip_1559_constants
     }
 
-    fn spec_id(&self, block_no: BlockNumber, timestamp: u64) -> Option<SpecId> {
+    pub fn spec_id(&self, block_no: BlockNumber, timestamp: u64) -> Option<SpecId> {
         for (spec_id, fork) in self.hard_forks.iter().rev() {
             if fork.active(block_no, timestamp) {
                 return Some(*spec_id);
@@ -213,6 +213,26 @@ impl ChainSpec {
         None
     }
 
+    pub fn get_fork_verifier_address(
+        &self,
+        block_num: u64,
+        verifier_type: VerifierType,
+    ) -> Result<Address> {
+        // fall down to the first fork that is active as default
+        for (spec_id, fork) in self.hard_forks.iter().rev() {
+            if fork.active(block_num, 0u64) {
+                if let Some(fork_verifier) = self.verifier_address_forks.get(&spec_id) {
+                    return fork_verifier
+                        .get(&verifier_type)
+                        .unwrap()
+                        .ok_or_else(|| anyhow!("Verifier address not found"));
+                }
+            }
+        }
+
+        Err(anyhow!("fork verifier is not active"))
+    }
+
     pub fn is_taiko(&self) -> bool {
         self.is_taiko
     }
@@ -249,6 +269,8 @@ impl std::fmt::Display for Network {
 
 #[cfg(test)]
 mod tests {
+    use reth_primitives::address;
+
     use super::*;
 
     #[test]
@@ -265,6 +287,77 @@ mod tests {
         );
     }
 
+    #[test]
+    fn raiko_active_fork() {
+        let eth_mainnet_spec = SupportedChainSpecs::default()
+            .get_chain_spec(&Network::Ethereum.to_string())
+            .unwrap();
+        assert_eq!(
+            eth_mainnet_spec.active_fork(0, 0).unwrap(),
+            SpecId::FRONTIER
+        );
+        assert_eq!(
+            eth_mainnet_spec.active_fork(15_537_394, 0).unwrap(),
+            SpecId::MERGE
+        );
+        assert_eq!(
+            eth_mainnet_spec.active_fork(17_034_869, 0).unwrap(),
+            SpecId::MERGE
+        );
+        assert_eq!(
+            eth_mainnet_spec.active_fork(17_034_870, 0).unwrap(),
+            SpecId::SHANGHAI
+        );
+
+        let taiko_mainnet_spec = SupportedChainSpecs::default()
+        .get_chain_spec(&Network::TaikoMainnet.to_string())
+        .unwrap();
+        assert_eq!(
+            taiko_mainnet_spec.active_fork(0, 0).unwrap(),
+            SpecId::HEKLA
+        );
+        assert_eq!(
+            taiko_mainnet_spec.active_fork(999998, 0).unwrap(),
+            SpecId::HEKLA
+        );
+        assert_eq!(
+            taiko_mainnet_spec.active_fork(999999, 0).unwrap(),
+            SpecId::ONTAKE
+        );
+    }
+
+    #[test]
+    fn forked_verifier_address() {
+        let eth_mainnet_spec = SupportedChainSpecs::default()
+            .get_chain_spec(&Network::Ethereum.to_string())
+            .unwrap();
+        let verifier_address = eth_mainnet_spec
+            .get_fork_verifier_address(15_537_394, VerifierType::SGX)
+            .unwrap();
+        assert_eq!(
+            verifier_address,
+            address!("532efbf6d62720d0b2a2bb9d11066e8588cae6d9")
+        );
+
+        let hekla_mainnet_spec = SupportedChainSpecs::default()
+            .get_chain_spec(&Network::TaikoA7.to_string())
+            .unwrap();
+        let verifier_address = hekla_mainnet_spec
+            .get_fork_verifier_address(12345, VerifierType::SGX)
+            .unwrap();
+        assert_eq!(
+            verifier_address,
+            address!("532efbf6d62720d0b2a2bb9d11066e8588cae6d9")
+        );
+        let verifier_address = hekla_mainnet_spec
+            .get_fork_verifier_address(15_537_394, VerifierType::SGX)
+            .unwrap();
+        assert_eq!(
+            verifier_address,
+            address!("f6d620d0b2a2bb9d11066e8532efb72588cae6d9")
+        );
+    }
+
     #[ignore]
     #[test]
     fn serde_chain_spec() {
@@ -288,11 +381,14 @@ mod tests {
             l2_contract: None,
             rpc: "".to_string(),
             beacon_rpc: None,
-            verifier_address: BTreeMap::from([
-                (VerifierType::SGX, Some(Address::default())),
-                (VerifierType::SP1, None),
-                (VerifierType::RISC0, Some(Address::default())),
-            ]),
+            verifier_address_forks: BTreeMap::from([(
+                SpecId::FRONTIER,
+                BTreeMap::from([
+                    (VerifierType::SGX, Some(Address::default())),
+                    (VerifierType::SP1, None),
+                    (VerifierType::RISC0, Some(Address::default())),
+                ]),
+            )]),
             genesis_time: 0u64,
             seconds_per_slot: 1u64,
             is_taiko: false,
diff --git a/lib/src/input.rs b/lib/src/input.rs
index c96155fd2..bc58fdab8 100644
--- a/lib/src/input.rs
+++ b/lib/src/input.rs
@@ -73,6 +73,22 @@ impl BlockProposedFork {
             _ => false,
         }
     }
+
+    pub fn block_number(&self) -> u64 {
+        match self {
+            BlockProposedFork::Hekla(block) => block.meta.id,
+            BlockProposedFork::Ontake(block) => block.meta.id,
+            _ => 0,
+        }
+    }
+
+    pub fn block_timestamp(&self) -> u64 {
+        match self {
+            BlockProposedFork::Hekla(block) => block.meta.timestamp,
+            BlockProposedFork::Ontake(block) => block.meta.timestamp,
+            _ => 0,
+        }
+    }
 }
 
 #[serde_as]
diff --git a/lib/src/protocol_instance.rs b/lib/src/protocol_instance.rs
index 2f365e203..e76728983 100644
--- a/lib/src/protocol_instance.rs
+++ b/lib/src/protocol_instance.rs
@@ -28,29 +28,27 @@ impl BlockMetaDataFork {
     fn from(input: &GuestInput, header: &Header, tx_list_hash: B256) -> Self {
         match &input.taiko.block_proposed {
             BlockProposedFork::Nothing => unimplemented!("no block proposed"),
-            BlockProposedFork::Hekla(block_proposed) => {
-                BlockMetaDataFork::Hekla(BlockMetadata {
-                    l1Hash: input.taiko.l1_header.hash_slow(),
-                    difficulty: block_proposed.meta.difficulty,
-                    blobHash: tx_list_hash,
-                    extraData: bytes_to_bytes32(&header.extra_data).into(),
-                    depositsHash: keccak(Vec::<EthDeposit>::new().abi_encode()).into(),
-                    coinbase: header.beneficiary,
-                    id: header.number,
-                    gasLimit: (header.gas_limit
-                        - if input.chain_spec.is_taiko() {
-                            ANCHOR_GAS_LIMIT
-                        } else {
-                            0
-                        }) as u32,
-                    timestamp: header.timestamp,
-                    l1Height: input.taiko.l1_header.number,
-                    minTier: block_proposed.meta.minTier,
-                    blobUsed: block_proposed.meta.blobUsed,
-                    parentMetaHash: block_proposed.meta.parentMetaHash,
-                    sender: block_proposed.meta.sender,
-                })
-            }
+            BlockProposedFork::Hekla(block_proposed) => BlockMetaDataFork::Hekla(BlockMetadata {
+                l1Hash: input.taiko.l1_header.hash_slow(),
+                difficulty: block_proposed.meta.difficulty,
+                blobHash: tx_list_hash,
+                extraData: bytes_to_bytes32(&header.extra_data).into(),
+                depositsHash: keccak(Vec::<EthDeposit>::new().abi_encode()).into(),
+                coinbase: header.beneficiary,
+                id: header.number,
+                gasLimit: (header.gas_limit
+                    - if input.chain_spec.is_taiko() {
+                        ANCHOR_GAS_LIMIT
+                    } else {
+                        0
+                    }) as u32,
+                timestamp: header.timestamp,
+                l1Height: input.taiko.l1_header.number,
+                minTier: block_proposed.meta.minTier,
+                blobUsed: block_proposed.meta.blobUsed,
+                parentMetaHash: block_proposed.meta.parentMetaHash,
+                sender: block_proposed.meta.sender,
+            }),
             BlockProposedFork::Ontake(block_proposed_v2) => {
                 BlockMetaDataFork::Ontake(BlockMetadataV2 {
                     anchorBlockHash: input.taiko.l1_header.hash_slow(),
@@ -177,12 +175,9 @@ impl ProtocolInstance {
             );
         }
 
-        let verifier_address = (*input
+        let verifier_address = input
             .chain_spec
-            .verifier_address
-            .get(&proof_type)
-            .unwrap_or(&None))
-        .unwrap_or_default();
+            .get_fork_verifier_address(input.taiko.block_proposed.block_number(), proof_type)?;
 
         let pi = ProtocolInstance {
             transition: Transition {
@@ -202,7 +197,8 @@ impl ProtocolInstance {
         // Sanity check
         if input.chain_spec.is_taiko() {
             ensure!(
-                pi.block_metadata.match_block_proposal(&input.taiko.block_proposed),
+                pi.block_metadata
+                    .match_block_proposal(&input.taiko.block_proposed),
                 format!(
                     "block hash mismatch, expected: {:?}, got: {:?}",
                     input.taiko.block_proposed, pi.block_metadata
diff --git a/provers/sgx/setup/src/app_args.rs b/provers/sgx/setup/src/app_args.rs
index 459fd04ac..c67e4ad7f 100644
--- a/provers/sgx/setup/src/app_args.rs
+++ b/provers/sgx/setup/src/app_args.rs
@@ -37,6 +37,10 @@ pub struct BootstrapArgs {
 
     #[arg(long, default_value = "taiko_a7")]
     pub network: String,
+
+    /// block_num to get the verifier address for different fork
+    #[arg(long, default_value = "0")]
+    pub block_num: u64,
 }
 
 fn get_default_raiko_user_config_path(subdir: &str) -> PathBuf {
diff --git a/provers/sgx/setup/src/setup_bootstrap.rs b/provers/sgx/setup/src/setup_bootstrap.rs
index 2ae7a419d..1ea49c326 100644
--- a/provers/sgx/setup/src/setup_bootstrap.rs
+++ b/provers/sgx/setup/src/setup_bootstrap.rs
@@ -59,15 +59,15 @@ pub(crate) async fn setup_bootstrap(
         // clean check file
         remove_instance_id(&config_dir)?;
         let bootstrap_proof = bootstrap(secret_dir, gramine_cmd()).await?;
+        let verifier_address = taiko_chain_spec.get_fork_verifier_address(
+            bootstrap_args.block_num,
+            VerifierType::SGX,
+        )?;
         let register_id = register_sgx_instance(
             &bootstrap_proof.quote,
             &l1_chain_spec.rpc,
             l1_chain_spec.chain_id,
-            taiko_chain_spec
-                .verifier_address
-                .get(&VerifierType::SGX)
-                .unwrap()
-                .unwrap(),
+            verifier_address,
         )
         .await
         .map_err(|e| anyhow::Error::msg(e.to_string()))?;