diff --git a/crates/tests/src/script_tests/programs.rs b/crates/tests/src/script_tests/programs.rs index 6f25c5d15..5a5525475 100644 --- a/crates/tests/src/script_tests/programs.rs +++ b/crates/tests/src/script_tests/programs.rs @@ -7,6 +7,8 @@ use std::{fs, io::Read, path::PathBuf}; const SCRIPT_DIR: &str = "../../gwos/build/debug"; const CHALLENGE_LOCK_PATH: &str = "challenge-lock"; const WITHDRAWAL_LOCK_PATH: &str = "withdrawal-lock"; +const CUSTODIAN_LOCK_PATH: &str = "custodian-lock"; +const STAKE_LOCK_PATH: &str = "stake-lock"; const STATE_VALIDATOR: &str = "state-validator"; const SECP256K1_DATA_PATH: &str = "../../gwos/c/deps/ckb-production-scripts/build/secp256k1_data"; const ANYONE_CAN_PAY_LOCK_PATH: &str = @@ -51,6 +53,39 @@ lazy_static! { hasher.finalize(&mut buf); buf }; + pub static ref CUSTODIAN_LOCK_PROGRAM: Bytes = { + let mut buf = Vec::new(); + let mut path = PathBuf::new(); + path.push(&SCRIPT_DIR); + path.push(&CUSTODIAN_LOCK_PATH); + let mut f = fs::File::open(&path).expect("load custodian lock program"); + f.read_to_end(&mut buf) + .expect("read custodian lock program"); + Bytes::from(buf.to_vec()) + }; + pub static ref CUSTODIAN_LOCK_CODE_HASH: [u8; 32] = { + let mut buf = [0u8; 32]; + let mut hasher = new_blake2b(); + hasher.update(&CUSTODIAN_LOCK_PROGRAM); + hasher.finalize(&mut buf); + buf + }; + pub static ref STAKE_LOCK_PROGRAM: Bytes = { + let mut buf = Vec::new(); + let mut path = PathBuf::new(); + path.push(&SCRIPT_DIR); + path.push(&STAKE_LOCK_PATH); + let mut f = fs::File::open(&path).expect("load stake lock program"); + f.read_to_end(&mut buf).expect("read stake lock program"); + Bytes::from(buf.to_vec()) + }; + pub static ref STAKE_LOCK_CODE_HASH: [u8; 32] = { + let mut buf = [0u8; 32]; + let mut hasher = new_blake2b(); + hasher.update(&STAKE_LOCK_PROGRAM); + hasher.finalize(&mut buf); + buf + }; pub static ref ETH_ACCOUNT_LOCK_PROGRAM: Bytes = { let mut buf = Vec::new(); let mut path = PathBuf::new(); diff --git a/crates/tests/src/script_tests/state_validator/cancel_challenge/mod.rs b/crates/tests/src/script_tests/state_validator/cancel_challenge/mod.rs index a08de2c27..6a54666f1 100644 --- a/crates/tests/src/script_tests/state_validator/cancel_challenge/mod.rs +++ b/crates/tests/src/script_tests/state_validator/cancel_challenge/mod.rs @@ -8,8 +8,8 @@ use crate::script_tests::utils::init_env_log; use crate::script_tests::utils::layer1::build_simple_tx_with_out_point; use crate::script_tests::utils::layer1::random_out_point; use crate::script_tests::utils::rollup::{ - build_always_success_cell, build_rollup_locked_cell, build_type_id_script, - calculate_state_validator_type_id, CellContext, CellContextParam, + build_always_success_cell, build_rollup_locked_cell, calculate_type_id, + named_always_success_script, CellContext, CellContextParam, }; use crate::testing_tool::chain::into_deposit_info_cell; use crate::testing_tool::chain::setup_chain_with_account_lock_manage; @@ -66,7 +66,7 @@ pub(crate) fn build_merkle_proof(leaves: &[H256], indices: &[u32]) -> CKBMerkleP async fn test_burn_challenge_capacity() { init_env_log(); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -80,9 +80,9 @@ async fn test_burn_challenge_capacity() { .code_hash(CKBPack::pack(&[0u8; 32])) .build(); let reward_burn_lock_hash: [u8; 32] = reward_burn_lock.calc_script_hash().unpack().into(); - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); - let challenge_lock_type = build_type_id_script(b"challenge_lock_type_id"); - let eoa_lock_type = build_type_id_script(b"eoa_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); + let challenge_lock_type = named_always_success_script(b"challenge_lock_type_id"); + let eoa_lock_type = named_always_success_script(b"eoa_lock_type_id"); let challenge_script_type_hash: [u8; 32] = challenge_lock_type.calc_script_hash().unpack().into(); let eoa_lock_type_hash: [u8; 32] = eoa_lock_type.calc_script_hash().unpack().into(); diff --git a/crates/tests/src/script_tests/state_validator/cancel_challenge/tx_execution.rs b/crates/tests/src/script_tests/state_validator/cancel_challenge/tx_execution.rs index bd4a1d7ca..b85ef0536 100644 --- a/crates/tests/src/script_tests/state_validator/cancel_challenge/tx_execution.rs +++ b/crates/tests/src/script_tests/state_validator/cancel_challenge/tx_execution.rs @@ -7,8 +7,8 @@ use crate::script_tests::utils::init_env_log; use crate::script_tests::utils::layer1::build_simple_tx_with_out_point; use crate::script_tests::utils::layer1::random_out_point; use crate::script_tests::utils::rollup::{ - build_always_success_cell, build_rollup_locked_cell, build_type_id_script, - calculate_state_validator_type_id, CellContext, CellContextParam, + build_always_success_cell, build_rollup_locked_cell, calculate_type_id, + named_always_success_script, CellContext, CellContextParam, }; use crate::testing_tool::chain::setup_chain_with_config; use crate::testing_tool::chain::{apply_block_result, construct_block}; @@ -47,7 +47,7 @@ use gw_types::{ async fn test_cancel_tx_execute() { init_env_log(); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -56,10 +56,10 @@ async fn test_cancel_tx_execute() { .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); - let challenge_lock_type = build_type_id_script(b"challenge_lock_type_id"); - let eoa_lock_type = build_type_id_script(b"eoa_lock_type_id"); - let l2_sudt_type = build_type_id_script(b"l2_sudt_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); + let challenge_lock_type = named_always_success_script(b"challenge_lock_type_id"); + let eoa_lock_type = named_always_success_script(b"eoa_lock_type_id"); + let l2_sudt_type = named_always_success_script(b"l2_sudt_type_id"); let challenge_script_type_hash: [u8; 32] = challenge_lock_type.calc_script_hash().unpack().into(); let l2_sudt_type_hash: [u8; 32] = l2_sudt_type.calc_script_hash().unpack().into(); diff --git a/crates/tests/src/script_tests/state_validator/cancel_challenge/tx_signature.rs b/crates/tests/src/script_tests/state_validator/cancel_challenge/tx_signature.rs index 3010915d9..eea3dd2d4 100644 --- a/crates/tests/src/script_tests/state_validator/cancel_challenge/tx_signature.rs +++ b/crates/tests/src/script_tests/state_validator/cancel_challenge/tx_signature.rs @@ -8,8 +8,8 @@ use crate::script_tests::utils::init_env_log; use crate::script_tests::utils::layer1::build_simple_tx_with_out_point; use crate::script_tests::utils::layer1::random_out_point; use crate::script_tests::utils::rollup::{ - build_always_success_cell, build_rollup_locked_cell, build_type_id_script, - calculate_state_validator_type_id, CellContext, CellContextParam, + build_always_success_cell, build_rollup_locked_cell, calculate_type_id, + named_always_success_script, CellContext, CellContextParam, }; use crate::testing_tool::chain::into_deposit_info_cell; use crate::testing_tool::chain::setup_chain_with_account_lock_manage; @@ -55,7 +55,7 @@ use gw_types::{ async fn test_cancel_tx_signature() { init_env_log(); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -64,10 +64,10 @@ async fn test_cancel_tx_signature() { .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); - let challenge_lock_type = build_type_id_script(b"challenge_lock_type_id"); - let eoa_lock_type = build_type_id_script(b"eoa_lock_type_id"); - let l2_sudt_type = build_type_id_script(b"l2_sudt_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); + let challenge_lock_type = named_always_success_script(b"challenge_lock_type_id"); + let eoa_lock_type = named_always_success_script(b"eoa_lock_type_id"); + let l2_sudt_type = named_always_success_script(b"l2_sudt_type_id"); let challenge_script_type_hash: [u8; 32] = challenge_lock_type.calc_script_hash().unpack().into(); let eoa_lock_type_hash: [u8; 32] = eoa_lock_type.calc_script_hash().unpack().into(); diff --git a/crates/tests/src/script_tests/state_validator/cancel_challenge/withdrawal.rs b/crates/tests/src/script_tests/state_validator/cancel_challenge/withdrawal.rs index c2986a639..61e300585 100644 --- a/crates/tests/src/script_tests/state_validator/cancel_challenge/withdrawal.rs +++ b/crates/tests/src/script_tests/state_validator/cancel_challenge/withdrawal.rs @@ -9,8 +9,8 @@ use crate::script_tests::utils::init_env_log; use crate::script_tests::utils::layer1::build_simple_tx_with_out_point; use crate::script_tests::utils::layer1::random_out_point; use crate::script_tests::utils::rollup::{ - build_always_success_cell, build_rollup_locked_cell, build_type_id_script, - calculate_state_validator_type_id, CellContext, CellContextParam, + build_always_success_cell, build_rollup_locked_cell, calculate_type_id, + named_always_success_script, CellContext, CellContextParam, }; use crate::testing_tool::chain::into_deposit_info_cell; use crate::testing_tool::chain::{ @@ -52,7 +52,7 @@ use gw_types::{ async fn test_cancel_withdrawal() { init_env_log(); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -61,9 +61,9 @@ async fn test_cancel_withdrawal() { .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); - let challenge_lock_type = build_type_id_script(b"challenge_lock_type_id"); - let eoa_lock_type = build_type_id_script(b"eoa_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); + let challenge_lock_type = named_always_success_script(b"challenge_lock_type_id"); + let eoa_lock_type = named_always_success_script(b"eoa_lock_type_id"); let challenge_script_type_hash: [u8; 32] = challenge_lock_type.calc_script_hash().unpack().into(); let eoa_lock_type_hash: [u8; 32] = eoa_lock_type.calc_script_hash().unpack().into(); diff --git a/crates/tests/src/script_tests/state_validator/enter_challenge.rs b/crates/tests/src/script_tests/state_validator/enter_challenge.rs index 9261ab714..a7ec29c16 100644 --- a/crates/tests/src/script_tests/state_validator/enter_challenge.rs +++ b/crates/tests/src/script_tests/state_validator/enter_challenge.rs @@ -7,8 +7,8 @@ use crate::script_tests::utils::init_env_log; use crate::script_tests::utils::layer1::build_simple_tx_with_out_point; use crate::script_tests::utils::layer1::random_out_point; use crate::script_tests::utils::rollup::{ - build_always_success_cell, build_rollup_locked_cell, build_type_id_script, - calculate_state_validator_type_id, CellContext, CellContextParam, + build_always_success_cell, build_rollup_locked_cell, calculate_type_id, + named_always_success_script, CellContext, CellContextParam, }; use crate::testing_tool::chain::{apply_block_result, construct_block}; use crate::testing_tool::chain::{ @@ -45,7 +45,7 @@ const INVALID_CHALLENGE_TARGET_ERROR: i8 = 32; async fn test_enter_challenge() { init_env_log(); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -54,8 +54,8 @@ async fn test_enter_challenge() { .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); - let challenge_lock_type = build_type_id_script(b"challenge_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); + let challenge_lock_type = named_always_success_script(b"challenge_lock_type_id"); let challenge_script_type_hash: [u8; 32] = challenge_lock_type.calc_script_hash().unpack().into(); let finality_blocks = 10; @@ -279,7 +279,7 @@ async fn test_enter_challenge() { async fn test_enter_challenge_finalized_block() { init_env_log(); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -288,8 +288,8 @@ async fn test_enter_challenge_finalized_block() { .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); - let challenge_lock_type = build_type_id_script(b"challenge_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); + let challenge_lock_type = named_always_success_script(b"challenge_lock_type_id"); let challenge_script_type_hash: [u8; 32] = challenge_lock_type.calc_script_hash().unpack().into(); let finality_blocks = 1; diff --git a/crates/tests/src/script_tests/state_validator/revert.rs b/crates/tests/src/script_tests/state_validator/revert.rs index 1bc302da9..ada1072fa 100644 --- a/crates/tests/src/script_tests/state_validator/revert.rs +++ b/crates/tests/src/script_tests/state_validator/revert.rs @@ -7,8 +7,8 @@ use crate::script_tests::utils::init_env_log; use crate::script_tests::utils::layer1::build_simple_tx_with_out_point; use crate::script_tests::utils::layer1::{always_success_script, random_out_point}; use crate::script_tests::utils::rollup::{ - build_always_success_cell, build_rollup_locked_cell, build_type_id_script, - calculate_state_validator_type_id, CellContext, CellContextParam, + build_always_success_cell, build_rollup_locked_cell, calculate_type_id, + named_always_success_script, CellContext, CellContextParam, }; use crate::testing_tool::chain::{ apply_block_result, construct_block, into_deposit_info_cell, setup_chain_with_config, @@ -44,7 +44,7 @@ use gw_types::{packed::StakeLockArgs, prelude::*}; async fn test_revert() { init_env_log(); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -62,9 +62,9 @@ async fn test_revert() { .code_hash(CKBPack::pack(&[0u8; 32])) .build(); let reward_burn_lock_hash: [u8; 32] = reward_burn_lock.calc_script_hash().unpack().into(); - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); let stake_script_type_hash: [u8; 32] = stake_lock_type.calc_script_hash().unpack().into(); - let challenge_lock_type = build_type_id_script(b"challenge_lock_type_id"); + let challenge_lock_type = named_always_success_script(b"challenge_lock_type_id"); let challenge_script_type_hash: [u8; 32] = challenge_lock_type.calc_script_hash().unpack().into(); let finality_blocks = 10; diff --git a/crates/tests/src/script_tests/state_validator/submit_block.rs b/crates/tests/src/script_tests/state_validator/submit_block.rs index 0dba84f03..059ead26d 100644 --- a/crates/tests/src/script_tests/state_validator/submit_block.rs +++ b/crates/tests/src/script_tests/state_validator/submit_block.rs @@ -11,8 +11,8 @@ use crate::script_tests::utils::layer1::{ build_simple_tx_with_out_point_and_since, random_out_point, since_timestamp, }; use crate::script_tests::utils::rollup::{ - build_always_success_cell, build_rollup_locked_cell, build_type_id_script, - calculate_state_validator_type_id, CellContext, CellContextParam, + build_always_success_cell, build_rollup_locked_cell, calculate_type_id, + named_always_success_script, CellContext, CellContextParam, }; use ckb_error::assert_error_eq; use ckb_script::ScriptError; @@ -37,7 +37,7 @@ use gw_types::{ }, }; -const INVALID_BLOCK_ERROR: i8 = 20; +const INVALID_BLOCK: i8 = 20; const INVALID_POST_GLOBAL_STATE: i8 = 23; fn timestamp_now() -> u64 { @@ -53,7 +53,7 @@ async fn test_submit_block() { let capacity = 1000_00000000u64; let spend_cell = build_always_success_cell(capacity, None); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -62,7 +62,7 @@ async fn test_submit_block() { .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); let stake_script_type_hash: [u8; 32] = Unpack::::unpack(&stake_lock_type.calc_script_hash()).into(); let rollup_config = RollupConfig::new_builder() @@ -173,7 +173,7 @@ async fn test_downgrade_rollup_cell() { let capacity = 1000_00000000u64; let spend_cell = build_always_success_cell(capacity, None); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -182,7 +182,7 @@ async fn test_downgrade_rollup_cell() { .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); let stake_script_type_hash: [u8; 32] = stake_lock_type.calc_script_hash().unpack().into(); let rollup_config = RollupConfig::new_builder() .stake_script_type_hash(Pack::pack(&stake_script_type_hash)) @@ -307,7 +307,7 @@ async fn test_v1_block_timestamp_smaller_or_equal_than_previous_block_in_submit_ let capacity = 1000_00000000u64; let spend_cell = build_always_success_cell(capacity, None); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -316,7 +316,7 @@ async fn test_v1_block_timestamp_smaller_or_equal_than_previous_block_in_submit_ .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); let stake_script_type_hash: [u8; 32] = stake_lock_type.calc_script_hash().unpack().into(); let rollup_config = RollupConfig::new_builder() .stake_script_type_hash(Pack::pack(&stake_script_type_hash)) @@ -441,7 +441,7 @@ async fn test_v1_block_timestamp_smaller_or_equal_than_previous_block_in_submit_ "by-data-hash/{}", ckb_types::H256(*STATE_VALIDATOR_CODE_HASH) ), - INVALID_BLOCK_ERROR, + INVALID_POST_GLOBAL_STATE, ) .input_type_script(0); assert_error_eq!(err, expected_err); @@ -505,7 +505,7 @@ async fn test_v1_block_timestamp_smaller_or_equal_than_previous_block_in_submit_ "by-data-hash/{}", ckb_types::H256(*STATE_VALIDATOR_CODE_HASH) ), - INVALID_BLOCK_ERROR, + INVALID_POST_GLOBAL_STATE, ) .input_type_script(0); assert_error_eq!(err, expected_err); @@ -517,7 +517,7 @@ async fn test_v1_block_timestamp_bigger_than_rollup_input_since_in_submit_block( let capacity = 1000_00000000u64; let spend_cell = build_always_success_cell(capacity, None); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -526,7 +526,7 @@ async fn test_v1_block_timestamp_bigger_than_rollup_input_since_in_submit_block( .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); let stake_script_type_hash: [u8; 32] = stake_lock_type.calc_script_hash().unpack().into(); let rollup_config = RollupConfig::new_builder() .stake_script_type_hash(Pack::pack(&stake_script_type_hash)) @@ -646,7 +646,7 @@ async fn test_v1_block_timestamp_bigger_than_rollup_input_since_in_submit_block( "by-data-hash/{}", ckb_types::H256(*STATE_VALIDATOR_CODE_HASH) ), - INVALID_BLOCK_ERROR, + INVALID_POST_GLOBAL_STATE, ) .input_type_script(0); assert_error_eq!(err, expected_err); @@ -658,7 +658,7 @@ async fn test_v0_v1_wrong_global_state_tip_block_timestamp_in_submit_block() { let capacity = 1000_00000000u64; let spend_cell = build_always_success_cell(capacity, None); let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -667,7 +667,7 @@ async fn test_v0_v1_wrong_global_state_tip_block_timestamp_in_submit_block() { .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); let stake_script_type_hash: [u8; 32] = stake_lock_type.calc_script_hash().unpack().into(); let rollup_config = RollupConfig::new_builder() .stake_script_type_hash(Pack::pack(&stake_script_type_hash)) @@ -788,7 +788,7 @@ async fn test_v0_v1_wrong_global_state_tip_block_timestamp_in_submit_block() { "by-data-hash/{}", ckb_types::H256(*STATE_VALIDATOR_CODE_HASH) ), - INVALID_POST_GLOBAL_STATE, + INVALID_BLOCK, ) .input_type_script(0); assert_error_eq!(err, expected_err); @@ -826,7 +826,7 @@ async fn test_v0_v1_wrong_global_state_tip_block_timestamp_in_submit_block() { "by-data-hash/{}", ckb_types::H256(*STATE_VALIDATOR_CODE_HASH) ), - INVALID_BLOCK_ERROR, + INVALID_BLOCK, ) .input_type_script(0); assert_error_eq!(err, expected_err); @@ -861,7 +861,7 @@ async fn test_v0_v1_wrong_global_state_tip_block_timestamp_in_submit_block() { "by-data-hash/{}", ckb_types::H256(*STATE_VALIDATOR_CODE_HASH) ), - INVALID_BLOCK_ERROR, + INVALID_POST_GLOBAL_STATE, ) .input_type_script(0); assert_error_eq!(err, expected_err); @@ -871,7 +871,7 @@ async fn test_v0_v1_wrong_global_state_tip_block_timestamp_in_submit_block() { async fn test_check_reverted_cells_in_submit_block() { let capacity = 1000_00000000u64; let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -880,14 +880,14 @@ async fn test_check_reverted_cells_in_submit_block() { .build() }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); let stake_script_type_hash: [u8; 32] = stake_lock_type.calc_script_hash().unpack().into(); - let deposit_lock_type = build_type_id_script(b"deposit_lock_type_id"); + let deposit_lock_type = named_always_success_script(b"deposit_lock_type_id"); let deposit_script_type_hash: [u8; 32] = deposit_lock_type.calc_script_hash().unpack().into(); - let custodian_lock_type = build_type_id_script(b"custodian_lock_type_id"); + let custodian_lock_type = named_always_success_script(b"custodian_lock_type_id"); let custodian_script_type_hash: [u8; 32] = custodian_lock_type.calc_script_hash().unpack().into(); - let withdrawal_lock_type = build_type_id_script(b"withdrawal_lock_type_id"); + let withdrawal_lock_type = named_always_success_script(b"withdrawal_lock_type_id"); let withdrawal_script_type_hash: [u8; 32] = withdrawal_lock_type.calc_script_hash().unpack().into(); let rollup_config = RollupConfig::new_builder() @@ -1129,7 +1129,7 @@ async fn test_withdrawal_cell_lock_args_with_owner_lock_in_submit_block() { let capacity = 1000_00000000u64; let input_out_point = random_out_point(); - let type_id = calculate_state_validator_type_id(input_out_point.clone()); + let type_id = calculate_type_id(input_out_point.clone()); let rollup_type_script = { Script::new_builder() .code_hash(Pack::pack(&*STATE_VALIDATOR_CODE_HASH)) @@ -1139,12 +1139,12 @@ async fn test_withdrawal_cell_lock_args_with_owner_lock_in_submit_block() { }; // rollup lock & config - let stake_lock_type = build_type_id_script(b"stake_lock_type_id"); + let stake_lock_type = named_always_success_script(b"stake_lock_type_id"); let stake_script_type_hash: [u8; 32] = stake_lock_type.calc_script_hash().unpack().into(); - let custodian_lock_type = build_type_id_script(b"custodian_lock_type_id"); + let custodian_lock_type = named_always_success_script(b"custodian_lock_type_id"); let custodian_script_type_hash: [u8; 32] = custodian_lock_type.calc_script_hash().unpack().into(); - let withdrawal_lock_type = build_type_id_script(b"withdrawal_lock_type_id"); + let withdrawal_lock_type = named_always_success_script(b"withdrawal_lock_type_id"); let withdrawal_script_type_hash: [u8; 32] = withdrawal_lock_type.calc_script_hash().unpack().into(); let rollup_config = RollupConfig::new_builder() diff --git a/crates/tests/src/script_tests/utils/rollup.rs b/crates/tests/src/script_tests/utils/rollup.rs index a09b194d0..4eafb24aa 100644 --- a/crates/tests/src/script_tests/utils/rollup.rs +++ b/crates/tests/src/script_tests/utils/rollup.rs @@ -6,6 +6,7 @@ use crate::script_tests::utils::layer1::{ }; use crate::testing_tool::chain::{ALWAYS_SUCCESS_CODE_HASH, ALWAYS_SUCCESS_PROGRAM}; use ckb_script::TransactionScriptsVerifier; +use ckb_traits::CellDataProvider; use ckb_types::{ packed::{CellDep, CellOutput}, prelude::Pack as CKBPack, @@ -28,15 +29,15 @@ pub struct CellContextParam { impl Default for CellContextParam { fn default() -> Self { Self { - stake_lock_type: random_type_id_script(), - challenge_lock_type: random_type_id_script(), - deposit_lock_type: random_type_id_script(), - custodian_lock_type: random_type_id_script(), - withdrawal_lock_type: random_type_id_script(), - l2_sudt_type: random_type_id_script(), - always_success_type: random_type_id_script(), - eoa_lock_type: random_type_id_script(), - eth_lock_type: random_type_id_script(), + stake_lock_type: random_always_success_script(), + challenge_lock_type: random_always_success_script(), + deposit_lock_type: random_always_success_script(), + custodian_lock_type: random_always_success_script(), + withdrawal_lock_type: random_always_success_script(), + l2_sudt_type: random_always_success_script(), + always_success_type: random_always_success_script(), + eoa_lock_type: random_always_success_script(), + eth_lock_type: random_always_success_script(), } } } @@ -271,18 +272,24 @@ impl CellContext { verifier.set_debug_printer(|_script, msg| println!("[script debug] {}", msg)); verifier.verify(MAX_CYCLES) } + + pub fn rollup_config(&self) -> RollupConfig { + let rollup_config_out_point = self.rollup_config_dep.out_point(); + let rollup_config_data = self.inner.get_cell_data(&rollup_config_out_point).unwrap(); + RollupConfig::new_unchecked(rollup_config_data) + } } -pub fn build_type_id_script(name: &[u8]) -> ckb_types::packed::Script { +pub fn named_always_success_script(name: &[u8]) -> ckb_types::packed::Script { ckb_types::packed::Script::new_builder() .code_hash(CKBPack::pack(&ALWAYS_SUCCESS_CODE_HASH.clone())) .args(CKBPack::pack(&Bytes::from(name.to_vec()))) .build() } -fn random_type_id_script() -> ckb_types::packed::Script { +pub fn random_always_success_script() -> ckb_types::packed::Script { let random_bytes: [u8; 32] = rand::random(); - build_type_id_script(&random_bytes) + named_always_success_script(&random_bytes) } pub fn build_rollup_locked_cell( @@ -318,7 +325,8 @@ pub fn build_always_success_cell( .build() } -pub fn calculate_state_validator_type_id(input_out_point: ckb_types::packed::OutPoint) -> [u8; 32] { +/// Calculate type_id according to the CKB built-in TYPE_ID rule +pub fn calculate_type_id(input_out_point: ckb_types::packed::OutPoint) -> [u8; 32] { let input = ckb_types::packed::CellInput::new_builder() .previous_output(input_out_point) .build(); diff --git a/crates/tests/src/script_tests/withdrawal.rs b/crates/tests/src/script_tests/withdrawal.rs index 321322afa..ad38ac53c 100644 --- a/crates/tests/src/script_tests/withdrawal.rs +++ b/crates/tests/src/script_tests/withdrawal.rs @@ -13,13 +13,13 @@ use ckb_types::core::TransactionView; use ckb_types::prelude::{Builder, Entity}; use gw_common::blake2b::new_blake2b; use gw_types::bytes::Bytes; -use gw_types::core::ScriptHashType; +use gw_types::core::{ScriptHashType, Timepoint}; use gw_types::packed::{ - CellDep, CellInput, CellOutput, GlobalState, OutPoint, RollupConfig, Script, - UnlockWithdrawalViaFinalize, UnlockWithdrawalWitness, UnlockWithdrawalWitnessUnion, + BlockMerkleState, Byte32, CellDep, CellInput, CellOutput, GlobalState, OutPoint, RollupConfig, + Script, UnlockWithdrawalViaFinalize, UnlockWithdrawalWitness, UnlockWithdrawalWitnessUnion, WithdrawalLockArgs, WitnessArgs, }; -use gw_types::prelude::Pack; +use gw_types::prelude::{Pack, Unpack}; use secp256k1::rand::rngs::OsRng; use secp256k1::{Message, Secp256k1, SecretKey}; @@ -35,10 +35,17 @@ fn test_unlock_withdrawal_via_finalize_by_input_owner_cell() { let rollup_type_hash = rollup_type_script.hash(); let (mut verify_ctx, script_ctx) = build_verify_context(); - let last_finalized_block_number = rand::random::() + 100; + let withdrawal_timepoint = Timepoint::from_block_number(rand::random::() as u64 + 100); + let (block_merkle_state, last_finalized_timepoint) = + mock_global_state_timepoint_by_finalized_timepoint( + &verify_ctx.rollup_config(), + &withdrawal_timepoint, + ); let rollup_cell = { let global_state = GlobalState::new_builder() - .last_finalized_block_number(last_finalized_block_number.pack()) + .rollup_config_hash(verify_ctx.rollup_config().hash().pack()) + .last_finalized_block_number(last_finalized_timepoint.full_value().pack()) + .block(block_merkle_state) .build(); let output = CellOutput::new_builder() @@ -84,7 +91,7 @@ fn test_unlock_withdrawal_via_finalize_by_input_owner_cell() { let lock_args = WithdrawalLockArgs::new_builder() .account_script_hash(random_always_success_script().hash().pack()) .withdrawal_block_hash(random_always_success_script().hash().pack()) - .withdrawal_block_number(last_finalized_block_number.saturating_sub(1).pack()) + .withdrawal_block_number(withdrawal_timepoint.full_value().pack()) .owner_lock_hash(owner_lock.hash().pack()) .build(); let mut args = Vec::new(); @@ -153,6 +160,7 @@ fn test_unlock_withdrawal_via_finalize_by_input_owner_cell() { .cell_dep(script_ctx.acp.dep.to_ckb()) .cell_dep(script_ctx.secp256k1_data.dep.to_ckb()) .cell_dep(rollup_dep.to_ckb()) + .cell_dep(verify_ctx.rollup_config_dep.clone()) .build(); let err_sign_tx = sign_tx(tx.clone(), 1, &err_sk); @@ -174,10 +182,17 @@ fn test_unlock_withdrawal_via_finalize_by_switch_indexed_output_to_owner_lock() let rollup_type_hash = rollup_type_script.hash(); let (mut verify_ctx, script_ctx) = build_verify_context(); - let last_finalized_block_number = rand::random::() + 100; + let withdrawal_timepoint = Timepoint::from_block_number(rand::random::() as u64 + 100); + let (block_merkle_state, last_finalized_timepoint) = + mock_global_state_timepoint_by_finalized_timepoint( + &verify_ctx.rollup_config(), + &withdrawal_timepoint, + ); let rollup_cell = { let global_state = GlobalState::new_builder() - .last_finalized_block_number(last_finalized_block_number.pack()) + .rollup_config_hash(verify_ctx.rollup_config().hash().pack()) + .last_finalized_block_number(last_finalized_timepoint.full_value().pack()) + .block(block_merkle_state) .build(); let output = CellOutput::new_builder() @@ -198,7 +213,7 @@ fn test_unlock_withdrawal_via_finalize_by_switch_indexed_output_to_owner_lock() let lock_args = WithdrawalLockArgs::new_builder() .account_script_hash(random_always_success_script().hash().pack()) .withdrawal_block_hash(random_always_success_script().hash().pack()) - .withdrawal_block_number(last_finalized_block_number.saturating_sub(1).pack()) + .withdrawal_block_number(withdrawal_timepoint.full_value().pack()) .owner_lock_hash(owner_lock.hash().pack()) .build(); @@ -261,6 +276,7 @@ fn test_unlock_withdrawal_via_finalize_by_switch_indexed_output_to_owner_lock() .witness(unlock_via_finalize_witness.as_bytes().to_ckb()) .cell_dep(script_ctx.withdrawal.dep.to_ckb()) .cell_dep(rollup_dep.to_ckb()) + .cell_dep(verify_ctx.rollup_config_dep.clone()) .build(); verify_ctx.verify_tx(tx.clone()).expect("success"); @@ -343,10 +359,17 @@ fn test_unlock_withdrawal_via_finalize_fallback_to_input_owner_cell() { let rollup_type_hash = rollup_type_script.hash(); let (mut verify_ctx, script_ctx) = build_verify_context(); - let last_finalized_block_number = rand::random::() + 100; + let withdrawal_timepoint = Timepoint::from_block_number(rand::random::() as u64 + 100); + let (block_merkle_state, last_finalized_timepoint) = + mock_global_state_timepoint_by_finalized_timepoint( + &verify_ctx.rollup_config(), + &withdrawal_timepoint, + ); let rollup_cell = { let global_state = GlobalState::new_builder() - .last_finalized_block_number(last_finalized_block_number.pack()) + .rollup_config_hash(verify_ctx.rollup_config().hash().pack()) + .last_finalized_block_number(last_finalized_timepoint.full_value().pack()) + .block(block_merkle_state) .build(); let output = CellOutput::new_builder() @@ -387,7 +410,7 @@ fn test_unlock_withdrawal_via_finalize_fallback_to_input_owner_cell() { let lock_args = WithdrawalLockArgs::new_builder() .account_script_hash(random_always_success_script().hash().pack()) .withdrawal_block_hash(random_always_success_script().hash().pack()) - .withdrawal_block_number(last_finalized_block_number.saturating_sub(1).pack()) + .withdrawal_block_number(withdrawal_timepoint.full_value().pack()) .owner_lock_hash(owner_lock.hash().pack()) .build(); @@ -455,6 +478,7 @@ fn test_unlock_withdrawal_via_finalize_fallback_to_input_owner_cell() { .witness(unlock_via_finalize_witness.as_bytes().to_ckb()) .cell_dep(script_ctx.withdrawal.dep.to_ckb()) .cell_dep(rollup_dep.to_ckb()) + .cell_dep(verify_ctx.rollup_config_dep.clone()) .build(); let err = verify_ctx.verify_tx(tx.clone()).unwrap_err(); @@ -476,6 +500,7 @@ fn test_unlock_withdrawal_via_finalize_fallback_to_input_owner_cell() { .cell_dep(script_ctx.acp.dep.to_ckb()) .cell_dep(script_ctx.secp256k1_data.dep.to_ckb()) .cell_dep(rollup_dep.to_ckb()) + .cell_dep(verify_ctx.rollup_config_dep.clone()) .build(); let sign_tx = sign_tx(tx, 1, &sk); @@ -616,8 +641,31 @@ fn sign_tx(tx: TransactionView, witness_idx: usize, sk: &SecretKey) -> Transacti .build() } +// To make the `target_finalized_timepoint` to be finalized for GlobalState, +// returns the mocked `GlobalState.block` and +// `GlobalState.last_finalized_timepoint` fields +fn mock_global_state_timepoint_by_finalized_timepoint( + rollup_config: &RollupConfig, + target_finalized_timepoint: &Timepoint, +) -> (BlockMerkleState, Timepoint) { + match target_finalized_timepoint { + Timepoint::BlockNumber(block_number) => { + let finality_as_blocks: u64 = rollup_config.finality_blocks().unpack(); + let tip_number = block_number + finality_as_blocks; + let block_count = tip_number + 1; + let block_merkle_state = BlockMerkleState::new_builder() + .count(block_count.pack()) + .build(); + (block_merkle_state, target_finalized_timepoint.clone()) + } + Timepoint::Timestamp(_) => (Default::default(), target_finalized_timepoint.clone()), + } +} + mod conversion { - use ckb_types::packed::{Bytes, CellDep, CellInput, CellOutput, OutPoint, Script, WitnessArgs}; + use ckb_types::packed::{ + Byte32, Bytes, CellDep, CellInput, CellOutput, OutPoint, Script, WitnessArgs, + }; use ckb_types::prelude::{Entity, Pack}; pub trait ToCKBType { @@ -638,6 +686,7 @@ mod conversion { impl_to_ckb!(CellOutput); impl_to_ckb!(WitnessArgs); impl_to_ckb!(CellDep); + impl_to_ckb!(Byte32); impl ToCKBType for super::Bytes { fn to_ckb(&self) -> Bytes { @@ -662,6 +711,7 @@ mod conversion { impl_to_gw!(OutPoint); impl_to_gw!(CellOutput); impl_to_gw!(Script); + impl_to_gw!(Byte32); } use conversion::{ToCKBType, ToGWType}; diff --git a/gwos/contracts/Cargo.lock b/gwos/contracts/Cargo.lock index f8ab7a0ae..25a26c608 100644 --- a/gwos/contracts/Cargo.lock +++ b/gwos/contracts/Cargo.lock @@ -6,14 +6,14 @@ version = 3 name = "always-success" version = "0.1.0" dependencies = [ - "ckb-std", + "ckb-std 0.7.4", ] [[package]] name = "blake2b-ref" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95916998c798756098a4eb1b3f2cd510659705a9817bf203d61abd30fbec3e7b" +checksum = "294d17c72e0ba59fad763caa112368d0672083779cdebbb97164f4bb4c1e339a" [[package]] name = "blake2b-rs" @@ -104,6 +104,16 @@ dependencies = [ "cty", ] +[[package]] +name = "ckb-standalone-types" +version = "0.0.1-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af2cdbdf65ee5b1da71504f5a03d6984bce77d0b4b46daff63f4ba4a3b0eef08" +dependencies = [ + "cfg-if 0.1.10", + "molecule 0.6.1", +] + [[package]] name = "ckb-standalone-types" version = "0.1.2" @@ -111,7 +121,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22d7cbbdab96e6b809a102cf88bfec28795a0a3c06bfdea4abe4de89777801cd" dependencies = [ "cfg-if 1.0.0", - "molecule", + "molecule 0.7.2", +] + +[[package]] +name = "ckb-std" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5247e68ff32c17714105e2460db6113fb99efde8c830bbdd99f8bf715100dd64" +dependencies = [ + "buddy-alloc", + "cc", + "ckb-standalone-types 0.0.1-pre.1", ] [[package]] @@ -122,7 +143,7 @@ checksum = "e5761f11372e794d77b8e8a8059b22c5d6ccef907588dd5302a669f056ecce6b" dependencies = [ "buddy-alloc", "cc", - "ckb-standalone-types", + "ckb-standalone-types 0.1.2", "cstr_core", ] @@ -258,8 +279,8 @@ dependencies = [ [[package]] name = "gw-common" -version = "0.1.0" -source = "git+https://github.com/nervosnetwork/godwoken.git?rev=91c324544424292b4d715ce376d31bc45aa3cb5d#91c324544424292b4d715ce376d31bc45aa3cb5d" +version = "1.7.0-rc2" +source = "git+https://github.com/keroro520/godwoken.git?branch=new-finality-rule-based-on-timestamp#20348314cfef0b0d61431bd953c1a1ec1928cd88" dependencies = [ "cfg-if 0.1.10", "gw-hash", @@ -270,8 +291,8 @@ dependencies = [ [[package]] name = "gw-hash" -version = "0.1.0" -source = "git+https://github.com/nervosnetwork/godwoken.git?rev=91c324544424292b4d715ce376d31bc45aa3cb5d#91c324544424292b4d715ce376d31bc45aa3cb5d" +version = "1.7.0-rc2" +source = "git+https://github.com/keroro520/godwoken.git?branch=new-finality-rule-based-on-timestamp#20348314cfef0b0d61431bd953c1a1ec1928cd88" dependencies = [ "blake2b-ref", ] @@ -286,12 +307,12 @@ dependencies = [ [[package]] name = "gw-types" -version = "0.1.0" -source = "git+https://github.com/nervosnetwork/godwoken.git?rev=91c324544424292b4d715ce376d31bc45aa3cb5d#91c324544424292b4d715ce376d31bc45aa3cb5d" +version = "1.7.0-rc2" +source = "git+https://github.com/keroro520/godwoken.git?branch=new-finality-rule-based-on-timestamp#20348314cfef0b0d61431bd953c1a1ec1928cd88" dependencies = [ "cfg-if 0.1.10", "gw-hash", - "molecule", + "molecule 0.7.2", "primitive-types", "sparse-merkle-tree", ] @@ -300,7 +321,7 @@ dependencies = [ name = "gw-utils" version = "0.1.0" dependencies = [ - "ckb-std", + "ckb-std 0.9.0", "gw-common", "gw-types", ] @@ -350,6 +371,15 @@ dependencies = [ "cfg-if 0.1.10", ] +[[package]] +name = "molecule" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3067ceba3d7f5dcc7427cfc584fc506e756f1161151032fec840455f5a3c2fd5" +dependencies = [ + "cfg-if 0.1.10", +] + [[package]] name = "molecule" version = "0.7.2" diff --git a/gwos/contracts/always-success/Cargo.toml b/gwos/contracts/always-success/Cargo.toml index f3dc9bc70..e0538bfe9 100644 --- a/gwos/contracts/always-success/Cargo.toml +++ b/gwos/contracts/always-success/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ckb-std = "0.9.0" +ckb-std = "0.7.1" diff --git a/gwos/contracts/always-success/src/main.rs b/gwos/contracts/always-success/src/main.rs index f251162c4..e43f2c581 100644 --- a/gwos/contracts/always-success/src/main.rs +++ b/gwos/contracts/always-success/src/main.rs @@ -6,7 +6,6 @@ #![feature(lang_items)] #![feature(alloc_error_handler)] #![feature(panic_info_message)] -#![feature(asm)] // define modules mod entry; diff --git a/gwos/contracts/custodian-lock/src/entry.rs b/gwos/contracts/custodian-lock/src/entry.rs index 58f2117f3..251881189 100644 --- a/gwos/contracts/custodian-lock/src/entry.rs +++ b/gwos/contracts/custodian-lock/src/entry.rs @@ -20,13 +20,14 @@ use crate::ckb_std::{ high_level::load_script, high_level::load_witness_args, }; use gw_types::{ - core::ScriptHashType, + core::{ScriptHashType, Timepoint}, packed::{ CustodianLockArgs, CustodianLockArgsReader, UnlockCustodianViaRevertWitness, UnlockCustodianViaRevertWitnessReader, }, prelude::*, }; +use gw_utils::finality::is_finalized; use gw_utils::gw_types; use crate::error::Error; @@ -58,11 +59,14 @@ pub fn main() -> Result<(), Error> { Some(state) => state, None => return Err(Error::RollupCellNotFound), }; + let config = load_rollup_config(&global_state.rollup_config_hash().unpack())?; - let deposit_block_number: u64 = lock_args.deposit_block_number().unpack(); - let last_finalized_block_number: u64 = global_state.last_finalized_block_number().unpack(); - - if deposit_block_number <= last_finalized_block_number { + let is_finalized = is_finalized( + &config, + &global_state, + &Timepoint::from_full_value(lock_args.deposit_block_number().unpack()), + ); + if is_finalized { // this custodian lock is already finalized, rollup will handle the logic return Ok(()); } diff --git a/gwos/contracts/gw-utils/Cargo.toml b/gwos/contracts/gw-utils/Cargo.toml index 4263023d3..27afb0e44 100644 --- a/gwos/contracts/gw-utils/Cargo.toml +++ b/gwos/contracts/gw-utils/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" [dependencies] ckb-std = "0.9.0" -gw-types = { git = "https://github.com/nervosnetwork/godwoken.git", rev = "91c324544424292b4d715ce376d31bc45aa3cb5d", default-features = false } -gw-common = { git = "https://github.com/nervosnetwork/godwoken.git", rev = "91c324544424292b4d715ce376d31bc45aa3cb5d", default-features = false } +gw-types = { git = "https://github.com/keroro520/godwoken.git", branch = "new-finality-rule-based-on-timestamp", default-features = false } +gw-common = { git = "https://github.com/keroro520/godwoken.git", branch = "new-finality-rule-based-on-timestamp", default-features = false } diff --git a/gwos/contracts/gw-utils/src/error.rs b/gwos/contracts/gw-utils/src/error.rs index 9abc95516..507d35748 100644 --- a/gwos/contracts/gw-utils/src/error.rs +++ b/gwos/contracts/gw-utils/src/error.rs @@ -52,6 +52,8 @@ pub enum Error { DuplicatedScriptHash = 42, RegistryAddressNotFound = 43, DuplicatedRegistryAddress = 44, + NotFinalized = 45, + HeaderDepsNotFound = 46, } impl From for Error { diff --git a/gwos/contracts/gw-utils/src/finality.rs b/gwos/contracts/gw-utils/src/finality.rs new file mode 100644 index 000000000..85ab2eb16 --- /dev/null +++ b/gwos/contracts/gw-utils/src/finality.rs @@ -0,0 +1,68 @@ +//! # How to check finality +//! +//! To determine a block-number-based timepoint is finalized, compare it with +//! `prev_global_state.block.count - 1 + FINALITY_REQUIREMENT`. +//! +//! To determine a timestamp-based timepoint is finalized, +//! - If prev_global_state.last_finalized_block_number is also timestamp-based, +//! compare them directly; +//! - Otherwise, we know it is switching versions, so the corresponding entity +//! is surely not finalized. + +use ckb_std::debug; +use gw_types::core::Timepoint; +use gw_types::packed::{GlobalState, RollupConfig}; +use gw_types::prelude::Unpack; + +// 7 * 24 * 60 * 60 / 16800 * 1000 = 36000 +const BLOCK_INTERVAL_IN_MILLISECONDS: u64 = 36000; + +pub fn is_finalized( + rollup_config: &RollupConfig, + prev_global_state: &GlobalState, + timepoint: &Timepoint, +) -> bool { + match timepoint { + Timepoint::BlockNumber(block_number) => { + is_block_number_finalized(rollup_config, prev_global_state, *block_number) + } + Timepoint::Timestamp(timestamp) => is_timestamp_finalized(prev_global_state, *timestamp), + } +} + +pub fn is_timestamp_finalized(prev_global_state: &GlobalState, timestamp: u64) -> bool { + match Timepoint::from_full_value(prev_global_state.last_finalized_block_number().unpack()) { + Timepoint::BlockNumber(_) => { + debug!("[is_timestamp_finalized] switching version, prev_global_state.last_finalized_block_number is number-based"); + false + } + Timepoint::Timestamp(finalized) => { + let ret = timestamp <= finalized; + debug!( + "[is_timestamp_finalized] is_finalized: {}, prev_global_state last_finalized_timestamp: {}, timestamp: {}", + ret, finalized, timestamp + ); + ret + } + } +} + +pub fn is_block_number_finalized( + rollup_config: &RollupConfig, + prev_global_state: &GlobalState, + block_number: u64, +) -> bool { + let finality_blocks: u64 = rollup_config.finality_blocks().unpack(); + let tip_number: u64 = prev_global_state.block().count().unpack().saturating_sub(1); + let ret = block_number.saturating_add(finality_blocks) <= tip_number; + debug!( + "[is_block_number_finalized] is_finalized: {}, prev_global_state tip number: {}, block_number: {}", + ret, tip_number, block_number + ); + ret +} + +pub fn finality_as_duration(rollup_config: &RollupConfig) -> u64 { + let finality_blocks = rollup_config.finality_blocks().unpack(); + finality_blocks.saturating_mul(BLOCK_INTERVAL_IN_MILLISECONDS) +} diff --git a/gwos/contracts/gw-utils/src/lib.rs b/gwos/contracts/gw-utils/src/lib.rs index f719b0661..eb0b7b551 100644 --- a/gwos/contracts/gw-utils/src/lib.rs +++ b/gwos/contracts/gw-utils/src/lib.rs @@ -11,6 +11,7 @@ pub use gw_types; pub mod cells; pub mod error; +pub mod finality; pub mod signature; pub mod type_id; pub mod withdrawal; diff --git a/gwos/contracts/stake-lock/src/entry.rs b/gwos/contracts/stake-lock/src/entry.rs index 1c0191ca9..d72098afa 100644 --- a/gwos/contracts/stake-lock/src/entry.rs +++ b/gwos/contracts/stake-lock/src/entry.rs @@ -16,12 +16,14 @@ use crate::ckb_std::{ }; use gw_utils::cells::{ - rollup::{search_rollup_cell, search_rollup_state}, + rollup::{load_rollup_config, search_rollup_cell, search_rollup_state}, utils::search_lock_hash, }; +use gw_utils::finality::is_finalized; use gw_utils::gw_types; use gw_types::{ + core::Timepoint, packed::{StakeLockArgs, StakeLockArgsReader}, prelude::*, }; @@ -52,12 +54,15 @@ pub fn main() -> Result<(), Error> { // Unlock by User // read global state from rollup cell in deps if let Some(global_state) = search_rollup_state(&rollup_type_hash, Source::CellDep)? { - let stake_block_number: u64 = lock_args.stake_block_number().unpack(); - let last_finalized_block_number: u64 = global_state.last_finalized_block_number().unpack(); - // 1. check if stake_block_number is finalized // 2. check if owner_lock_hash exists in input cells - if stake_block_number <= last_finalized_block_number + let config = load_rollup_config(&global_state.rollup_config_hash().unpack())?; + let is_finalized = is_finalized( + &config, + &global_state, + &Timepoint::from_full_value(lock_args.stake_block_number().unpack()), + ); + if is_finalized && search_lock_hash(&lock_args.owner_lock_hash().unpack(), Source::Input).is_some() { return Ok(()); diff --git a/gwos/contracts/state-validator/src/types.rs b/gwos/contracts/state-validator/src/types.rs index a7a131032..8dcf526b3 100644 --- a/gwos/contracts/state-validator/src/types.rs +++ b/gwos/contracts/state-validator/src/types.rs @@ -29,9 +29,9 @@ pub struct WithdrawalRequest { } pub struct BlockContext { pub number: u64, - pub finalized_number: u64, pub timestamp: u64, pub block_hash: H256, pub rollup_type_hash: H256, pub prev_account_root: H256, + pub post_version: u8, } diff --git a/gwos/contracts/state-validator/src/verifications/challenge.rs b/gwos/contracts/state-validator/src/verifications/challenge.rs index 8fb3b1929..fbe12b9c0 100644 --- a/gwos/contracts/state-validator/src/verifications/challenge.rs +++ b/gwos/contracts/state-validator/src/verifications/challenge.rs @@ -6,6 +6,7 @@ use gw_types::{ packed::{GlobalState, RollupConfig}, prelude::*, }; +use gw_utils::finality::{is_block_number_finalized, is_timestamp_finalized}; use gw_utils::{ cells::lock_cells::{collect_burn_cells, find_challenge_cell}, ckb_std::{ckb_constants::Source, debug}, @@ -38,13 +39,23 @@ pub fn verify_enter_challenge( // check that challenge target is exists let witness = args.witness(); let challenged_block = witness.raw_l2block(); + // check challenged block isn't finazlied - if prev_global_state.last_finalized_block_number().unpack() - >= challenged_block.number().unpack() - { - debug!("enter challenge finalized block error"); + let post_version: u8 = post_global_state.version().into(); + let is_block_finalized = if post_version < 2 { + is_block_number_finalized( + config, + post_global_state, + challenged_block.number().unpack(), + ) + } else { + is_timestamp_finalized(post_global_state, challenged_block.timestamp().unpack()) + }; + if is_block_finalized { + debug!("cannot challenge a finalized block"); return Err(Error::InvalidChallengeTarget); } + let valid = { let merkle_proof = CompiledMerkleProof(witness.block_proof().unpack()); let leaves = vec![( diff --git a/gwos/contracts/state-validator/src/verifications/revert.rs b/gwos/contracts/state-validator/src/verifications/revert.rs index 6ba0ee8b7..8c8ac3e94 100644 --- a/gwos/contracts/state-validator/src/verifications/revert.rs +++ b/gwos/contracts/state-validator/src/verifications/revert.rs @@ -4,10 +4,11 @@ use gw_common::{ H256, }; use gw_types::{ - core::Status, + core::{Status, Timepoint}, packed::{BlockMerkleState, Byte32, GlobalState, RawL2Block, RollupConfig}, prelude::*, }; +use gw_utils::finality::finality_as_duration; use gw_utils::gw_types; use gw_utils::{ cells::{ @@ -247,12 +248,27 @@ fn check_reverted_blocks( }; let account_merkle_state = reverted_blocks[0].prev_account(); let tip_block_hash = reverted_blocks[0].parent_block_hash(); - let last_finalized_block_number = { - let number: u64 = reverted_blocks[0].number().unpack(); - number + let post_version: u8 = post_global_state.version().into(); + let last_finalized = if post_version < 2 { + let tip_number: u64 = reverted_blocks[0].number().unpack(); + let finalized_number = tip_number .saturating_sub(1) - .saturating_sub(config.finality_blocks().unpack()) + .saturating_sub(config.finality_blocks().unpack()); + Timepoint::from_block_number(finalized_number) + } else { + let rollup_input_since = Since::new(load_input_since(0, Source::GroupInput)?); + let rollup_input_timestamp = match ( + rollup_input_since.is_absolute(), + rollup_input_since.extract_lock_value(), + ) { + (true, Some(LockValue::Timestamp(time_ms))) => time_ms, + _ => return Err(Error::InvalidSince), + }; + let l1_timestamp = rollup_input_timestamp; + let finalized_timestamp = l1_timestamp.saturating_sub(finality_as_duration(&config)); + Timepoint::from_timestamp(finalized_timestamp) }; + let new_tip_block = revert_args.new_tip_block(); if new_tip_block.hash() != tip_block_hash.as_slice() { debug!("[verify revert] reverted new_tip_block doesn't match"); @@ -269,7 +285,7 @@ fn check_reverted_blocks( .block(block_merkle_state) .tip_block_hash(tip_block_hash.to_entity()) .tip_block_timestamp(tip_block_timestamp.to_entity()) - .last_finalized_block_number(last_finalized_block_number.pack()) + .last_finalized_block_number(last_finalized.full_value().pack()) .reverted_block_root(reverted_block_root) .status(status.into()) .build() diff --git a/gwos/contracts/state-validator/src/verifications/submit_block.rs b/gwos/contracts/state-validator/src/verifications/submit_block.rs index b68e0bc38..48f8bb76d 100644 --- a/gwos/contracts/state-validator/src/verifications/submit_block.rs +++ b/gwos/contracts/state-validator/src/verifications/submit_block.rs @@ -15,6 +15,7 @@ use gw_utils::gw_types::packed::{L2BlockReader, WithdrawalRequestReader}; // https://nervosnetwork.github.io/ckb-std/riscv64imac-unknown-none-elf/doc/ckb_std/index.html use crate::ckb_std::{ckb_constants::Source, debug}; use gw_state::kv_state::KVState; +use gw_utils::finality::{finality_as_duration, is_finalized}; use gw_utils::gw_common::{self, ckb_decimal::CKBCapacity}; use gw_utils::gw_types::{self, U256}; @@ -42,7 +43,7 @@ use gw_common::{ }; use gw_types::{ bytes::Bytes, - core::{ScriptHashType, Status}, + core::{ScriptHashType, Status, Timepoint}, packed::{Byte32, GlobalState, RawL2Block, RollupConfig}, prelude::*, }; @@ -73,13 +74,21 @@ fn check_withdrawal_cells<'a>( for cell in withdrawal_cells { // check withdrawal cell block info let withdrawal_block_hash: H256 = cell.args.withdrawal_block_hash().unpack(); - if withdrawal_block_hash != context.block_hash - || cell.args.withdrawal_block_number().unpack() != context.number - { + if withdrawal_block_hash != context.block_hash { debug!("withdrawal cell mismatch block_hash"); return Err(Error::InvalidWithdrawalCell); } + let expected_timepoint = if context.post_version < 2 { + Timepoint::from_block_number(context.number) + } else { + Timepoint::from_timestamp(context.timestamp) + }; + if cell.args.withdrawal_block_number().unpack() != expected_timepoint.full_value() { + debug!("withdrawal cell mismatch timepoint"); + return Err(Error::InvalidWithdrawalCell); + } + let cell_account_script_hash: H256 = cell.args.account_script_hash().unpack(); // check that there is a corresponded withdrawal request match withdrawal_requests.iter().position(|request| { @@ -116,6 +125,7 @@ fn check_withdrawal_cells<'a>( fn check_input_custodian_cells( config: &RollupConfig, + prev_global_state: &GlobalState, context: &BlockContext, output_withdrawal_cells: Vec, ) -> Result, Error> { @@ -124,8 +134,11 @@ fn check_input_custodian_cells( collect_custodian_locks(&context.rollup_type_hash, config, Source::Input)? .into_iter() .partition(|cell| { - let number: u64 = cell.args.deposit_block_number().unpack(); - number <= context.finalized_number + is_finalized( + config, + prev_global_state, + &Timepoint::from_full_value(cell.args.deposit_block_number().unpack()), + ) }); // check unfinalized custodian cells == reverted deposit requests let mut reverted_deposit_cells = @@ -160,6 +173,7 @@ fn check_input_custodian_cells( fn check_output_custodian_cells( config: &RollupConfig, + prev_global_state: &GlobalState, context: &BlockContext, mut deposit_cells: Vec, input_finalized_assets: BTreeMap, @@ -169,15 +183,28 @@ fn check_output_custodian_cells( collect_custodian_locks(&context.rollup_type_hash, config, Source::Output)? .into_iter() .partition(|cell| { - let number: u64 = cell.args.deposit_block_number().unpack(); - number <= context.finalized_number + is_finalized( + config, + prev_global_state, + &Timepoint::from_full_value(cell.args.deposit_block_number().unpack()), + ) }); // check deposits request cells == unfinalized custodian cells + // check l2block's timepoint == unfinalized custodian cells' deposit_block_number + // check l2block's block_hash == unfinalized custodian cells' deposit_block_hash + let expected_timepoint = if context.post_version < 2 { + Timepoint::from_block_number(context.number) + } else { + Timepoint::from_timestamp(context.timestamp) + }; for custodian_cell in unfinalized_custodian_cells { let index = deposit_cells .iter() .position(|cell| { custodian_cell.args.deposit_lock_args() == cell.args + && custodian_cell.args.deposit_block_hash() == context.block_hash.pack() + && custodian_cell.args.deposit_block_number().unpack() + == expected_timepoint.full_value() && custodian_cell.value == cell.value }) .ok_or(Error::InvalidCustodianCell)?; @@ -375,7 +402,7 @@ fn check_layer2_withdrawal( fn load_block_context_and_state<'a>( rollup_type_hash: H256, - config: &RollupConfig, + rollup_config: &RollupConfig, tree_buffer: &'a mut [Pair], kv_state_proof: &'a Bytes, l2block: &L2BlockReader, @@ -396,7 +423,7 @@ fn load_block_context_and_state<'a>( } let timestamp: u64 = raw_block.timestamp().unpack(); - check_block_timestamp(prev_global_state, post_global_state, timestamp)?; + check_block_timestamp(rollup_config, post_global_state, timestamp)?; // verify parent block hash if raw_block.parent_block_hash().as_slice() != prev_global_state.tip_block_hash().as_slice() { @@ -465,9 +492,9 @@ fn load_block_context_and_state<'a>( } // Generate context + let post_version: u8 = post_global_state.version().into(); let account_count: u32 = prev_global_state.account().count().unpack(); let prev_account_root = prev_global_state.account().merkle_root().unpack(); - let finalized_number = number.saturating_sub(config.finality_blocks().unpack()); // Check pre account merkle proof let kv_state = KVState::build( @@ -484,13 +511,30 @@ fn load_block_context_and_state<'a>( let context = BlockContext { number, - finalized_number, timestamp, rollup_type_hash, block_hash, prev_account_root, + post_version, }; + debug!( + "[load_block_context_and_state] BlockContext: {{ + rollup_type_hash: {:?}, + number: {}, + timestamp: {}, + block_hash: {:#x}, + post_version: {}, + prev_account_root: {:#x} + }}", + context.rollup_type_hash.pack(), + context.number, + context.timestamp, + context.block_hash.pack(), + context.post_version, + context.prev_account_root.pack() + ); + Ok((context, kv_state)) } @@ -525,10 +569,15 @@ fn verify_block_producer( Source::Input, &owner_lock_hash, )? { + let expected_timepoint = if context.post_version < 2 { + Timepoint::from_block_number(context.number) + } else { + Timepoint::from_timestamp(context.timestamp) + }; let expected_stake_lock_args = input_stake_cell .args .as_builder() - .stake_block_number(raw_block.number().to_entity()) + .stake_block_number(expected_timepoint.full_value().pack()) .build(); if expected_stake_lock_args != output_stake_cell.args || input_stake_cell.capacity > output_stake_cell.capacity @@ -682,58 +731,136 @@ fn check_block_withdrawals(block: &L2BlockReader) -> Result<(), Error> { Ok(()) } +// Assert l2block.timestamp == post_global_state.tip_block_timestamp +// Assert l2block.timestamp <= l1tx.since +// Assert l2block.timestamp <= +// post_global_state.last_finalized_timepoint +// + rollup_config.finality_as_duration() +// + 4h +// Assert l2block.timestamp >= +// post_global_state.last_finalized_timepoint +// + rollup_config.finality_as_duration() +// - 4h fn check_block_timestamp( - prev_global_state: &GlobalState, + rollup_config: &RollupConfig, post_global_state: &GlobalState, block_timestamp: u64, ) -> Result<(), Error> { - let prev_version: u8 = prev_global_state.version().into(); + let post_block_timestamp: u64 = post_global_state.tip_block_timestamp().unpack(); + if block_timestamp != post_block_timestamp { + debug!( + "[check_block_timestamp] block.timestamp is not same as post_global_state.tip_block_timestamp, {} != {}", + block_timestamp, post_block_timestamp + ); + return Err(Error::InvalidBlock); + } + let post_version: u8 = post_global_state.version().into(); + if post_version >= 1 { + let rollup_input_since = Since::new(load_input_since(0, Source::GroupInput)?); + let rollup_input_timestamp = match ( + rollup_input_since.is_absolute(), + rollup_input_since.extract_lock_value(), + ) { + (true, Some(LockValue::Timestamp(time_ms))) => time_ms, + _ => return Err(Error::InvalidSince), + }; + if rollup_input_timestamp <= block_timestamp { + return Err(Error::InvalidPostGlobalState); + } + } - if 0 == post_version && post_global_state.tip_block_timestamp().unpack() != 0 { - debug!("v0 global state tip block timestamp isn't 0"); - return Err(Error::InvalidPostGlobalState); + if post_version >= 2 { + // 4 hours, 4 * 60 * 60 * 1000 = 14400000ms + const BACKBONE_BIAS: u64 = 14400000; + let backbone = post_global_state.last_finalized_block_number().unpack() + + rollup_config.finality_as_duration(); + if !(backbone.saturating_sub(BACKBONE_BIAS) <= block_timestamp + && block_timestamp <= backbone.saturating_add(BACKBONE_BIAS)) + { + debug!( + "[check_block_timestamp] block.timestamp is out of available range, block.timestamp: {}, backbone range: [{}-{}, {}+{}]", + block_timestamp, + backbone, BACKBONE_BIAS, + backbone, BACKBONE_BIAS + ); + return Err(Error::InvalidBlock); + } } - // NOTE: Downgrade already checked in main - if 0 == post_version { - debug!("[check block timestamp] skip block timestamp"); - return Ok(()); + Ok(()) +} + +fn check_global_state_tip_block_timestamp( + prev_global_state: &GlobalState, + post_global_state: &GlobalState, +) -> Result<(), Error> { + let prev_block_timestamp: u64 = prev_global_state.tip_block_timestamp().unpack(); + let post_block_timestamp: u64 = post_global_state.tip_block_timestamp().unpack(); + if !(prev_block_timestamp < post_block_timestamp) { + debug!( + "[check_global_state_tip_block_timestamp] prev_block_timestamp: {}, post_block_timestamp: {}", + prev_block_timestamp, + post_block_timestamp + ); + return Err(Error::InvalidPostGlobalState); } + Ok(()) +} - let rollup_input_since = Since::new(load_input_since(0, Source::GroupInput)?); - if !rollup_input_since.is_absolute() { - return Err(Error::InvalidSince); +fn check_global_state_last_finalized_timepoint( + rollup_config: &RollupConfig, + context: &BlockContext, + prev_global_state: &GlobalState, + post_global_state: &GlobalState, +) -> Result<(), Error> { + // skip + // if context.post_version == 0 { } + + if prev_global_state.last_finalized_block_number().unpack() + > post_global_state.last_finalized_block_number().unpack() + { + return Err(Error::InvalidPostGlobalState); } - let rollup_input_timestamp = match rollup_input_since.extract_lock_value() { - Some(LockValue::Timestamp(time)) => time, - _ => return Err(Error::InvalidSince), - }; - debug!( - "[check block timestamp] input since timestamp {}", - rollup_input_timestamp - ); + let last_finalized_timepoint = + Timepoint::from_full_value(post_global_state.last_finalized_block_number().unpack()); - let tip_block_timestamp = prev_global_state.tip_block_timestamp().unpack(); - if prev_version > 0 && tip_block_timestamp >= rollup_input_timestamp { - debug!("[check block timestamp] input since is smaller than tip block timestamp"); - return Err(Error::InvalidSince); + if context.post_version == 1 { + match last_finalized_timepoint { + Timepoint::BlockNumber(last_finalized_block_number) => { + let finality_as_blocks = rollup_config.finality_blocks().unpack(); + if last_finalized_block_number.saturating_add(finality_as_blocks) != context.number + { + return Err(Error::InvalidPostGlobalState); + } + } + Timepoint::Timestamp(_) => { + return Err(Error::InvalidPostGlobalState); + } + } + return Ok(()); } - let post_block_timestamp: u64 = post_global_state.tip_block_timestamp().unpack(); - if block_timestamp != post_block_timestamp - || block_timestamp > rollup_input_timestamp - || (prev_version != 0 && block_timestamp <= tip_block_timestamp) - { - debug!( - "[check block timestamp] invalid block timestamp {}, post block timestamp {}, rollup input timestamp {} tip block timestamp {}", - block_timestamp, - post_block_timestamp, - rollup_input_timestamp, - tip_block_timestamp - ); - return Err(Error::InvalidBlock); + let rollup_input_since = Since::new(load_input_since(0, Source::GroupInput)?); + let rollup_input_timestamp = match ( + rollup_input_since.is_absolute(), + rollup_input_since.extract_lock_value(), + ) { + (true, Some(LockValue::Timestamp(time_ms))) => time_ms, + _ => return Err(Error::InvalidSince), + }; + match last_finalized_timepoint { + Timepoint::BlockNumber(_) => { + return Err(Error::InvalidPostGlobalState); + } + Timepoint::Timestamp(last_finalized_timestamp) => { + if !(last_finalized_timestamp + finality_as_duration(rollup_config) + < rollup_input_timestamp) + { + return Err(Error::InvalidPostGlobalState); + } + } } Ok(()) @@ -778,9 +905,11 @@ pub fn verify( let withdrawal_requests_vec = block.withdrawals(); let withdrawal_requests = withdrawal_requests_vec.iter().collect(); check_withdrawal_cells(&context, withdrawal_requests, &withdrawal_cells)?; - let input_finalized_assets = check_input_custodian_cells(config, &context, withdrawal_cells)?; + let input_finalized_assets = + check_input_custodian_cells(config, prev_global_state, &context, withdrawal_cells)?; check_output_custodian_cells( config, + prev_global_state, &context, deposit_cells.clone(), input_finalized_assets, @@ -799,6 +928,14 @@ pub fn verify( // Check transactions check_block_transactions(block, &kv_state)?; + check_global_state_tip_block_timestamp(prev_global_state, post_global_state)?; + check_global_state_last_finalized_timepoint( + &config, + &context, + prev_global_state, + post_global_state, + )?; + // Verify Post state let actual_post_global_state = { // because of the optimistic challenge mechanism, @@ -807,10 +944,11 @@ pub fn verify( let account_merkle_state = block.raw().post_account(); // we have verified the post block merkle state let block_merkle_state = post_global_state.block(); - // last finalized block number - let last_finalized_block_number = context.finalized_number; - let version = post_global_state.version(); - let tip_block_timestamp = if version == 0.into() { + + // check_global_state_tip_block_timestamp() has checked post_global_state.tip_block_timestamp + // check_global_state_last_finalized_timepoint() has checked post_global_state.last_finalized_block_number + let last_finalized_block_number = post_global_state.last_finalized_block_number(); + let tip_block_timestamp = if context.post_version == 0 { 0 } else { context.timestamp @@ -823,8 +961,8 @@ pub fn verify( .block(block_merkle_state) .tip_block_hash(context.block_hash.pack()) .tip_block_timestamp(tip_block_timestamp.pack()) - .last_finalized_block_number(last_finalized_block_number.pack()) - .version(version) + .last_finalized_block_number(last_finalized_block_number) + .version(context.post_version.into()) .build() }; diff --git a/gwos/contracts/withdrawal-lock/src/entry.rs b/gwos/contracts/withdrawal-lock/src/entry.rs index 6a1543cb0..1cbe6f33b 100644 --- a/gwos/contracts/withdrawal-lock/src/entry.rs +++ b/gwos/contracts/withdrawal-lock/src/entry.rs @@ -12,13 +12,17 @@ use gw_utils::ckb_std::{ debug, high_level::{load_cell_lock_hash, QueryIter}, }; +use gw_utils::finality::is_finalized; use gw_utils::gw_types::packed::{ CustodianLockArgs, CustodianLockArgsReader, RollupActionUnionReader, UnlockWithdrawalWitnessUnion, WithdrawalLockArgs, }; use gw_utils::{ cells::rollup::MAX_ROLLUP_WITNESS_SIZE, - gw_types::{self, core::ScriptHashType}, + gw_types::{ + self, + core::{ScriptHashType, Timepoint}, + }, }; use gw_utils::{cells::utils::search_lock_hash, ckb_std::high_level::load_cell_lock}; @@ -162,14 +166,16 @@ pub fn main() -> Result<(), Error> { .ok_or(Error::RollupCellNotFound)? } }; - // check finality - let withdrawal_block_number: u64 = lock_args.withdrawal_block_number().unpack(); - let last_finalized_block_number: u64 = - global_state.last_finalized_block_number().unpack(); + let config = load_rollup_config(&global_state.rollup_config_hash().unpack())?; - if withdrawal_block_number > last_finalized_block_number { - // not yet finalized - return Err(Error::InvalidArgs); + // check finality + let is_finalized = is_finalized( + &config, + &global_state, + &Timepoint::from_full_value(lock_args.withdrawal_block_number().unpack()), + ); + if !is_finalized { + return Err(Error::NotFinalized); } // withdrawal lock is finalized, unlock for owner