From 206b7e98a012b7cd88b0bc492629c0a691b5197d Mon Sep 17 00:00:00 2001 From: "zero.qn" Date: Mon, 21 Jun 2021 22:33:41 +0800 Subject: [PATCH 1/4] feat: add test mode jsonrpc api --- Cargo.lock | 2 + crates/block-producer/Cargo.toml | 1 + crates/block-producer/src/lib.rs | 1 + crates/block-producer/src/runner.rs | 45 +++++-- .../block-producer/src/test_mode_control.rs | 116 ++++++++++++++++++ crates/config/src/config.rs | 29 +++++ crates/jsonrpc-types/src/lib.rs | 1 + crates/jsonrpc-types/src/test_mode.rs | 34 +++++ crates/rpc-server/Cargo.toml | 1 + crates/rpc-server/src/lib.rs | 1 + crates/rpc-server/src/server.rs | 33 ++++- crates/rpc-server/src/test_mode_registry.rs | 70 +++++++++++ crates/tools/src/generate_config.rs | 4 +- 13 files changed, 322 insertions(+), 16 deletions(-) create mode 100644 crates/block-producer/src/test_mode_control.rs create mode 100644 crates/jsonrpc-types/src/test_mode.rs create mode 100644 crates/rpc-server/src/test_mode_registry.rs diff --git a/Cargo.lock b/Cargo.lock index 9c91dd4f8..59cc1dd4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1976,6 +1976,7 @@ dependencies = [ "async-jsonrpc-client", "async-native-tls", "async-std", + "async-trait", "ckb-crypto", "ckb-fixed-hash", "ckb-types", @@ -2120,6 +2121,7 @@ dependencies = [ "async-jsonrpc-client", "async-native-tls", "async-std", + "async-trait", "bytes 1.0.1", "ckb-crypto", "ckb-fixed-hash", diff --git a/crates/block-producer/Cargo.toml b/crates/block-producer/Cargo.toml index f12fb3206..a193e892e 100644 --- a/crates/block-producer/Cargo.toml +++ b/crates/block-producer/Cargo.toml @@ -45,3 +45,4 @@ smol = "1.2.5" lazy_static = "1.4" sqlx = { version = "0.5", features = [ "runtime-async-std-native-tls", "postgres", "sqlite", "chrono", "decimal" ] } hex = "0.4" +async-trait = "0.1" diff --git a/crates/block-producer/src/lib.rs b/crates/block-producer/src/lib.rs index f2f163206..956854f19 100644 --- a/crates/block-producer/src/lib.rs +++ b/crates/block-producer/src/lib.rs @@ -6,6 +6,7 @@ pub mod produce_block; pub mod rpc_client; pub mod runner; pub mod stake; +pub mod test_mode_control; pub mod transaction_skeleton; pub mod types; pub mod utils; diff --git a/crates/block-producer/src/runner.rs b/crates/block-producer/src/runner.rs index c96a4e1fc..f0703f541 100644 --- a/crates/block-producer/src/runner.rs +++ b/crates/block-producer/src/runner.rs @@ -1,13 +1,13 @@ use crate::{ - block_producer::BlockProducer, poller::ChainUpdater, rpc_client::RPCClient, types::ChainEvent, - utils::CKBGenesisInfo, + block_producer::BlockProducer, poller::ChainUpdater, rpc_client::RPCClient, + test_mode_control::TestModeControl, types::ChainEvent, utils::CKBGenesisInfo, }; use anyhow::{anyhow, Context, Result}; use async_jsonrpc_client::HttpClient; use futures::{executor::block_on, select, FutureExt}; use gw_chain::chain::Chain; use gw_common::H256; -use gw_config::Config; +use gw_config::{Config, TestMode}; use gw_db::{config::Config as DBConfig, schema::COLUMNS, RocksDB}; use gw_generator::{ account_lock_manage::{secp256k1::Secp256k1Eth, AccountLockManage}, @@ -15,8 +15,11 @@ use gw_generator::{ genesis::init_genesis, Generator, RollupContext, }; +use gw_jsonrpc_types::test_mode::TestModePayload; use gw_mem_pool::pool::MemPool; -use gw_rpc_server::{registry::Registry, server::start_jsonrpc_server}; +use gw_rpc_server::{ + registry::Registry, server::start_jsonrpc_server, test_mode_registry::TestModeRegistry, +}; use gw_store::Store; use gw_types::{ bytes::Bytes, @@ -40,6 +43,7 @@ async fn poll_loop( rpc_client: RPCClient, chain_updater: ChainUpdater, block_producer: BlockProducer, + test_mode_control: TestModeControl, poll_interval: Duration, ) -> Result<()> { struct Inner { @@ -99,13 +103,20 @@ async fn poll_loop( err ); } - if let Err(err) = inner.block_producer.handle_event(event.clone()).await { - log::error!( - "Error occured when polling block_producer, event: {:?}, error: {}", - event, - err - ); + + if TestMode::Disable == test_mode_control.mode() + || TestMode::Enable == test_mode_control.mode() + && Some(TestModePayload::None) == test_mode_control.take_payload().await + { + if let Err(err) = inner.block_producer.handle_event(event.clone()).await { + log::error!( + "Error occured when polling block_producer, event: {:?}, error: {}", + event, + err + ); + } } + // } // }) // .detach(); @@ -217,6 +228,12 @@ pub fn run(config: Config) -> Result<()> { // RPC registry let rpc_registry = Registry::new(store.clone(), mem_pool.clone(), generator.clone()); + // Test mode rpc registry + let test_mode = config.test_mode.mode(); + let test_mode_control = + TestModeControl::create(test_mode, rpc_client.clone(), &block_producer_config)?; + let tests_rpc_registry = TestModeRegistry::new(test_mode_control.clone()); + // create web3 indexer let web3_indexer = match config.web3_indexer { Some(web3_indexer_config) => { @@ -301,13 +318,17 @@ pub fn run(config: Config) -> Result<()> { log::info!("Rollup config hash: {}", rollup_config_hash); } + if TestMode::Enable == test_mode { + log::info!("Test mode enabled!!!"); + } + smol::block_on(async { select! { _ = ctrl_c.recv().fuse() => log::info!("Exiting..."), - e = poll_loop(rpc_client, chain_updater, block_producer, Duration::from_secs(3)).fuse() => { + e = poll_loop(rpc_client, chain_updater, block_producer, test_mode_control ,Duration::from_secs(3)).fuse() => { log::error!("Error in main poll loop: {:?}", e); } - e = start_jsonrpc_server(rpc_address, rpc_registry).fuse() => { + e = start_jsonrpc_server(rpc_address, rpc_registry, tests_rpc_registry, test_mode).fuse() => { log::error!("Error running JSONRPC server: {:?}", e); exit(1); }, diff --git a/crates/block-producer/src/test_mode_control.rs b/crates/block-producer/src/test_mode_control.rs new file mode 100644 index 000000000..05d47e1d3 --- /dev/null +++ b/crates/block-producer/src/test_mode_control.rs @@ -0,0 +1,116 @@ +use crate::poa::{PoA, ShouldIssueBlock}; +use crate::rpc_client::RPCClient; +use crate::types::InputCellInfo; +use crate::wallet::Wallet; + +use anyhow::{anyhow, Context, Result}; +use async_trait::async_trait; +use ckb_types::prelude::{Builder, Entity}; +use gw_common::H256; +use gw_config::{BlockProducerConfig, TestMode}; +use gw_jsonrpc_types::{ + godwoken::GlobalState, + test_mode::{ShouldProduceBlock, TestModePayload}, +}; +use gw_rpc_server::test_mode_registry::TestModeRPC; +use gw_types::{packed::CellInput, prelude::Unpack}; +use smol::lock::Mutex; + +use std::sync::Arc; + +#[derive(Clone)] +pub struct TestModeControl { + mode: TestMode, + payload: Arc>>, + rpc_client: RPCClient, + poa: Arc>, +} + +impl TestModeControl { + pub fn create( + mode: TestMode, + rpc_client: RPCClient, + config: &BlockProducerConfig, + ) -> Result { + let wallet = Wallet::from_config(&config.wallet_config).with_context(|| "init wallet")?; + let poa = PoA::new( + rpc_client.clone(), + wallet.lock_script().to_owned(), + config.poa_lock_dep.clone().into(), + config.poa_state_dep.clone().into(), + ); + + Ok(TestModeControl { + mode, + payload: Arc::new(Mutex::new(None)), + rpc_client, + poa: Arc::new(Mutex::new(poa)), + }) + } + + pub fn mode(&self) -> TestMode { + self.mode + } + + pub async fn get_payload(&self) -> Option { + self.payload.lock().await.to_owned() + } + + pub async fn take_payload(&self) -> Option { + self.payload.lock().await.take() + } +} + +#[async_trait] +impl TestModeRPC for TestModeControl { + async fn get_global_state(&self) -> Result { + let rollup_cell = { + let opt = self.rpc_client.query_rollup_cell().await?; + opt.ok_or_else(|| anyhow!("rollup cell not found"))? + }; + + let global_state = gw_types::packed::GlobalState::from_slice(&rollup_cell.data) + .map_err(|_| anyhow!("parse rollup up global state"))?; + + Ok(global_state.into()) + } + + async fn next_global_state(&self, payload: TestModePayload) -> Result<()> { + *self.payload.lock().await = Some(payload); + + Ok(()) + } + + async fn should_produce_next_block(&self) -> Result { + let rollup_cell = { + let opt = self.rpc_client.query_rollup_cell().await?; + opt.ok_or_else(|| anyhow!("rollup cell not found"))? + }; + + let tip_hash: H256 = { + let l1_tip_hash_number = self.rpc_client.get_tip().await?; + let tip_hash: [u8; 32] = l1_tip_hash_number.block_hash().unpack(); + tip_hash.into() + }; + + let ret = { + let median_time = self.rpc_client.get_block_median_time(tip_hash).await?; + let poa_cell_input = InputCellInfo { + input: CellInput::new_builder() + .previous_output(rollup_cell.out_point.clone()) + .build(), + cell: rollup_cell.clone(), + }; + + let mut poa = self.poa.lock().await; + poa.should_issue_next_block(median_time, &poa_cell_input) + .await? + }; + + Ok(match ret { + ShouldIssueBlock::Yes => ShouldProduceBlock::Yes, + ShouldIssueBlock::YesIfFull => ShouldProduceBlock::YesIfFull, + ShouldIssueBlock::No => ShouldProduceBlock::No, + }) + } +} diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index d6c27dd50..c02a8b2c1 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -16,6 +16,7 @@ pub struct Config { pub rpc_server: RPCServerConfig, pub block_producer: Option, pub web3_indexer: Option, + pub test_mode: TestModeConfig, } #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] @@ -87,3 +88,31 @@ pub struct Web3IndexerConfig { pub polyjuice_script_type_hash: H256, pub eth_account_lock_hash: H256, } + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum TestMode { + Enable, + Disable, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct TestModeConfig { + pub enable: bool, +} + +impl TestModeConfig { + pub fn mode(&self) -> TestMode { + if self.enable { + TestMode::Enable + } else { + TestMode::Disable + } + } +} + +impl Default for TestModeConfig { + fn default() -> Self { + Self { enable: false } + } +} diff --git a/crates/jsonrpc-types/src/lib.rs b/crates/jsonrpc-types/src/lib.rs index 4160fa5e0..f917ec712 100644 --- a/crates/jsonrpc-types/src/lib.rs +++ b/crates/jsonrpc-types/src/lib.rs @@ -2,3 +2,4 @@ pub mod blockchain; pub mod godwoken; // re-exports pub use ckb_jsonrpc_types; +pub mod test_mode; diff --git a/crates/jsonrpc-types/src/test_mode.rs b/crates/jsonrpc-types/src/test_mode.rs new file mode 100644 index 000000000..a92429e22 --- /dev/null +++ b/crates/jsonrpc-types/src/test_mode.rs @@ -0,0 +1,34 @@ +use ckb_jsonrpc_types::{Uint32, Uint64}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)] +#[serde(rename_all = "snake_case")] +pub enum ShouldProduceBlock { + Yes, + YesIfFull, + No, +} + +#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)] +#[serde(rename_all = "snake_case")] +pub enum ChallengeType { + TxExecution, + TxSignature, + WithdrawalSignature, +} + +#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)] +#[serde(rename_all = "snake_case")] +pub enum TestModePayload { + None, + BadBlock { + target_index: Uint32, + target_type: ChallengeType, + }, + Challenge { + block_number: Uint64, + target_index: Uint32, + target_type: ChallengeType, + }, + WaitForChallengeMaturity, +} diff --git a/crates/rpc-server/Cargo.toml b/crates/rpc-server/Cargo.toml index b72ee4e15..6a512f317 100644 --- a/crates/rpc-server/Cargo.toml +++ b/crates/rpc-server/Cargo.toml @@ -39,3 +39,4 @@ serde_json = "1.0" smol = "1.2.5" tokio = { version = "1.0.1", default-features = false, features = ["rt-multi-thread"] } bytes-v10 = { version = "1.0", package = "bytes" } +async-trait = "0.1" diff --git a/crates/rpc-server/src/lib.rs b/crates/rpc-server/src/lib.rs index 1eb538bd3..90981f11b 100644 --- a/crates/rpc-server/src/lib.rs +++ b/crates/rpc-server/src/lib.rs @@ -1,2 +1,3 @@ pub mod registry; pub mod server; +pub mod test_mode_registry; diff --git a/crates/rpc-server/src/server.rs b/crates/rpc-server/src/server.rs index 926ebe071..8c1ec0388 100644 --- a/crates/rpc-server/src/server.rs +++ b/crates/rpc-server/src/server.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use std::task::{Context, Poll}; use anyhow::{Error, Result}; +use gw_config::TestMode; use hyper::service::{make_service_fn, service_fn}; use hyper::{body::HttpBody, Body, Method, Request, Response, Server}; use smol::{io, prelude::*, Async}; @@ -13,9 +14,19 @@ use smol::{io, prelude::*, Async}; use jsonrpc_v2::{RequestKind, ResponseObjects, Router, Server as JsonrpcServer}; use crate::registry::Registry; - -pub async fn start_jsonrpc_server(listen_addr: SocketAddr, registry: Registry) -> Result<()> { +use crate::test_mode_registry::{ + TestModeRegistry, TEST_MODE_URI_PATH_GLOBAL_STATE, TEST_MODE_URI_PATH_PRODUCE_BLOCK, +}; + +pub async fn start_jsonrpc_server( + listen_addr: SocketAddr, + registry: Registry, + tests_registry: TestModeRegistry, + test_mode: TestMode, +) -> Result<()> { let rpc_server = registry.build_rpc_server()?; + let tests_produce_block_rpc_server = tests_registry.build_produce_block_rpc_server()?; + let tests_global_state_rpc_server = tests_registry.build_global_state_rpc_server()?; let listener = Async::::bind(listen_addr)?; // Format the full address. @@ -27,7 +38,23 @@ pub async fn start_jsonrpc_server(listen_addr: SocketAddr, registry: Registry) - .executor(SmolExecutor) .serve(make_service_fn(move |_| { let rpc_server = Arc::clone(&rpc_server); - async { Ok::<_, Error>(service_fn(move |req| serve(Arc::clone(&rpc_server), req))) } + let tests_produce_block_rpc_server = Arc::clone(&tests_produce_block_rpc_server); + let tests_global_state_rpc_server = Arc::clone(&tests_global_state_rpc_server); + + async move { + Ok::<_, Error>(service_fn(move |req| { + let server = match req.uri().path() { + TEST_MODE_URI_PATH_PRODUCE_BLOCK if TestMode::Enable == test_mode => { + &tests_produce_block_rpc_server + } + TEST_MODE_URI_PATH_GLOBAL_STATE if TestMode::Enable == test_mode => { + &tests_global_state_rpc_server + } + _ => &rpc_server, + }; + serve(Arc::clone(&server), req) + })) + } })) .await?; diff --git a/crates/rpc-server/src/test_mode_registry.rs b/crates/rpc-server/src/test_mode_registry.rs new file mode 100644 index 000000000..dabc0c313 --- /dev/null +++ b/crates/rpc-server/src/test_mode_registry.rs @@ -0,0 +1,70 @@ +use anyhow::Result; +use async_trait::async_trait; +use gw_jsonrpc_types::{ + godwoken::GlobalState, + test_mode::{ShouldProduceBlock, TestModePayload}, +}; +use jsonrpc_v2::{Data, MapRouter, Params, Server, Server as JsonrpcServer}; + +use std::sync::Arc; + +type RPCServer = Arc>; +type BoxedRPCImpl = Box; + +pub const TEST_MODE_URI_PATH_PRODUCE_BLOCK: &str = "/tests/produce-block"; +pub const TEST_MODE_URI_PATH_GLOBAL_STATE: &str = "/tests/global-state"; + +#[async_trait] +pub trait TestModeRPC { + async fn get_global_state(&self) -> Result; + async fn next_global_state(&self, payload: TestModePayload) -> Result<()>; + async fn should_produce_next_block(&self) -> Result; +} + +pub struct TestModeRegistry { + rpc_impl: Arc, +} + +impl TestModeRegistry { + pub fn new(rpc_impl: T) -> Self { + Self { + rpc_impl: Arc::new(Box::new(rpc_impl)), + } + } + + pub fn build_produce_block_rpc_server(&self) -> Result { + let mut server = JsonrpcServer::new(); + + server = server + .with_data(Data(Arc::clone(&self.rpc_impl))) + .with_method("next_global_state", next_global_state) + .with_method("should_produce_next_block", should_produce_next_block); + + Ok(server.finish()) + } + + pub fn build_global_state_rpc_server(&self) -> Result { + let mut server = JsonrpcServer::new(); + + server = server + .with_data(Data(Arc::clone(&self.rpc_impl))) + .with_method("get_global_state", get_global_state); + + Ok(server.finish()) + } +} + +async fn next_global_state( + Params((payload,)): Params<(TestModePayload,)>, + rpc_impl: Data, +) -> Result<()> { + rpc_impl.next_global_state(payload).await +} + +async fn get_global_state(rpc_impl: Data) -> Result { + rpc_impl.get_global_state().await +} + +async fn should_produce_next_block(rpc_impl: Data) -> Result { + rpc_impl.should_produce_next_block().await +} diff --git a/crates/tools/src/generate_config.rs b/crates/tools/src/generate_config.rs index 26028c438..9912cc7fc 100644 --- a/crates/tools/src/generate_config.rs +++ b/crates/tools/src/generate_config.rs @@ -7,7 +7,7 @@ use ckb_sdk::HttpRpcClient; use ckb_types::prelude::Entity; use gw_config::{ BackendConfig, BlockProducerConfig, ChainConfig, Config, GenesisConfig, RPCClientConfig, - RPCServerConfig, StoreConfig, WalletConfig, Web3IndexerConfig, + RPCServerConfig, StoreConfig, TestModeConfig, WalletConfig, Web3IndexerConfig, }; use gw_jsonrpc_types::godwoken::L2BlockCommittedInfo; @@ -170,6 +170,7 @@ pub fn generate_config( }), None => None, }; + let test_mode = TestModeConfig { enable: false }; let config: Config = Config { backends, @@ -180,6 +181,7 @@ pub fn generate_config( rpc_server, block_producer, web3_indexer, + test_mode, }; let output_content = toml::to_string_pretty(&config).expect("serde toml to string pretty"); From 9f209a3e400cbd6723dba9dba44d30b00cad94e7 Mon Sep 17 00:00:00 2001 From: "zero.qn" Date: Tue, 22 Jun 2021 09:08:13 +0800 Subject: [PATCH 2/4] chore(block-producer): add test mode challenge todo --- crates/block-producer/src/runner.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/block-producer/src/runner.rs b/crates/block-producer/src/runner.rs index f0703f541..582b7193e 100644 --- a/crates/block-producer/src/runner.rs +++ b/crates/block-producer/src/runner.rs @@ -104,6 +104,7 @@ async fn poll_loop( ); } + // TODO: implement test mode challenge control if TestMode::Disable == test_mode_control.mode() || TestMode::Enable == test_mode_control.mode() && Some(TestModePayload::None) == test_mode_control.take_payload().await From e1aab8fae39e42b5b3330952094c7340ad642ad3 Mon Sep 17 00:00:00 2001 From: "zero.qn" Date: Wed, 23 Jun 2021 09:26:42 +0800 Subject: [PATCH 3/4] refactor: merge test_mode_registry and registry expose test mode jsonrpc through tests_* method --- crates/block-producer/src/runner.rs | 17 ++--- .../block-producer/src/test_mode_control.rs | 6 +- crates/rpc-server/src/lib.rs | 1 - crates/rpc-server/src/registry.rs | 54 +++++++++++++- crates/rpc-server/src/server.rs | 33 +-------- crates/rpc-server/src/test_mode_registry.rs | 70 ------------------- 6 files changed, 67 insertions(+), 114 deletions(-) delete mode 100644 crates/rpc-server/src/test_mode_registry.rs diff --git a/crates/block-producer/src/runner.rs b/crates/block-producer/src/runner.rs index 582b7193e..b20f29b17 100644 --- a/crates/block-producer/src/runner.rs +++ b/crates/block-producer/src/runner.rs @@ -17,9 +17,7 @@ use gw_generator::{ }; use gw_jsonrpc_types::test_mode::TestModePayload; use gw_mem_pool::pool::MemPool; -use gw_rpc_server::{ - registry::Registry, server::start_jsonrpc_server, test_mode_registry::TestModeRegistry, -}; +use gw_rpc_server::{registry::Registry, server::start_jsonrpc_server}; use gw_store::Store; use gw_types::{ bytes::Bytes, @@ -227,13 +225,16 @@ pub fn run(config: Config) -> Result<()> { )); // RPC registry - let rpc_registry = Registry::new(store.clone(), mem_pool.clone(), generator.clone()); - - // Test mode rpc registry let test_mode = config.test_mode.mode(); let test_mode_control = TestModeControl::create(test_mode, rpc_client.clone(), &block_producer_config)?; - let tests_rpc_registry = TestModeRegistry::new(test_mode_control.clone()); + let rpc_registry = Registry::new( + store.clone(), + mem_pool.clone(), + generator.clone(), + test_mode, + test_mode_control.clone(), + ); // create web3 indexer let web3_indexer = match config.web3_indexer { @@ -329,7 +330,7 @@ pub fn run(config: Config) -> Result<()> { e = poll_loop(rpc_client, chain_updater, block_producer, test_mode_control ,Duration::from_secs(3)).fuse() => { log::error!("Error in main poll loop: {:?}", e); } - e = start_jsonrpc_server(rpc_address, rpc_registry, tests_rpc_registry, test_mode).fuse() => { + e = start_jsonrpc_server(rpc_address, rpc_registry).fuse() => { log::error!("Error running JSONRPC server: {:?}", e); exit(1); }, diff --git a/crates/block-producer/src/test_mode_control.rs b/crates/block-producer/src/test_mode_control.rs index 05d47e1d3..0d7e21375 100644 --- a/crates/block-producer/src/test_mode_control.rs +++ b/crates/block-producer/src/test_mode_control.rs @@ -12,7 +12,7 @@ use gw_jsonrpc_types::{ godwoken::GlobalState, test_mode::{ShouldProduceBlock, TestModePayload}, }; -use gw_rpc_server::test_mode_registry::TestModeRPC; +use gw_rpc_server::registry::TestModeRPC; use gw_types::{packed::CellInput, prelude::Unpack}; use smol::lock::Mutex; @@ -75,13 +75,13 @@ impl TestModeRPC for TestModeControl { Ok(global_state.into()) } - async fn next_global_state(&self, payload: TestModePayload) -> Result<()> { + async fn produce_block(&self, payload: TestModePayload) -> Result<()> { *self.payload.lock().await = Some(payload); Ok(()) } - async fn should_produce_next_block(&self) -> Result { + async fn should_produce_block(&self) -> Result { let rollup_cell = { let opt = self.rpc_client.query_rollup_cell().await?; opt.ok_or_else(|| anyhow!("rollup cell not found"))? diff --git a/crates/rpc-server/src/lib.rs b/crates/rpc-server/src/lib.rs index 90981f11b..1eb538bd3 100644 --- a/crates/rpc-server/src/lib.rs +++ b/crates/rpc-server/src/lib.rs @@ -1,3 +1,2 @@ pub mod registry; pub mod server; -pub mod test_mode_registry; diff --git a/crates/rpc-server/src/registry.rs b/crates/rpc-server/src/registry.rs index 1193dac33..fd196ff8b 100644 --- a/crates/rpc-server/src/registry.rs +++ b/crates/rpc-server/src/registry.rs @@ -1,11 +1,14 @@ use anyhow::Result; +use async_trait::async_trait; use ckb_types::prelude::{Builder, Entity}; use gw_common::{state::State, H256}; +use gw_config::TestMode; use gw_generator::{sudt::build_l2_sudt_script, Generator}; use gw_jsonrpc_types::{ blockchain::Script, ckb_jsonrpc_types::{JsonBytes, Uint128, Uint32}, - godwoken::{L2BlockView, RunResult, TxReceipt}, + godwoken::{GlobalState, L2BlockView, RunResult, TxReceipt}, + test_mode::{ShouldProduceBlock, TestModePayload}, }; use gw_store::{ state_db::{CheckPoint, StateDBMode, StateDBTransaction, SubState}, @@ -25,6 +28,14 @@ type RPCServer = Arc>; type MemPool = Mutex; type AccountID = Uint32; type JsonH256 = ckb_fixed_hash::H256; +type BoxedTestsRPCImpl = Box; + +#[async_trait] +pub trait TestModeRPC { + async fn get_global_state(&self) -> Result; + async fn produce_block(&self, payload: TestModePayload) -> Result<()>; + async fn should_produce_block(&self) -> Result; +} fn to_h256(v: JsonH256) -> H256 { let h: [u8; 32] = v.into(); @@ -40,14 +51,27 @@ pub struct Registry { generator: Arc, mem_pool: Arc, store: Store, + test_mode: TestMode, + tests_rpc_impl: Arc, } impl Registry { - pub fn new(store: Store, mem_pool: Arc, generator: Arc) -> Self { + pub fn new( + store: Store, + mem_pool: Arc, + generator: Arc, + test_mode: TestMode, + tests_rpc_impl: T, + ) -> Self + where + T: TestModeRPC + Send + Sync + 'static, + { Self { mem_pool, store, generator, + test_mode, + tests_rpc_impl: Arc::new(Box::new(tests_rpc_impl)), } } @@ -84,6 +108,15 @@ impl Registry { .with_method("submit_withdrawal_request", submit_withdrawal_request) .with_method("compute_l2_sudt_script_hash", compute_l2_sudt_script_hash); + // Tests + if TestMode::Enable == self.test_mode { + server = server + .with_data(Data(Arc::clone(&self.tests_rpc_impl))) + .with_method("tests_produce_block", tests_produce_block) + .with_method("tests_should_produce_block", tests_should_produce_block) + .with_method("tests_get_global_state", tests_get_global_state); + } + Ok(server.finish()) } } @@ -384,3 +417,20 @@ async fn compute_l2_sudt_script_hash( build_l2_sudt_script(generator.rollup_context(), &to_h256(l1_sudt_script_hash)); Ok(to_jsonh256(l2_sudt_script.hash().into())) } + +async fn tests_produce_block( + Params((payload,)): Params<(TestModePayload,)>, + tests_rpc_impl: Data, +) -> Result<()> { + tests_rpc_impl.produce_block(payload).await +} + +async fn tests_get_global_state(tests_rpc_impl: Data) -> Result { + tests_rpc_impl.get_global_state().await +} + +async fn tests_should_produce_block( + tests_rpc_impl: Data, +) -> Result { + tests_rpc_impl.should_produce_block().await +} diff --git a/crates/rpc-server/src/server.rs b/crates/rpc-server/src/server.rs index 8c1ec0388..926ebe071 100644 --- a/crates/rpc-server/src/server.rs +++ b/crates/rpc-server/src/server.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use std::task::{Context, Poll}; use anyhow::{Error, Result}; -use gw_config::TestMode; use hyper::service::{make_service_fn, service_fn}; use hyper::{body::HttpBody, Body, Method, Request, Response, Server}; use smol::{io, prelude::*, Async}; @@ -14,19 +13,9 @@ use smol::{io, prelude::*, Async}; use jsonrpc_v2::{RequestKind, ResponseObjects, Router, Server as JsonrpcServer}; use crate::registry::Registry; -use crate::test_mode_registry::{ - TestModeRegistry, TEST_MODE_URI_PATH_GLOBAL_STATE, TEST_MODE_URI_PATH_PRODUCE_BLOCK, -}; - -pub async fn start_jsonrpc_server( - listen_addr: SocketAddr, - registry: Registry, - tests_registry: TestModeRegistry, - test_mode: TestMode, -) -> Result<()> { + +pub async fn start_jsonrpc_server(listen_addr: SocketAddr, registry: Registry) -> Result<()> { let rpc_server = registry.build_rpc_server()?; - let tests_produce_block_rpc_server = tests_registry.build_produce_block_rpc_server()?; - let tests_global_state_rpc_server = tests_registry.build_global_state_rpc_server()?; let listener = Async::::bind(listen_addr)?; // Format the full address. @@ -38,23 +27,7 @@ pub async fn start_jsonrpc_server( .executor(SmolExecutor) .serve(make_service_fn(move |_| { let rpc_server = Arc::clone(&rpc_server); - let tests_produce_block_rpc_server = Arc::clone(&tests_produce_block_rpc_server); - let tests_global_state_rpc_server = Arc::clone(&tests_global_state_rpc_server); - - async move { - Ok::<_, Error>(service_fn(move |req| { - let server = match req.uri().path() { - TEST_MODE_URI_PATH_PRODUCE_BLOCK if TestMode::Enable == test_mode => { - &tests_produce_block_rpc_server - } - TEST_MODE_URI_PATH_GLOBAL_STATE if TestMode::Enable == test_mode => { - &tests_global_state_rpc_server - } - _ => &rpc_server, - }; - serve(Arc::clone(&server), req) - })) - } + async { Ok::<_, Error>(service_fn(move |req| serve(Arc::clone(&rpc_server), req))) } })) .await?; diff --git a/crates/rpc-server/src/test_mode_registry.rs b/crates/rpc-server/src/test_mode_registry.rs deleted file mode 100644 index dabc0c313..000000000 --- a/crates/rpc-server/src/test_mode_registry.rs +++ /dev/null @@ -1,70 +0,0 @@ -use anyhow::Result; -use async_trait::async_trait; -use gw_jsonrpc_types::{ - godwoken::GlobalState, - test_mode::{ShouldProduceBlock, TestModePayload}, -}; -use jsonrpc_v2::{Data, MapRouter, Params, Server, Server as JsonrpcServer}; - -use std::sync::Arc; - -type RPCServer = Arc>; -type BoxedRPCImpl = Box; - -pub const TEST_MODE_URI_PATH_PRODUCE_BLOCK: &str = "/tests/produce-block"; -pub const TEST_MODE_URI_PATH_GLOBAL_STATE: &str = "/tests/global-state"; - -#[async_trait] -pub trait TestModeRPC { - async fn get_global_state(&self) -> Result; - async fn next_global_state(&self, payload: TestModePayload) -> Result<()>; - async fn should_produce_next_block(&self) -> Result; -} - -pub struct TestModeRegistry { - rpc_impl: Arc, -} - -impl TestModeRegistry { - pub fn new(rpc_impl: T) -> Self { - Self { - rpc_impl: Arc::new(Box::new(rpc_impl)), - } - } - - pub fn build_produce_block_rpc_server(&self) -> Result { - let mut server = JsonrpcServer::new(); - - server = server - .with_data(Data(Arc::clone(&self.rpc_impl))) - .with_method("next_global_state", next_global_state) - .with_method("should_produce_next_block", should_produce_next_block); - - Ok(server.finish()) - } - - pub fn build_global_state_rpc_server(&self) -> Result { - let mut server = JsonrpcServer::new(); - - server = server - .with_data(Data(Arc::clone(&self.rpc_impl))) - .with_method("get_global_state", get_global_state); - - Ok(server.finish()) - } -} - -async fn next_global_state( - Params((payload,)): Params<(TestModePayload,)>, - rpc_impl: Data, -) -> Result<()> { - rpc_impl.next_global_state(payload).await -} - -async fn get_global_state(rpc_impl: Data) -> Result { - rpc_impl.get_global_state().await -} - -async fn should_produce_next_block(rpc_impl: Data) -> Result { - rpc_impl.should_produce_next_block().await -} From e104929e81cffe93017e8764f5f492b0cf726de1 Mon Sep 17 00:00:00 2001 From: "zero.qn" Date: Wed, 23 Jun 2021 11:25:54 +0800 Subject: [PATCH 4/4] refactor: use TestMode directly in config --- crates/block-producer/src/runner.rs | 7 +++---- crates/config/src/config.rs | 21 +++------------------ crates/tools/src/generate_config.rs | 5 ++--- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/crates/block-producer/src/runner.rs b/crates/block-producer/src/runner.rs index b20f29b17..4704db43b 100644 --- a/crates/block-producer/src/runner.rs +++ b/crates/block-producer/src/runner.rs @@ -225,14 +225,13 @@ pub fn run(config: Config) -> Result<()> { )); // RPC registry - let test_mode = config.test_mode.mode(); let test_mode_control = - TestModeControl::create(test_mode, rpc_client.clone(), &block_producer_config)?; + TestModeControl::create(config.test_mode, rpc_client.clone(), &block_producer_config)?; let rpc_registry = Registry::new( store.clone(), mem_pool.clone(), generator.clone(), - test_mode, + config.test_mode, test_mode_control.clone(), ); @@ -320,7 +319,7 @@ pub fn run(config: Config) -> Result<()> { log::info!("Rollup config hash: {}", rollup_config_hash); } - if TestMode::Enable == test_mode { + if TestMode::Enable == config.test_mode { log::info!("Test mode enabled!!!"); } diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index c02a8b2c1..b99ac1009 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -8,6 +8,7 @@ use std::path::PathBuf; #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct Config { + pub test_mode: TestMode, pub backends: Vec, pub store: StoreConfig, pub genesis: GenesisConfig, @@ -16,7 +17,6 @@ pub struct Config { pub rpc_server: RPCServerConfig, pub block_producer: Option, pub web3_indexer: Option, - pub test_mode: TestModeConfig, } #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] @@ -96,23 +96,8 @@ pub enum TestMode { Disable, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct TestModeConfig { - pub enable: bool, -} - -impl TestModeConfig { - pub fn mode(&self) -> TestMode { - if self.enable { - TestMode::Enable - } else { - TestMode::Disable - } - } -} - -impl Default for TestModeConfig { +impl Default for TestMode { fn default() -> Self { - Self { enable: false } + TestMode::Disable } } diff --git a/crates/tools/src/generate_config.rs b/crates/tools/src/generate_config.rs index 9912cc7fc..6c8a0619c 100644 --- a/crates/tools/src/generate_config.rs +++ b/crates/tools/src/generate_config.rs @@ -7,7 +7,7 @@ use ckb_sdk::HttpRpcClient; use ckb_types::prelude::Entity; use gw_config::{ BackendConfig, BlockProducerConfig, ChainConfig, Config, GenesisConfig, RPCClientConfig, - RPCServerConfig, StoreConfig, TestModeConfig, WalletConfig, Web3IndexerConfig, + RPCServerConfig, StoreConfig, TestMode, WalletConfig, Web3IndexerConfig, }; use gw_jsonrpc_types::godwoken::L2BlockCommittedInfo; @@ -170,7 +170,6 @@ pub fn generate_config( }), None => None, }; - let test_mode = TestModeConfig { enable: false }; let config: Config = Config { backends, @@ -181,7 +180,7 @@ pub fn generate_config( rpc_server, block_producer, web3_indexer, - test_mode, + test_mode: TestMode::Disable, }; let output_content = toml::to_string_pretty(&config).expect("serde toml to string pretty");