diff --git a/rpc/README.md b/rpc/README.md index e50b65674fb..0f0dc4de92e 100644 --- a/rpc/README.md +++ b/rpc/README.md @@ -1662,7 +1662,7 @@ Response { "rfc": "0029", "epoch_number": "0x0" }, { "rfc": "0030", "epoch_number": "0x0" }, { "rfc": "0031", "epoch_number": "0x0" }, - { "rfc": "0032", "epoch_number": "0x0" }, + { "rfc": "0032", "epoch_number": "0x1526" }, { "rfc": "0036", "epoch_number": "0x0" }, { "rfc": "0038", "epoch_number": "0x0" }, { "rfc": "0048", "epoch_number": null }, diff --git a/rpc/src/module/chain.rs b/rpc/src/module/chain.rs index 6a013be67cb..3704976f80f 100644 --- a/rpc/src/module/chain.rs +++ b/rpc/src/module/chain.rs @@ -1344,7 +1344,7 @@ pub trait ChainRpc { /// { "rfc": "0029", "epoch_number": "0x0" }, /// { "rfc": "0030", "epoch_number": "0x0" }, /// { "rfc": "0031", "epoch_number": "0x0" }, - /// { "rfc": "0032", "epoch_number": "0x0" }, + /// { "rfc": "0032", "epoch_number": "0x1526" }, /// { "rfc": "0036", "epoch_number": "0x0" }, /// { "rfc": "0038", "epoch_number": "0x0" }, /// { "rfc": "0048", "epoch_number": null }, diff --git a/script/src/verify.rs b/script/src/verify.rs index 8f8c406c7e2..bdb8b8d588c 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -536,6 +536,18 @@ impl bool { + // If the proposal window is allowed to prejudge on the vm version, + // it will cause proposal tx to start a new vm in the blocks before hardfork, + // destroying the assumption that the transaction execution only uses the old vm + // before hardfork, leading to unexpected network splits. + let epoch_number = self.tx_env.epoch_number_without_proposal_window(); + let hardfork_switch = self.consensus.hardfork_switch(); + hardfork_switch + .ckb2021 + .is_vm_version_1_and_syscalls_2_enabled(epoch_number) + } + fn is_vm_version_2_and_syscalls_3_enabled(&self) -> bool { // If the proposal window is allowed to prejudge on the vm version, // it will cause proposal tx to start a new vm in the blocks before hardfork, @@ -551,6 +563,7 @@ impl Result { let is_vm_version_2_and_syscalls_3_enabled = self.is_vm_version_2_and_syscalls_3_enabled(); + let is_vm_version_1_and_syscalls_2_enabled = self.is_vm_version_1_and_syscalls_2_enabled(); let script_hash_type = ScriptHashType::try_from(script.hash_type()) .map_err(|err| ScriptError::InvalidScriptHashType(err.to_string()))?; match script_hash_type { @@ -566,8 +579,10 @@ impl { if is_vm_version_2_and_syscalls_3_enabled { Ok(ScriptVersion::V2) - } else { + } else if is_vm_version_1_and_syscalls_2_enabled { Ok(ScriptVersion::V1) + } else { + Ok(ScriptVersion::V0) } } } diff --git a/script/src/verify/tests/ckb_latest/features_since_v2019.rs b/script/src/verify/tests/ckb_latest/features_since_v2019.rs index 516df11492f..77d224c0aea 100644 --- a/script/src/verify/tests/ckb_latest/features_since_v2019.rs +++ b/script/src/verify/tests/ckb_latest/features_since_v2019.rs @@ -190,96 +190,6 @@ fn check_signature_referenced_via_type_hash() { assert!(result.is_ok()); } -#[test] -fn check_signature_referenced_via_type_hash_ok_with_multiple_matches() { - let script_version = SCRIPT_VERSION; - - let mut file = open_cell_always_success(); - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer).unwrap(); - let data = Bytes::from(buffer); - - let (privkey, pubkey) = random_keypair(); - let mut args = b"foobar".to_vec(); - - let signature = sign_args(&args, &privkey); - args.extend(&to_hex_pubkey(&pubkey)); - args.extend(&to_hex_signature(&signature)); - - let dep_out_point = OutPoint::new(h256!("0x123").pack(), 8); - let cell_dep = CellDep::new_builder() - .out_point(dep_out_point.clone()) - .build(); - let output = CellOutputBuilder::default() - .capacity(Capacity::bytes(data.len()).unwrap().pack()) - .type_( - Some( - Script::new_builder() - .code_hash(h256!("0x123456abcd90").pack()) - .hash_type(ScriptHashType::Data.into()) - .build(), - ) - .pack(), - ) - .build(); - let type_hash = output.type_().to_opt().as_ref().unwrap().calc_script_hash(); - let dep_cell = CellMetaBuilder::from_cell_output(output, data.clone()) - .transaction_info(default_transaction_info()) - .out_point(dep_out_point) - .build(); - - let dep_out_point2 = OutPoint::new(h256!("0x1234").pack(), 8); - let cell_dep2 = CellDep::new_builder() - .out_point(dep_out_point2.clone()) - .build(); - let output2 = CellOutputBuilder::default() - .capacity(Capacity::bytes(data.len()).unwrap().pack()) - .type_( - Some( - Script::new_builder() - .code_hash(h256!("0x123456abcd90").pack()) - .hash_type(ScriptHashType::Data.into()) - .build(), - ) - .pack(), - ) - .build(); - let dep_cell2 = CellMetaBuilder::from_cell_output(output2, data) - .transaction_info(default_transaction_info()) - .out_point(dep_out_point2) - .build(); - - let script = Script::new_builder() - .args(Bytes::from(args).pack()) - .code_hash(type_hash) - .hash_type(ScriptHashType::Type.into()) - .build(); - let input = CellInput::new(OutPoint::null(), 0); - - let transaction = TransactionBuilder::default() - .input(input) - .cell_dep(cell_dep) - .cell_dep(cell_dep2) - .build(); - - let output = CellOutputBuilder::default() - .capacity(capacity_bytes!(100).pack()) - .lock(script) - .build(); - let dummy_cell = create_dummy_cell(output); - - let rtx = ResolvedTransaction { - transaction, - resolved_cell_deps: vec![dep_cell, dep_cell2], - resolved_inputs: vec![dummy_cell], - resolved_dep_groups: vec![], - }; - - let verifier = TransactionScriptsVerifierWithEnv::new(); - let result = verifier.verify_without_limit(script_version, &rtx); - assert_eq!(result.unwrap(), 539); -} - #[test] fn check_invalid_signature() { let script_version = SCRIPT_VERSION; diff --git a/script/src/verify/tests/ckb_latest/features_since_v2021.rs b/script/src/verify/tests/ckb_latest/features_since_v2021.rs index 423a67bd159..9570c326aed 100644 --- a/script/src/verify/tests/ckb_latest/features_since_v2021.rs +++ b/script/src/verify/tests/ckb_latest/features_since_v2021.rs @@ -10,7 +10,7 @@ use ckb_vm::Error as VmError; use proptest::{prelude::*, prop_assert_eq, proptest}; use rand::distributions::Uniform; use rand::{thread_rng, Rng}; -use std::collections::VecDeque; +use std::{collections::VecDeque, io::Read}; use super::SCRIPT_VERSION; use crate::syscalls::SOURCE_GROUP_FLAG; @@ -1694,3 +1694,97 @@ fn exec_slice() { let res = Ok(2); test_exec(0b0000, 1, 2, 1, from, res); } + +#[test] +fn check_signature_referenced_via_type_hash_ok_with_multiple_matches() { + let script_version = SCRIPT_VERSION; + if script_version < ScriptVersion::V1 { + // This transaction is restricted by rfc_0029 and not supported in the 2019 version + return; + } + + let mut file = open_cell_always_success(); + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer).unwrap(); + let data = Bytes::from(buffer); + + let (privkey, pubkey) = random_keypair(); + let mut args = b"foobar".to_vec(); + + let signature = sign_args(&args, &privkey); + args.extend(&to_hex_pubkey(&pubkey)); + args.extend(&to_hex_signature(&signature)); + + let dep_out_point = OutPoint::new(h256!("0x123").pack(), 8); + let cell_dep = CellDep::new_builder() + .out_point(dep_out_point.clone()) + .build(); + let output = CellOutputBuilder::default() + .capacity(Capacity::bytes(data.len()).unwrap().pack()) + .type_( + Some( + Script::new_builder() + .code_hash(h256!("0x123456abcd90").pack()) + .hash_type(ScriptHashType::Data.into()) + .build(), + ) + .pack(), + ) + .build(); + let type_hash = output.type_().to_opt().as_ref().unwrap().calc_script_hash(); + let dep_cell = CellMetaBuilder::from_cell_output(output, data.clone()) + .transaction_info(default_transaction_info()) + .out_point(dep_out_point) + .build(); + + let dep_out_point2 = OutPoint::new(h256!("0x1234").pack(), 8); + let cell_dep2 = CellDep::new_builder() + .out_point(dep_out_point2.clone()) + .build(); + let output2 = CellOutputBuilder::default() + .capacity(Capacity::bytes(data.len()).unwrap().pack()) + .type_( + Some( + Script::new_builder() + .code_hash(h256!("0x123456abcd90").pack()) + .hash_type(ScriptHashType::Data.into()) + .build(), + ) + .pack(), + ) + .build(); + let dep_cell2 = CellMetaBuilder::from_cell_output(output2, data) + .transaction_info(default_transaction_info()) + .out_point(dep_out_point2) + .build(); + + let script = Script::new_builder() + .args(Bytes::from(args).pack()) + .code_hash(type_hash) + .hash_type(ScriptHashType::Type.into()) + .build(); + let input = CellInput::new(OutPoint::null(), 0); + + let transaction = TransactionBuilder::default() + .input(input) + .cell_dep(cell_dep) + .cell_dep(cell_dep2) + .build(); + + let output = CellOutputBuilder::default() + .capacity(capacity_bytes!(100).pack()) + .lock(script) + .build(); + let dummy_cell = create_dummy_cell(output); + + let rtx = ResolvedTransaction { + transaction, + resolved_cell_deps: vec![dep_cell, dep_cell2], + resolved_inputs: vec![dummy_cell], + resolved_dep_groups: vec![], + }; + + let verifier = TransactionScriptsVerifierWithEnv::new(); + let result = verifier.verify_without_limit(script_version, &rtx); + assert_eq!(result.unwrap(), 539); +} diff --git a/script/src/verify/tests/utils.rs b/script/src/verify/tests/utils.rs index d206de1f377..8eaffcd64d7 100644 --- a/script/src/verify/tests/utils.rs +++ b/script/src/verify/tests/utils.rs @@ -126,6 +126,7 @@ pub(crate) struct TransactionScriptsVerifierWithEnv { // Ref: https://doc.rust-lang.org/reference/destructors.html store: Arc, consensus: Arc, + version_1_enabled_at: EpochNumber, version_2_enabled_at: EpochNumber, _tmp_dir: TempDir, } @@ -135,10 +136,15 @@ impl TransactionScriptsVerifierWithEnv { let tmp_dir = TempDir::new().unwrap(); let db = RocksDB::open_in(&tmp_dir, COLUMNS); let store = Arc::new(ChainDB::new(db, Default::default())); + let version_1_enabled_at = 5; let version_2_enabled_at = 10; let hardfork_switch = HardForks { - ckb2021: CKB2021::new_mirana(), + ckb2021: CKB2021::new_mirana() + .as_builder() + .rfc_0032(version_1_enabled_at) + .build() + .unwrap(), ckb2023: CKB2023::new_mirana() .as_builder() .rfc_0049(version_2_enabled_at) @@ -152,6 +158,7 @@ impl TransactionScriptsVerifierWithEnv { ); Self { store, + version_1_enabled_at, version_2_enabled_at, consensus, _tmp_dir: tmp_dir, @@ -237,7 +244,7 @@ impl TransactionScriptsVerifierWithEnv { let data_loader = self.store.as_data_loader(); let epoch = match version { ScriptVersion::V0 => EpochNumberWithFraction::new(0, 0, 1), - ScriptVersion::V1 => EpochNumberWithFraction::new(0, 0, 1), + ScriptVersion::V1 => EpochNumberWithFraction::new(self.version_1_enabled_at, 0, 1), ScriptVersion::V2 => EpochNumberWithFraction::new(self.version_2_enabled_at, 0, 1), }; let header = HeaderView::new_advanced_builder() diff --git a/spec/src/hardfork.rs b/spec/src/hardfork.rs index 2c1f411a2f1..6d304025b1a 100644 --- a/spec/src/hardfork.rs +++ b/spec/src/hardfork.rs @@ -23,7 +23,7 @@ impl HardForkConfig { ckb2021 = self.update_2021( ckb2021, mainnet::CKB2021_START_EPOCH, - mainnet::RFC0028_START_EPOCH, + mainnet::RFC0028_RFC0032_RFC0033_RFC0034_START_EPOCH, )?; Ok(HardForks { @@ -39,7 +39,7 @@ impl HardForkConfig { ckb2021 = self.update_2021( ckb2021, testnet::CKB2021_START_EPOCH, - testnet::RFC0028_START_EPOCH, + testnet::RFC0028_RFC0032_RFC0033_RFC0034_START_EPOCH, )?; let mut ckb2023 = CKB2023::new_builder(); ckb2023 = self.update_2023(ckb2023, testnet::CKB2023_START_EPOCH)?; @@ -54,14 +54,14 @@ impl HardForkConfig { &self, builder: CKB2021Builder, ckb2021: EpochNumber, - rfc_0028_start: EpochNumber, + rfc_0028_0032_0033_0034_start: EpochNumber, ) -> Result { let builder = builder - .rfc_0028(rfc_0028_start) + .rfc_0028(rfc_0028_0032_0033_0034_start) .rfc_0029(ckb2021) .rfc_0030(ckb2021) .rfc_0031(ckb2021) - .rfc_0032(ckb2021) + .rfc_0032(rfc_0028_0032_0033_0034_start) .rfc_0036(ckb2021) .rfc_0038(ckb2021); Ok(builder) @@ -80,12 +80,7 @@ impl HardForkConfig { /// /// Enable features which are set to `None` at the dev default config. pub fn complete_with_dev_default(&self) -> Result { - let mut ckb2021 = CKB2021::new_builder(); - ckb2021 = self.update_2021( - ckb2021, - testnet::CKB2021_START_EPOCH, - testnet::RFC0028_START_EPOCH, - )?; + let ckb2021 = CKB2021::new_dev_default(); let ckb2023 = if let Some(epoch) = self.ckb2023 { CKB2023::new_with_specified(epoch) @@ -93,9 +88,6 @@ impl HardForkConfig { CKB2023::new_dev_default() }; - Ok(HardForks { - ckb2021: ckb2021.build()?, - ckb2023, - }) + Ok(HardForks { ckb2021, ckb2023 }) } } diff --git a/util/constant/src/hardfork/mainnet.rs b/util/constant/src/hardfork/mainnet.rs index df7fc333935..a3f028a4521 100644 --- a/util/constant/src/hardfork/mainnet.rs +++ b/util/constant/src/hardfork/mainnet.rs @@ -1,8 +1,8 @@ /// The Chain Specification name. pub const CHAIN_SPEC_NAME: &str = "ckb"; -/// hardcode rfc0028 epoch -pub const RFC0028_START_EPOCH: u64 = 5414; +/// hardcode rfc0028/rfc0032/rfc0033/rfc0034 epoch +pub const RFC0028_RFC0032_RFC0033_RFC0034_START_EPOCH: u64 = 5414; /// First epoch number for CKB v2021, at about 2022/05/10 1:00 UTC // pub const CKB2021_START_EPOCH: u64 = 5414; pub const CKB2021_START_EPOCH: u64 = 0; diff --git a/util/constant/src/hardfork/testnet.rs b/util/constant/src/hardfork/testnet.rs index 362df34df33..6f2b061368b 100644 --- a/util/constant/src/hardfork/testnet.rs +++ b/util/constant/src/hardfork/testnet.rs @@ -1,8 +1,8 @@ /// The Chain Specification name. pub const CHAIN_SPEC_NAME: &str = "ckb_testnet"; -/// hardcode rfc0028 epoch -pub const RFC0028_START_EPOCH: u64 = 3113; +/// hardcode rfc0028/rfc0032/rfc0033/rfc0034 epoch +pub const RFC0028_RFC0032_RFC0033_RFC0034_START_EPOCH: u64 = 3113; /// First epoch number for CKB v2021, at about 2021/10/24 3:15 UTC. // pub const CKB2021_START_EPOCH: u64 = 3113; pub const CKB2021_START_EPOCH: u64 = 0; diff --git a/util/types/src/core/hardfork/ckb2021.rs b/util/types/src/core/hardfork/ckb2021.rs index ffe10d3e957..53aaa687eaa 100644 --- a/util/types/src/core/hardfork/ckb2021.rs +++ b/util/types/src/core/hardfork/ckb2021.rs @@ -87,13 +87,13 @@ impl CKB2021 { pub fn new_mirana() -> Self { // Use a builder to ensure all features are set manually. Self::new_builder() - .rfc_0028(hardfork::mainnet::RFC0028_START_EPOCH) - .rfc_0029(0) - .rfc_0030(0) - .rfc_0031(0) - .rfc_0032(0) - .rfc_0036(0) - .rfc_0038(0) + .rfc_0028(hardfork::mainnet::RFC0028_RFC0032_RFC0033_RFC0034_START_EPOCH) + .rfc_0029(hardfork::mainnet::CKB2021_START_EPOCH) + .rfc_0030(hardfork::mainnet::CKB2021_START_EPOCH) + .rfc_0031(hardfork::mainnet::CKB2021_START_EPOCH) + .rfc_0032(hardfork::mainnet::RFC0028_RFC0032_RFC0033_RFC0034_START_EPOCH) + .rfc_0036(hardfork::mainnet::CKB2021_START_EPOCH) + .rfc_0038(hardfork::mainnet::CKB2021_START_EPOCH) .build() .unwrap() }