Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
372: feat: tx valid since r=quake a=jjyr



Co-authored-by: jjy <jjyruby@gmail.com>
  • Loading branch information
bors[bot] and jjyr committed Apr 12, 2019
2 parents 69d06e1 + ef16437 commit b58721d
Show file tree
Hide file tree
Showing 37 changed files with 838 additions and 318 deletions.
4 changes: 2 additions & 2 deletions benches/benches/process_block.rs
Expand Up @@ -142,7 +142,7 @@ fn new_chain() -> (
let commit_transactions: Vec<Transaction> = (0..100)
.map(|i| {
TransactionBuilder::default()
.input(CellInput::new(OutPoint::null(), vec![]))
.input(CellInput::new(OutPoint::null(), 0, vec![]))
.output(CellOutput::new(
50000,
vec![i],
Expand Down Expand Up @@ -231,6 +231,6 @@ fn create_transaction(hash: H256) -> Transaction {
Script::always_success(),
None,
))
.input(CellInput::new(OutPoint::new(hash, 0), vec![]))
.input(CellInput::new(OutPoint::new(hash, 0), 0, vec![]))
.build()
}
52 changes: 46 additions & 6 deletions chain/src/chain.rs
@@ -1,19 +1,20 @@
use ckb_chain_spec::consensus::Consensus;
use ckb_core::block::Block;
use ckb_core::cell::{
resolve_transaction, BlockCellProvider, OverlayCellProvider, ResolvedTransaction,
};
use ckb_core::extras::BlockExt;
use ckb_core::service::{Request, DEFAULT_CHANNEL_SIZE, SIGNAL_CHANNEL_SIZE};
use ckb_core::transaction::ProposalShortId;
use ckb_core::BlockNumber;
use ckb_core::{header::Header, BlockNumber};
use ckb_notify::NotifyController;
use ckb_shared::cell_set::CellSetDiff;
use ckb_shared::chain_state::ChainState;
use ckb_shared::error::SharedError;
use ckb_shared::index::ChainIndex;
use ckb_shared::shared::Shared;
use ckb_shared::store::StoreBatch;
use ckb_traits::ChainProvider;
use ckb_traits::{BlockMedianTimeContext, ChainProvider};
use ckb_verification::{BlockVerifier, TransactionsVerifier, Verifier};
use crossbeam_channel::{self, select, Receiver, Sender};
use failure::Error as FailureError;
Expand Down Expand Up @@ -96,6 +97,39 @@ impl GlobalIndex {
}
}

// Verification context for fork
struct ForkContext<'a, CI> {
pub fork_blocks: &'a [Block],
pub store: Arc<CI>,
pub consensus: &'a Consensus,
}

impl<'a, CI: ChainIndex> ForkContext<'a, CI> {
fn get_header(&self, number: BlockNumber) -> Option<Header> {
match self
.fork_blocks
.iter()
.find(|b| b.header().number() == number)
{
Some(block) => Some(block.header().to_owned()),
None => self
.store
.get_block_hash(number)
.and_then(|hash| self.store.get_header(&hash)),
}
}
}

impl<'a, CI: ChainIndex> BlockMedianTimeContext for ForkContext<'a, CI> {
fn median_block_count(&self) -> u64 {
self.consensus.median_time_block_count() as u64
}

fn timestamp(&self, number: BlockNumber) -> Option<u64> {
self.get_header(number).map(|header| header.timestamp())
}
}

pub struct ChainService<CI> {
shared: Shared<CI>,
notify: NotifyController,
Expand Down Expand Up @@ -439,6 +473,12 @@ impl<CI: ChainIndex + 'static> ChainService<CI> {
chain_state.mut_txs_verify_cache(),
&resolved,
self.shared.block_reward(b.header().number()),
ForkContext {
fork_blocks: &fork.attached_blocks,
store: Arc::clone(self.shared.store()),
consensus: self.shared.consensus(),
},
b.header().number(),
) {
Ok(_) => {
cell_set_diff.push_new(b);
Expand Down Expand Up @@ -506,10 +546,10 @@ impl<CI: ChainIndex + 'static> ChainService<CI> {

debug!(target: "chain", "Proposal in Head Block {{");
debug!(target: "chain", " {:?}", self
.shared
.block_hash(tip)
.and_then(|hash| self.shared.store().get_block_proposal_txs_ids(&hash))
.expect("invalid block number"));
.shared
.block_hash(tip)
.and_then(|hash| self.shared.store().get_block_proposal_txs_ids(&hash))
.expect("invalid block number"));

debug!(target: "chain", "}}");

Expand Down
11 changes: 7 additions & 4 deletions chain/src/tests/basic.rs
Expand Up @@ -2,7 +2,7 @@ use crate::tests::util::{create_transaction, gen_block, start_chain};
use ckb_chain_spec::consensus::Consensus;
use ckb_core::block::Block;
use ckb_core::block::BlockBuilder;
use ckb_core::cell::{CellProvider, CellStatus};
use ckb_core::cell::{CellMeta, CellProvider, CellStatus};
use ckb_core::header::HeaderBuilder;
use ckb_core::script::Script;
use ckb_core::transaction::{CellInput, CellOutput, OutPoint, TransactionBuilder};
Expand All @@ -14,7 +14,7 @@ use std::sync::Arc;
#[test]
fn test_genesis_transaction_spend() {
let tx = TransactionBuilder::default()
.input(CellInput::new(OutPoint::null(), Default::default()))
.input(CellInput::new(OutPoint::null(), 0, Default::default()))
.outputs(vec![
CellOutput::new(
100_000_000,
Expand Down Expand Up @@ -173,7 +173,10 @@ fn test_transaction_spend_in_same_block() {
.chain_state()
.lock()
.cell(&OutPoint::new(tx2_hash, 0)),
CellStatus::Live(tx2_output)
CellStatus::Live(CellMeta {
cell_output: tx2_output,
block_number: Some(4)
})
);
}

Expand Down Expand Up @@ -344,7 +347,7 @@ fn test_transaction_conflict_in_different_blocks() {
#[test]
fn test_genesis_transaction_fetch() {
let tx = TransactionBuilder::default()
.input(CellInput::new(OutPoint::null(), Default::default()))
.input(CellInput::new(OutPoint::null(), 0, Default::default()))
.outputs(vec![
CellOutput::new(
100_000_000,
Expand Down
2 changes: 1 addition & 1 deletion chain/src/tests/util.rs
Expand Up @@ -81,6 +81,6 @@ pub(crate) fn create_transaction(parent: H256, unique_data: u8) -> Transaction {
Script::always_success(),
None,
))
.input(CellInput::new(OutPoint::new(parent, 0), vec![]))
.input(CellInput::new(OutPoint::new(parent, 0), 0, vec![]))
.build()
}
38 changes: 25 additions & 13 deletions core/src/cell.rs
Expand Up @@ -6,10 +6,16 @@ use numext_fixed_hash::H256;
use std::iter::Chain;
use std::slice;

#[derive(Clone, PartialEq, Debug)]
pub struct CellMeta {
pub cell_output: CellOutput,
pub block_number: Option<u64>,
}

#[derive(Clone, PartialEq, Debug)]
pub enum CellStatus {
/// Cell exists and has not been spent.
Live(CellOutput),
Live(CellMeta),
/// Cell exists and has been spent.
Dead,
/// Cell does not exist.
Expand All @@ -32,14 +38,14 @@ impl CellStatus {
self == &CellStatus::Unknown
}

pub fn get_live(&self) -> Option<&CellOutput> {
pub fn get_live(&self) -> Option<&CellMeta> {
match *self {
CellStatus::Live(ref output) => Some(output),
_ => None,
}
}

pub fn take_live(self) -> Option<CellOutput> {
pub fn take_live(self) -> Option<CellMeta> {
match self {
CellStatus::Live(output) => Some(output),
_ => None,
Expand Down Expand Up @@ -114,7 +120,10 @@ impl<'a> CellProvider for BlockCellProvider<'a> {
.outputs()
.get(out_point.index as usize)
{
Some(x) => CellStatus::Live(x.clone()),
Some(x) => CellStatus::Live(CellMeta {
cell_output: x.clone(),
block_number: Some(self.block.header().number()),
}),
None => CellStatus::Unknown,
}
} else {
Expand Down Expand Up @@ -191,8 +200,8 @@ impl ResolvedTransaction {
self.input_cells
.iter()
.filter_map(|cell_status| {
if let CellStatus::Live(cell_output) = cell_status {
Some(cell_output.capacity)
if let CellStatus::Live(cell_meta) = cell_status {
Some(cell_meta.cell_output.capacity)
} else {
None
}
Expand All @@ -209,12 +218,12 @@ mod tests {
use std::collections::HashMap;

struct CellMemoryDb {
cells: HashMap<OutPoint, Option<CellOutput>>,
cells: HashMap<OutPoint, Option<CellMeta>>,
}
impl CellProvider for CellMemoryDb {
fn cell(&self, o: &OutPoint) -> CellStatus {
match self.cells.get(o) {
Some(&Some(ref cell_output)) => CellStatus::Live(cell_output.clone()),
Some(&Some(ref cell)) => CellStatus::Live(cell.clone()),
Some(&None) => CellStatus::Dead,
None => CellStatus::Unknown,
}
Expand All @@ -239,11 +248,14 @@ mod tests {
hash: H256::zero(),
index: 3,
};
let o = CellOutput {
capacity: 2,
data: vec![],
lock: Script::default(),
type_: None,
let o = CellMeta {
block_number: Some(1),
cell_output: CellOutput {
capacity: 2,
data: vec![],
lock: Script::default(),
type_: None,
},
};

db.cells.insert(p1.clone(), Some(o.clone()));
Expand Down
22 changes: 12 additions & 10 deletions core/src/transaction.rs
Expand Up @@ -63,32 +63,36 @@ impl OutPoint {
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, OccupiedCapacity)]
pub struct CellInput {
pub previous_output: OutPoint,
pub valid_since: u64,
// Depends on whether the operation is Transform or Destroy, this is the proof to transform
// lock or destroy lock.
pub args: Vec<Vec<u8>>,
}

impl CellInput {
pub fn new(previous_output: OutPoint, args: Vec<Vec<u8>>) -> Self {
pub fn new(previous_output: OutPoint, valid_since: u64, args: Vec<Vec<u8>>) -> Self {
CellInput {
previous_output,
valid_since,
args,
}
}

pub fn new_cellbase_input(block_number: BlockNumber) -> Self {
CellInput {
previous_output: OutPoint::null(),
valid_since: 0,
args: vec![block_number.to_le_bytes().to_vec()],
}
}

pub fn destruct(self) -> (OutPoint, Vec<Vec<u8>>) {
pub fn destruct(self) -> (OutPoint, u64, Vec<Vec<u8>>) {
let CellInput {
previous_output,
valid_since,
args,
} = self;
(previous_output, args)
(previous_output, valid_since, args)
}
}

Expand Down Expand Up @@ -424,19 +428,17 @@ mod test {
Script::default(),
None,
))
.input(CellInput::new(OutPoint::new(H256::zero(), 0), vec![]))
.input(CellInput::new(OutPoint::new(H256::zero(), 0), 0, vec![]))
.witness(vec![vec![7, 8, 9]])
.build();

assert_eq!(
tx.hash(),
H256::from_hex_str("3a4238c3fda565d6e76e76b5b05d3403b37b94d53c1644d5ff58d4e9293ca468")
.unwrap()
format!("{:x}", tx.hash()),
"a896bfe8c8439305f099e1f07b47844ba0a5a27ec1e26ec25b236fa7e4831115"
);
assert_eq!(
tx.witness_hash(),
H256::from_hex_str("997f0627d2c1ef00fc98311357aa097c3fff5ed0a0408e14ea26656f5beae6b3")
.unwrap()
format!("{:x}", tx.witness_hash()),
"3f08580e373cad9a828173efe614ce3a8310957351c77f2859a18fc49d4cd227"
);
}
}
4 changes: 4 additions & 0 deletions core/src/transaction_meta.rs
Expand Up @@ -47,6 +47,10 @@ impl TransactionMeta {
self.dead_cell.len()
}

pub fn block_number(&self) -> u64 {
self.block_number
}

pub fn is_empty(&self) -> bool {
self.dead_cell.is_empty()
}
Expand Down
8 changes: 6 additions & 2 deletions miner/src/block_assembler.rs
Expand Up @@ -538,8 +538,12 @@ mod tests {
.with_header_builder(header_builder);

let resolver = HeaderResolverWrapper::new(block.header(), shared.clone());
let header_verifier = HeaderVerifier::new(shared.clone(), Pow::Dummy.engine());
assert!(header_verifier.verify(&resolver).is_ok());
let header_verify_result = {
let chain_state = shared.chain_state().lock();
let header_verifier = HeaderVerifier::new(&*chain_state, Pow::Dummy.engine());
header_verifier.verify(&resolver)
};
assert!(header_verify_result.is_ok());

let block_verify = BlockVerifier::new(shared.clone());
assert!(block_verify.verify(&block).is_ok());
Expand Down
1 change: 1 addition & 0 deletions protocol/src/builder.rs
Expand Up @@ -156,6 +156,7 @@ impl<'a> FbsCellInput<'a> {
let mut builder = CellInputBuilder::new(fbb);
builder.add_hash(&hash);
builder.add_index(cell_input.previous_output.index);
builder.add_valid_since(cell_input.valid_since);
builder.add_args(args);
builder.finish()
}
Expand Down
1 change: 1 addition & 0 deletions protocol/src/convert.rs
Expand Up @@ -280,6 +280,7 @@ impl<'a> TryFrom<ckb_protocol::CellInput<'a>> for ckb_core::transaction::CellInp
hash: TryInto::try_into(hash)?,
index: cell_input.index(),
},
valid_since: cell_input.valid_since(),
args: cast!(args)?,
})
}
Expand Down
1 change: 1 addition & 0 deletions protocol/src/protocol.fbs
Expand Up @@ -80,6 +80,7 @@ table OutPoint {
table CellInput {
hash: H256;
index: uint32;
valid_since: uint64;
args: [Bytes];
}

Expand Down

0 comments on commit b58721d

Please sign in to comment.