Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hotfix(rpc server): submit withdrawal missing data for submit_tx #770

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 58 additions & 3 deletions crates/rpc-server/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ impl Registry {
}))
.with_data(Data::new(SubmitTransactionContext {
in_queue_request_map: self.in_queue_request_map.clone(),
submit_tx: self.submit_tx,
submit_tx: self.submit_tx.clone(),
mem_pool_state: self.mem_pool_state.clone(),
rate_limiter: send_transaction_rate_limiter,
rate_limit_config: self.send_tx_rate_limit,
Expand All @@ -313,6 +313,7 @@ impl Registry {
.with_data(Data::new(self.consensus_config))
.with_data(Data::new(self.node_mode))
.with_data(Data::new(self.in_queue_request_map))
.with_data(Data::new(self.submit_tx))
.with_method("gw_ping", ping)
.with_method("gw_get_tip_block_hash", get_tip_block_hash)
.with_method("gw_get_block_hash", get_block_hash)
Expand Down Expand Up @@ -384,7 +385,11 @@ impl Registry {
server = server
// .with_method("gw_dump_mem_block", dump_mem_block)
.with_method("gw_get_rocksdb_mem_stats", get_rocksdb_memory_stats)
.with_method("gw_dump_jemalloc_profiling", dump_jemalloc_profiling);
.with_method("gw_dump_jemalloc_profiling", dump_jemalloc_profiling)
.with_method(
"gw_submit_withdrawal_request_finalized_custodian_unchecked",
test_submit_withdrawal_request_finalized_custodian_unchecked,
);
}
}
}
Expand Down Expand Up @@ -1252,6 +1257,7 @@ async fn submit_l2transaction(
}

// TODO: refactor complex type.
// Either `RPCContext` or derive?
#[allow(clippy::type_complexity)]
#[instrument(skip_all)]
async fn submit_withdrawal_request(
Expand All @@ -1263,13 +1269,37 @@ async fn submit_withdrawal_request(
Data<mpsc::Sender<(InQueueRequestHandle, Request)>>,
),
rpc_client: Data<RPCClient>,
) -> Result<JsonH256, RpcError> {
inner_submit_withdrawal_request(
Params((withdrawal_request,)),
generator,
store,
in_queue_request_map,
submit_tx,
rpc_client,
true,
)
.await
}

// TODO: remove code after remove withdrawal cell
#[allow(clippy::type_complexity)]
#[instrument(skip_all)]
async fn inner_submit_withdrawal_request(
Params((withdrawal_request,)): Params<(JsonBytes,)>,
generator: Data<Generator>,
store: Data<Store>,
in_queue_request_map: Data<Option<Arc<InQueueRequestMap>>>,
submit_tx: Data<mpsc::Sender<(InQueueRequestHandle, Request)>>,
rpc_client: Data<RPCClient>,
check_finalized_custodian: bool,
) -> Result<JsonH256, RpcError> {
let withdrawal_bytes = withdrawal_request.into_bytes();
let withdrawal = packed::WithdrawalRequestExtra::from_slice(&withdrawal_bytes)?;
let withdrawal_hash = withdrawal.hash();

// verify finalized custodian
{
if check_finalized_custodian {
let t = Instant::now();
let finalized_custodians = {
let db = store.get_snapshot();
Expand Down Expand Up @@ -1911,6 +1941,31 @@ async fn get_mem_pool_state_ready(
Ok(mem_pool_state.completed_initial_syncing())
}

// TODO: remove code after remove withdrawal cell
#[allow(clippy::type_complexity)]
#[instrument(skip_all)]
async fn test_submit_withdrawal_request_finalized_custodian_unchecked(
Params((withdrawal_request,)): Params<(JsonBytes,)>,
generator: Data<Generator>,
store: Data<Store>,
(in_queue_request_map, submit_tx): (
Data<Option<Arc<InQueueRequestMap>>>,
Data<mpsc::Sender<(InQueueRequestHandle, Request)>>,
),
rpc_client: Data<RPCClient>,
) -> Result<JsonH256, RpcError> {
inner_submit_withdrawal_request(
Params((withdrawal_request,)),
generator,
store,
in_queue_request_map,
submit_tx,
rpc_client,
false,
)
.await
}

async fn tests_produce_block(
Params((payload,)): Params<(TestModePayload,)>,
tests_rpc_impl: Data<BoxedTestsRPCImpl>,
Expand Down
46 changes: 42 additions & 4 deletions crates/tests/src/testing_tool/rpc_server.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::{sync::Arc, time::Duration};
use std::{collections::HashSet, iter::FromIterator, sync::Arc, time::Duration};

use anyhow::{bail, Result};
use ckb_types::prelude::Entity;
use gw_block_producer::test_mode_control::TestModeControl;
use gw_chain::chain::Chain;
use gw_common::H256;
use gw_config::{NodeMode::FullNode, RPCClientConfig};
use gw_config::{NodeMode::FullNode, RPCClientConfig, RPCMethods};

use gw_jsonrpc_types::{
ckb_jsonrpc_types::{Byte32, JsonBytes, Uint64},
Expand All @@ -18,7 +18,7 @@ use gw_rpc_client::{
use gw_rpc_server::registry::{Registry, RegistryArgs};
use gw_types::{
bytes::Bytes,
packed::{L2Transaction, RawL2Transaction, Script},
packed::{L2Transaction, RawL2Transaction, Script, WithdrawalRequestExtra},
prelude::Pack,
};

Expand Down Expand Up @@ -74,7 +74,10 @@ impl RPCServer {
node_mode: FullNode,
rpc_client,
send_tx_rate_limit: Default::default(),
server_config: Default::default(),
server_config: gw_config::RPCServerConfig {
enable_methods: HashSet::from_iter(vec![RPCMethods::Test]),
..Default::default()
},
chain_config: Default::default(),
consensus_config: Default::default(),
dynamic_config_manager: Default::default(),
Expand Down Expand Up @@ -180,6 +183,41 @@ impl RPCServer {
Ok(result)
}

pub async fn submit_withdrawal_request(&self, req: &WithdrawalRequestExtra) -> Result<H256> {
let params = {
let bytes = JsonBytes::from_bytes(req.as_bytes());
serde_json::to_value(&(bytes,))?
};

let req = RequestBuilder::default()
.with_id(1)
.with_method("gw_submit_withdrawal_request")
.with_params(params)
.finish();

let hash: Byte32 = self.handle_single_request(req).await?;
Ok(hash.0.into())
}

pub async fn submit_withdrawal_request_finalized_custodian_unchecked(
&self,
req: &WithdrawalRequestExtra,
) -> Result<H256> {
let params = {
let bytes = JsonBytes::from_bytes(req.as_bytes());
serde_json::to_value(&(bytes,))?
};

let req = RequestBuilder::default()
.with_id(1)
.with_method("gw_submit_withdrawal_request_finalized_custodian_unchecked")
.with_params(params)
.finish();

let hash: Byte32 = self.handle_single_request(req).await?;
Ok(hash.0.into())
}

async fn handle_single_request<R: DeserializeOwned>(&self, req: RequestObject) -> Result<R> {
let ret = match self.inner.handle(req).await {
ResponseObjects::One(ResponseObject::Result { result, .. }) => {
Expand Down
1 change: 1 addition & 0 deletions crates/tests/src/tests/rpc_server/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod execute_l2transaction;
pub mod execute_raw_l2transaction;
pub mod submit_l2transaction;
pub mod submit_withdrawal_request;
114 changes: 114 additions & 0 deletions crates/tests/src/tests/rpc_server/submit_withdrawal_request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use gw_common::{
builtins::{CKB_SUDT_ACCOUNT_ID, ETH_REGISTRY_ACCOUNT_ID},
ckb_decimal::CKBCapacity,
state::State,
H256,
};
use gw_generator::account_lock_manage::eip712::{self, traits::EIP712Encode};
use gw_types::{
packed::{
DepositRequest, RawWithdrawalRequest, Script, WithdrawalRequest, WithdrawalRequestExtra,
},
prelude::{Builder, Entity, Pack},
};

use crate::testing_tool::{chain::TestChain, eth_wallet::EthWallet, rpc_server::RPCServer};

#[tokio::test(flavor = "multi_thread")]
async fn test_submit_withdrawal_request() {
let _ = env_logger::builder().is_test(true).try_init();

let rollup_type_script = Script::default();
let mut chain = TestChain::setup(rollup_type_script).await;
let rpc_server = RPCServer::build(&chain, None).await.unwrap();

// Deposit test account
const DEPOSIT_CAPACITY: u64 = 12345768 * 10u64.pow(8);
let test_wallet = EthWallet::random(chain.rollup_type_hash());
let deposit = DepositRequest::new_builder()
.capacity(DEPOSIT_CAPACITY.pack())
.sudt_script_hash(H256::zero().pack())
.amount(0.pack())
.script(test_wallet.account_script().to_owned())
.registry_id(ETH_REGISTRY_ACCOUNT_ID.pack())
.build();
chain.produce_block(vec![deposit], vec![]).await.unwrap();

let mem_pool_state = chain.mem_pool_state().await;
let snap = mem_pool_state.load();
let state = snap.state().unwrap();

let balance_before_withdrawal = state
.get_sudt_balance(CKB_SUDT_ACCOUNT_ID, test_wallet.reg_address())
.unwrap();

const WITHDRAWAL_CAPACITY: u64 = 1000u64 * 10u64.pow(8);
let withdrawal = {
let raw = RawWithdrawalRequest::new_builder()
.chain_id(chain.chain_id().pack())
.capacity(WITHDRAWAL_CAPACITY.pack())
.amount(0.pack())
.account_script_hash(test_wallet.account_script_hash().pack())
.owner_lock_hash(test_wallet.account_script_hash().pack())
.registry_id(gw_common::builtins::ETH_REGISTRY_ACCOUNT_ID.pack())
.build();
let typed_withdrawal = eip712::types::Withdrawal::from_raw(
raw.clone(),
test_wallet.account_script().to_owned(),
test_wallet.registry_address.clone(),
)
.unwrap();
let domain_seperator = eip712::types::EIP712Domain {
name: "Godwoken".to_string(),
version: "1".to_string(),
chain_id: chain.chain_id(),
verifying_contract: None,
salt: None,
};
let message = typed_withdrawal.eip712_message(domain_seperator.hash_struct());
let sig = test_wallet.sign_message(message).unwrap();
let req = WithdrawalRequest::new_builder()
.raw(raw)
.signature(sig.pack())
.build();
WithdrawalRequestExtra::new_builder()
.request(req)
.owner_lock(test_wallet.account_script().to_owned())
.build()
};

// Expect `gw_submit_withdrawal_request` call finalized custodian check logic code
let err = rpc_server
.submit_withdrawal_request(&withdrawal)
.await
.unwrap_err();
eprintln!("submit withdrawal request {}", err);

// Expect rpc error since we don't configure valid rpc url
assert!(err.to_string().contains("get_cells error"));

let withdrawal_hash = rpc_server
.submit_withdrawal_request_finalized_custodian_unchecked(&withdrawal)
.await
.unwrap();

let is_in_queue = rpc_server
.is_request_in_queue(withdrawal_hash)
.await
.unwrap();
assert!(is_in_queue);

chain.produce_block(vec![], vec![]).await.unwrap();

let snap = mem_pool_state.load();
let state = snap.state().unwrap();

let balance_after_withdrawal = state
.get_sudt_balance(CKB_SUDT_ACCOUNT_ID, test_wallet.reg_address())
.unwrap();

assert_eq!(
balance_before_withdrawal,
balance_after_withdrawal + CKBCapacity::from_layer1(WITHDRAWAL_CAPACITY).to_layer2()
);
}