Skip to content

Commit

Permalink
feat(hardfork): allow loading uncommitted cell data hashes from tx pool
Browse files Browse the repository at this point in the history
  • Loading branch information
yangby-cryptape committed May 27, 2021
1 parent 0a1225c commit 10ffedf
Show file tree
Hide file tree
Showing 28 changed files with 306 additions and 81 deletions.
6 changes: 4 additions & 2 deletions benches/benches/benchmarks/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ fn bench(c: &mut Criterion) {
let mut seen_inputs = HashSet::new();

for tx in txs.clone() {
resolve_transaction(tx, &mut seen_inputs, &provider, snapshot).unwrap();
resolve_transaction(tx, &mut seen_inputs, &provider, snapshot, false)
.unwrap();
}

i -= 1;
Expand All @@ -158,7 +159,8 @@ fn bench(c: &mut Criterion) {
let rtxs: Vec<_> = txs
.into_iter()
.map(|tx| {
resolve_transaction(tx, &mut seen_inputs, &provider, snapshot).unwrap()
resolve_transaction(tx, &mut seen_inputs, &provider, snapshot, false)
.unwrap()
})
.collect();

Expand Down
8 changes: 7 additions & 1 deletion benches/benches/benchmarks/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,13 @@ pub fn dao_data(shared: &Shared, parent: &HeaderView, txs: &[TransactionView]) -
let snapshot: &Snapshot = &shared.snapshot();
let overlay_cell_provider = OverlayCellProvider::new(&transactions_provider, snapshot);
let rtxs = txs.iter().cloned().try_fold(vec![], |mut rtxs, tx| {
let rtx = resolve_transaction(tx, &mut seen_inputs, &overlay_cell_provider, snapshot);
let rtx = resolve_transaction(
tx,
&mut seen_inputs,
&overlay_cell_provider,
snapshot,
false,
);
match rtx {
Ok(rtx) => {
rtxs.push(rtx);
Expand Down
4 changes: 4 additions & 0 deletions chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ impl ChainService {

let verify_context = VerifyContext::new(txn, self.shared.consensus());
let async_handle = self.shared.tx_pool_controller().handle();
let hardfork_switch = self.shared.consensus().hardfork_switch();

let mut found_error = None;
for (ext, b) in fork
Expand All @@ -704,6 +705,8 @@ impl ChainService {
};

let transactions = b.transactions();
let allow_in_txpool = hardfork_switch
.is_allow_cell_data_hash_in_txpool_enabled(b.epoch().number());
let resolved = {
let txn_cell_provider = txn.cell_provider();
let cell_provider = OverlayCellProvider::new(&block_cp, &txn_cell_provider);
Expand All @@ -716,6 +719,7 @@ impl ChainService {
&mut seen_inputs,
&cell_provider,
&verify_context,
allow_in_txpool,
)
})
.collect::<Result<Vec<ResolvedTransaction>, _>>()
Expand Down
14 changes: 8 additions & 6 deletions chain/src/tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ fn test_genesis_transaction_spend() {
assert_eq!(
shared
.snapshot()
.cell(&OutPoint::new(genesis_tx_hash, 0), false),
.cell(&OutPoint::new(genesis_tx_hash, 0), false, false),
CellStatus::Unknown
);
}
Expand All @@ -142,7 +142,7 @@ fn test_transaction_spend_in_same_block() {
assert_eq!(
shared
.snapshot()
.cell(&OutPoint::new(hash.to_owned().to_owned(), 0), false),
.cell(&OutPoint::new(hash.to_owned().to_owned(), 0), false, false),
CellStatus::Unknown
);
}
Expand Down Expand Up @@ -171,12 +171,14 @@ fn test_transaction_spend_in_same_block() {
assert_eq!(
shared
.snapshot()
.cell(&OutPoint::new(last_cellbase_hash, 0), false),
.cell(&OutPoint::new(last_cellbase_hash, 0), false, false),
CellStatus::Unknown
);

assert_eq!(
shared.snapshot().cell(&OutPoint::new(tx1_hash, 0), false),
shared
.snapshot()
.cell(&OutPoint::new(tx1_hash, 0), false, false),
CellStatus::Unknown
);

Expand All @@ -189,7 +191,7 @@ fn test_transaction_spend_in_same_block() {
assert_eq!(
shared
.snapshot()
.cell(&OutPoint::new(tx2_hash.clone(), 0), false),
.cell(&OutPoint::new(tx2_hash.clone(), 0), false, false),
CellStatus::live_cell(CellMeta {
cell_output: tx2_output,
data_bytes: tx2_output_data.len() as u64,
Expand Down Expand Up @@ -375,7 +377,7 @@ fn test_genesis_transaction_fetch() {
let (_chain_controller, shared, _parent) = start_chain(Some(consensus));

let out_point = OutPoint::new(root_hash, 0);
let state = shared.snapshot().cell(&out_point, false);
let state = shared.snapshot().cell(&out_point, false, false);
assert!(state.is_live());
}

Expand Down
16 changes: 11 additions & 5 deletions chain/src/tests/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,18 +144,21 @@ fn test_block_cells_update() {
for tx in block.transactions()[1..4].iter() {
for pt in tx.output_pts() {
// full spent
assert_eq!(txn_cell_provider.cell(&pt, false), CellStatus::Unknown);
assert_eq!(
txn_cell_provider.cell(&pt, false, false),
CellStatus::Unknown
);
}
}

// ensure tx3 outputs is unspent after attach_block_cell
for pt in block.transactions()[4].output_pts() {
assert!(txn_cell_provider.cell(&pt, false).is_live());
assert!(txn_cell_provider.cell(&pt, false, false).is_live());
}

// ensure issue_tx outputs is spent after attach_block_cell
assert_eq!(
txn_cell_provider.cell(&issue_tx.output_pts()[0], false),
txn_cell_provider.cell(&issue_tx.output_pts()[0], false, false),
CellStatus::Unknown
);

Expand All @@ -164,12 +167,15 @@ fn test_block_cells_update() {
// ensure tx0-3 outputs is unknown after detach_block_cell
for tx in block.transactions()[1..=4].iter() {
for pt in tx.output_pts() {
assert_eq!(txn_cell_provider.cell(&pt, false), CellStatus::Unknown);
assert_eq!(
txn_cell_provider.cell(&pt, false, false),
CellStatus::Unknown
);
}
}

// ensure issue_tx outputs is back to live after detach_block_cell
assert!(txn_cell_provider
.cell(&issue_tx.output_pts()[0], false)
.cell(&issue_tx.output_pts()[0], false, false)
.is_live());
}
69 changes: 54 additions & 15 deletions chain/src/tests/load_input_data_hash_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ use crate::tests::util::{
use ckb_chain_spec::consensus::ConsensusBuilder;
use ckb_dao_utils::genesis_dao_data;
use ckb_test_chain_utils::load_input_data_hash_cell;
use ckb_tx_pool::{PlugTarget, TxEntry};
use ckb_types::prelude::*;
use ckb_types::{
bytes::Bytes,
core::{
capacity_bytes, BlockBuilder, Capacity, EpochNumberWithFraction, TransactionBuilder,
TransactionView,
capacity_bytes, hardfork::HardForkSwitch, BlockBuilder, Capacity, EpochNumberWithFraction,
TransactionBuilder, TransactionView,
},
packed::{CellDep, CellInput, CellOutputBuilder, OutPoint},
utilities::DIFF_TWO,
Expand Down Expand Up @@ -48,7 +49,8 @@ pub(crate) fn create_load_input_data_hash_transaction(
.build()
}

// Ensure tx-pool accept tx which calls syscall load_cell_data_hash from input
// Ensure tx-pool reject or accept tx which calls syscall load_cell_data_hash from input base on
// hardfork features.
#[test]
fn test_load_input_data_hash_cell() {
let (_, _, load_input_data_hash_script) = load_input_data_hash_cell();
Expand All @@ -74,20 +76,57 @@ fn test_load_input_data_hash_cell() {
.dao(dao)
.build();

let consensus = ConsensusBuilder::default()
.cellbase_maturity(EpochNumberWithFraction::new(0, 0, 1))
.genesis_block(genesis_block)
.build();
{
// Test CKB v2019 reject
let hardfork_switch = HardForkSwitch::new_without_any_enabled();
let consensus = ConsensusBuilder::default()
.cellbase_maturity(EpochNumberWithFraction::new(0, 0, 1))
.genesis_block(genesis_block.clone())
.hardfork_switch(hardfork_switch)
.build();

let (_chain_controller, shared, _parent) = start_chain(Some(consensus));

let tx0 = create_load_input_data_hash_transaction(&issue_tx, 0);
let tx1 = create_load_input_data_hash_transaction(&tx0, 0);

let tx_pool = shared.tx_pool_controller();
let ret = tx_pool.submit_local_tx(tx0.clone()).unwrap();
assert!(ret.is_err());
//ValidationFailure(2) missing item
assert!(format!("{}", ret.err().unwrap()).contains("ValidationFailure(2)"));

let entry0 = vec![TxEntry::dummy_resolve(tx0, 0, Capacity::shannons(0), 100)];
tx_pool.plug_entry(entry0, PlugTarget::Proposed).unwrap();

// Ensure tx which calls syscall load_cell_data_hash will got reject even previous tx is already in tx-pool
let ret = tx_pool.submit_local_tx(tx1).unwrap();
assert!(ret.is_err());
assert!(format!("{}", ret.err().unwrap()).contains("ValidationFailure(2)"));
}
{
// Test CKB v2021 accept
let hardfork_switch = HardForkSwitch::new_without_any_enabled()
.as_builder()
.rfc_pr_0228(0)
.build()
.unwrap();
let consensus = ConsensusBuilder::default()
.cellbase_maturity(EpochNumberWithFraction::new(0, 0, 1))
.genesis_block(genesis_block)
.hardfork_switch(hardfork_switch)
.build();

let (_chain_controller, shared, _parent) = start_chain(Some(consensus));
let (_chain_controller, shared, _parent) = start_chain(Some(consensus));

let tx0 = create_load_input_data_hash_transaction(&issue_tx, 0);
let tx1 = create_load_input_data_hash_transaction(&tx0, 0);
let tx0 = create_load_input_data_hash_transaction(&issue_tx, 0);
let tx1 = create_load_input_data_hash_transaction(&tx0, 0);

let tx_pool = shared.tx_pool_controller();
let ret = tx_pool.submit_local_tx(tx0).unwrap();
assert!(ret.is_ok());
let tx_pool = shared.tx_pool_controller();
let ret = tx_pool.submit_local_tx(tx0).unwrap();
assert!(ret.is_ok());

let ret = tx_pool.submit_local_tx(tx1).unwrap();
assert!(ret.is_ok());
let ret = tx_pool.submit_local_tx(tx1).unwrap();
assert!(ret.is_ok());
}
}
1 change: 0 additions & 1 deletion chain/src/tests/non_contextual_block_txs_verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ pub(crate) fn create_cellbase(
}
}

#[allow(clippy::too_many_arguments)]
pub(crate) fn gen_block(
parent_header: &HeaderView,
transactions: Vec<TransactionView>,
Expand Down
8 changes: 7 additions & 1 deletion chain/src/tests/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,13 @@ pub fn dao_data(
let transactions_provider = TransactionsProvider::new(txs.iter());
let overlay_cell_provider = OverlayCellProvider::new(&transactions_provider, store);
let rtxs = txs.iter().try_fold(vec![], |mut rtxs, tx| {
let rtx = resolve_transaction(tx.clone(), &mut seen_inputs, &overlay_cell_provider, store);
let rtx = resolve_transaction(
tx.clone(),
&mut seen_inputs,
&overlay_cell_provider,
store,
false,
);
match rtx {
Ok(rtx) => {
rtxs.push(rtx);
Expand Down
5 changes: 4 additions & 1 deletion rpc/src/module/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1393,7 +1393,10 @@ impl ChainRpc for ChainRpcImpl {
}

fn get_live_cell(&self, out_point: OutPoint, with_data: bool) -> Result<CellWithStatus> {
let cell_status = self.shared.snapshot().cell(&out_point.into(), with_data);
let cell_status = self
.shared
.snapshot()
.cell(&out_point.into(), with_data, true);
Ok(cell_status.into())
}

Expand Down
30 changes: 25 additions & 5 deletions rpc/src/module/experiment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,12 @@ pub(crate) struct DryRunner<'a> {
}

impl<'a> CellProvider for DryRunner<'a> {
fn cell(&self, out_point: &packed::OutPoint, with_data: bool) -> CellStatus {
fn cell(
&self,
out_point: &packed::OutPoint,
with_data: bool,
_allow_in_txpool: bool,
) -> CellStatus {
let snapshot = self.shared.snapshot();
snapshot
.get_cell(out_point)
Expand Down Expand Up @@ -244,12 +249,27 @@ impl<'a> DryRunner<'a> {

pub(crate) fn run(&self, tx: packed::Transaction) -> Result<DryRunResult> {
let snapshot: &Snapshot = &self.shared.snapshot();
match resolve_transaction(tx.into_view(), &mut HashSet::new(), self, self) {
let consensus = snapshot.consensus();
let tx_env = {
let tip_header = snapshot.tip_header();
TxVerifyEnv::new_submit(&tip_header)
};
let allow_in_txpool = {
let proposal_window = consensus.tx_proposal_window();
let epoch_number = tx_env.epoch_number(proposal_window);
consensus
.hardfork_switch()
.is_allow_cell_data_hash_in_txpool_enabled(epoch_number)
};
match resolve_transaction(
tx.into_view(),
&mut HashSet::new(),
self,
self,
allow_in_txpool,
) {
Ok(resolved) => {
let consensus = snapshot.consensus();
let max_cycles = consensus.max_block_cycles;
let tip_header = snapshot.tip_header();
let tx_env = TxVerifyEnv::new_submit(&tip_header);
match ScriptVerifier::new(
&resolved,
consensus,
Expand Down
8 changes: 7 additions & 1 deletion rpc/src/module/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use crate::error::RPCError;
use ckb_app_config::BlockAssemblerConfig;
use ckb_chain::chain::ChainController;
use ckb_dao::DaoCalculator;
use ckb_jsonrpc_types::{Block, BlockTemplate, Cycle, JsonBytes, Script, Transaction};
use ckb_jsonrpc_types::{
AsEpochNumberWithFraction, Block, BlockTemplate, Cycle, JsonBytes, Script, Transaction,
};
use ckb_logger::error;
use ckb_network::{NetworkController, SupportProtocols};
use ckb_shared::{shared::Shared, Snapshot};
Expand Down Expand Up @@ -179,12 +181,16 @@ impl IntegrationTestRpc for IntegrationTestRpcImpl {
let transactions_provider = TransactionsProvider::new(txs.as_slice().iter());
let overlay_cell_provider = OverlayCellProvider::new(&transactions_provider, snapshot);

let allow_in_txpool = consensus
.hardfork_switch()
.is_allow_cell_data_hash_in_txpool_enabled(block_template.epoch.epoch_number());
let rtxs = txs.iter().map(|tx| {
resolve_transaction(
tx.clone(),
&mut seen_inputs,
&overlay_cell_provider,
snapshot,
allow_in_txpool,
).map_err(|err| {
error!(
"resolve transactions error when generating block with block template, error: {:?}",
Expand Down
10 changes: 8 additions & 2 deletions rpc/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,14 @@ fn next_block(shared: &Shared, parent: &HeaderView) -> BlockView {
let cellbase = always_success_cellbase(parent.number() + 1, reward.total, shared.consensus());

let dao = {
let resolved_cellbase =
resolve_transaction(cellbase.clone(), &mut HashSet::new(), snapshot, snapshot).unwrap();
let resolved_cellbase = resolve_transaction(
cellbase.clone(),
&mut HashSet::new(),
snapshot,
snapshot,
false,
)
.unwrap();
let data_loader = shared.store().as_data_provider();
DaoCalculator::new(shared.consensus(), &data_loader)
.dao_field(&[resolved_cellbase], parent)
Expand Down
Loading

0 comments on commit 10ffedf

Please sign in to comment.