Merge pull request #1751 from blockstack/feat/fix-1744

Feat/fix 1744
This commit is contained in:
Jude Nelson
2020-07-27 16:38:59 +00:00
committed by GitHub
16 changed files with 112 additions and 64 deletions

View File

@@ -584,6 +584,7 @@ mod test {
new_tip.block_height = parent_header_info.block_height + 1;
new_tip.consensus_hash = ConsensusHash(Hash160::from_data(&Sha512Trunc256Sum::from_data(&parent_header_info.consensus_hash.0).0).0);
new_tip.burn_header_hash = BurnchainHeaderHash(Sha512Trunc256Sum::from_data(&parent_header_info.consensus_hash.0).0);
new_tip.burn_header_height = parent_header_info.burn_header_height + 1;
block_reward.parent_consensus_hash = parent_header_info.consensus_hash.clone();
block_reward.parent_block_hash = parent_header_info.anchored_header.block_hash().clone();
@@ -602,6 +603,7 @@ mod test {
&new_tip.anchored_header,
&new_tip.consensus_hash,
&new_tip.burn_header_hash,
new_tip.burn_header_height,
new_tip.burn_header_timestamp,
new_tip.microblock_tail.clone(),
&block_reward,

View File

@@ -122,7 +122,6 @@ pub struct StagingMicroblock {
#[derive(Debug, Clone, PartialEq)]
pub struct StagingBlock {
pub consensus_hash: ConsensusHash,
pub burn_header_timestamp: u64,
pub anchored_block_hash: BlockHeaderHash,
pub parent_consensus_hash: ConsensusHash,
pub parent_anchored_block_hash: BlockHeaderHash,
@@ -281,7 +280,6 @@ impl FromRow<StagingBlock> for StagingBlock {
let anchored_block_hash : BlockHeaderHash = BlockHeaderHash::from_column(row, "anchored_block_hash")?;
let parent_anchored_block_hash : BlockHeaderHash = BlockHeaderHash::from_column(row, "parent_anchored_block_hash")?;
let consensus_hash : ConsensusHash = ConsensusHash::from_column(row, "consensus_hash")?;
let burn_header_timestamp = u64::from_column(row, "burn_header_timestamp")?;
let parent_consensus_hash: ConsensusHash = ConsensusHash::from_column(row, "parent_consensus_hash")?;
let parent_microblock_hash : BlockHeaderHash = BlockHeaderHash::from_column(row, "parent_microblock_hash")?;
let parent_microblock_seq : u16 = row.get("parent_microblock_seq");
@@ -302,7 +300,6 @@ impl FromRow<StagingBlock> for StagingBlock {
anchored_block_hash,
parent_anchored_block_hash,
consensus_hash,
burn_header_timestamp,
parent_consensus_hash,
parent_microblock_hash,
parent_microblock_seq,
@@ -421,7 +418,6 @@ const STACKS_BLOCK_INDEX_SQL : &'static [&'static str]= &[
CREATE TABLE staging_blocks(anchored_block_hash TEXT NOT NULL,
parent_anchored_block_hash TEXT NOT NULL,
consensus_hash TEXT NOT NULL,
burn_header_timestamp INT NOT NULL,
parent_consensus_hash TEXT NOT NULL,
parent_microblock_hash TEXT NOT NULL,
parent_microblock_seq INT NOT NULL,
@@ -1143,11 +1139,10 @@ impl StacksChainState {
/// Store a preprocessed block, queuing it up for subsequent processing.
/// The caller should at least verify that the block is attached to some fork in the burn
/// chain.
fn store_staging_block<'a>(tx: &mut BlocksDBTx<'a>, consensus_hash: &ConsensusHash, burn_header_timestamp: u64, block: &StacksBlock, parent_consensus_hash: &ConsensusHash, commit_burn: u64, sortition_burn: u64) -> Result<(), Error> {
fn store_staging_block<'a>(tx: &mut BlocksDBTx<'a>, consensus_hash: &ConsensusHash, block: &StacksBlock, parent_consensus_hash: &ConsensusHash, commit_burn: u64, sortition_burn: u64) -> Result<(), Error> {
debug!("Store anchored block {}/{}, parent in {}", consensus_hash, block.block_hash(), parent_consensus_hash);
assert!(commit_burn < i64::max_value() as u64);
assert!(sortition_burn < i64::max_value() as u64);
assert!(burn_header_timestamp < i64::max_value() as u64);
let block_hash = block.block_hash();
let index_block_hash = StacksBlockHeader::make_index_block_hash(&consensus_hash, &block_hash);
@@ -1173,7 +1168,6 @@ impl StacksChainState {
(anchored_block_hash, \
parent_anchored_block_hash, \
consensus_hash, \
burn_header_timestamp, \
parent_consensus_hash, \
parent_microblock_hash, \
parent_microblock_seq, \
@@ -1185,12 +1179,11 @@ impl StacksChainState {
commit_burn, \
sortition_burn, \
index_block_hash) \
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)";
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)";
let args: &[&dyn ToSql] = &[
&block_hash,
&block.header.parent_block,
&consensus_hash,
&u64_to_sql(burn_header_timestamp)?,
&parent_consensus_hash,
&block.header.parent_microblock,
&block.header.parent_microblock_sequence,
@@ -2263,7 +2256,7 @@ impl StacksChainState {
///
/// TODO: consider how full the block is (i.e. how much computational budget it consumes) when
/// deciding whether or not it can be processed.
pub fn preprocess_anchored_block(&mut self, sort_ic: &SortitionDBConn, consensus_hash: &ConsensusHash, burn_header_timestamp: u64, block: &StacksBlock, parent_consensus_hash: &ConsensusHash) -> Result<bool, Error> {
pub fn preprocess_anchored_block(&mut self, sort_ic: &SortitionDBConn, consensus_hash: &ConsensusHash, block: &StacksBlock, parent_consensus_hash: &ConsensusHash) -> Result<bool, Error> {
debug!("preprocess anchored block {}/{}", consensus_hash, block.block_hash());
let sort_handle = SortitionHandleConn::open_reader_consensus(sort_ic, consensus_hash)?;
@@ -2310,7 +2303,7 @@ impl StacksChainState {
debug!("Storing staging block");
// queue block up for processing
StacksChainState::store_staging_block(&mut block_tx, consensus_hash, burn_header_timestamp, &block, parent_consensus_hash, commit_burn, sortition_burn)?;
StacksChainState::store_staging_block(&mut block_tx, consensus_hash, &block, parent_consensus_hash, commit_burn, sortition_burn)?;
// store users who burned for this block so they'll get rewarded if we process it
StacksChainState::store_staging_block_user_burn_supports(&mut block_tx, consensus_hash, &block.block_hash(), &user_burns)?;
@@ -2404,7 +2397,7 @@ impl StacksChainState {
sn
};
self.preprocess_anchored_block(sort_ic, &snapshot.consensus_hash, snapshot.burn_header_timestamp, block, &parent_sn.consensus_hash)?;
self.preprocess_anchored_block(sort_ic, &snapshot.consensus_hash, block, &parent_sn.consensus_hash)?;
let block_hash = block.block_hash();
for mblock in microblocks.iter() {
self.preprocess_streamed_microblock(&snapshot.consensus_hash, &block_hash, mblock)?;
@@ -2772,6 +2765,7 @@ impl StacksChainState {
parent_chain_tip: &StacksHeaderInfo,
chain_tip_consensus_hash: &ConsensusHash,
chain_tip_burn_header_hash: &BurnchainHeaderHash,
chain_tip_burn_header_height: u32,
chain_tip_burn_header_timestamp: u64,
block: &StacksBlock,
microblocks: &Vec<StacksMicroblock>, // parent microblocks
@@ -2909,6 +2903,7 @@ impl StacksChainState {
&block.header,
chain_tip_consensus_hash,
chain_tip_burn_header_hash,
chain_tip_burn_header_height,
chain_tip_burn_header_timestamp,
microblock_tail_opt,
&scheduled_miner_reward,
@@ -2964,8 +2959,8 @@ impl StacksChainState {
}
};
let burn_header_hash = match SortitionDB::get_block_snapshot_consensus(sort_tx, &next_staging_block.consensus_hash)? {
Some(sn) => sn.burn_header_hash,
let (burn_header_hash, burn_header_height, burn_header_timestamp) = match SortitionDB::get_block_snapshot_consensus(sort_tx, &next_staging_block.consensus_hash)? {
Some(sn) => (sn.burn_header_hash, sn.block_height as u32, sn.burn_header_timestamp),
None => {
// shouldn't happen
panic!("CORRUPTION: staging block {}/{} does not correspond to a burn block", &next_staging_block.consensus_hash, &next_staging_block.anchored_block_hash);
@@ -3102,7 +3097,8 @@ impl StacksChainState {
&parent_block_header_info,
&next_staging_block.consensus_hash,
&burn_header_hash,
next_staging_block.burn_header_timestamp,
burn_header_height,
burn_header_timestamp,
&block,
&next_microblocks,
next_staging_block.commit_burn,
@@ -3637,9 +3633,9 @@ pub mod test {
assert!(StacksChainState::has_block_indexed(&chainstate.blocks_path, &index_block_hash).unwrap());
}
pub fn store_staging_block(chainstate: &mut StacksChainState, consensus_hash: &ConsensusHash, consensus_hash_timestamp: u64, block: &StacksBlock, parent_consensus_hash: &ConsensusHash, commit_burn: u64, sortition_burn: u64) {
pub fn store_staging_block(chainstate: &mut StacksChainState, consensus_hash: &ConsensusHash, block: &StacksBlock, parent_consensus_hash: &ConsensusHash, commit_burn: u64, sortition_burn: u64) {
let mut tx = chainstate.blocks_tx_begin().unwrap();
StacksChainState::store_staging_block(&mut tx, consensus_hash, consensus_hash_timestamp, block, parent_consensus_hash, commit_burn, sortition_burn).unwrap();
StacksChainState::store_staging_block(&mut tx, consensus_hash, block, parent_consensus_hash, commit_burn, sortition_burn).unwrap();
tx.commit().unwrap();
let index_block_hash = StacksBlockHeader::make_index_block_hash(consensus_hash, &block.block_hash());
@@ -3765,7 +3761,7 @@ pub mod test {
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, &ConsensusHash([2u8; 20]), &block.block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, &ConsensusHash([2u8; 20]), get_epoch_time_secs(), &block, &ConsensusHash([1u8; 20]), 1, 2);
store_staging_block(&mut chainstate, &ConsensusHash([2u8; 20]), &block, &ConsensusHash([1u8; 20]), 1, 2);
assert_block_staging_not_processed(&mut chainstate, &ConsensusHash([2u8; 20]), &block);
assert_block_not_stored(&mut chainstate, &ConsensusHash([2u8; 20]), &block);
@@ -3789,7 +3785,7 @@ pub mod test {
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, &ConsensusHash([2u8; 20]), &block.block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, &ConsensusHash([2u8; 20]), get_epoch_time_secs(), &block, &ConsensusHash([1u8; 20]), 1, 2);
store_staging_block(&mut chainstate, &ConsensusHash([2u8; 20]), &block, &ConsensusHash([1u8; 20]), 1, 2);
assert_block_staging_not_processed(&mut chainstate, &ConsensusHash([2u8; 20]), &block);
assert_block_not_stored(&mut chainstate, &ConsensusHash([2u8; 20]), &block);
@@ -3842,7 +3838,7 @@ pub mod test {
assert!(StacksChainState::load_staging_microblock(&chainstate.blocks_db, &ConsensusHash([2u8; 20]), &block.block_hash(), &microblocks[0].block_hash()).unwrap().is_none());
assert!(StacksChainState::load_staging_microblock_stream(&chainstate.blocks_db, &chainstate.blocks_path, &ConsensusHash([2u8; 20]), &block.block_hash(), u16::max_value()).unwrap().is_none());
store_staging_block(&mut chainstate, &ConsensusHash([2u8; 20]), get_epoch_time_secs(), &block, &ConsensusHash([1u8; 20]), 1, 2);
store_staging_block(&mut chainstate, &ConsensusHash([2u8; 20]), &block, &ConsensusHash([1u8; 20]), 1, 2);
for mb in microblocks.iter() {
store_staging_microblock(&mut chainstate, &ConsensusHash([2u8; 20]), &block.block_hash(), mb);
}
@@ -3894,7 +3890,7 @@ pub mod test {
assert!(StacksChainState::load_staging_microblock(&chainstate.blocks_db, &ConsensusHash([2u8; 20]), &block.block_hash(), &microblocks[0].block_hash()).unwrap().is_none());
assert!(StacksChainState::load_staging_microblock_stream(&chainstate.blocks_db, &chainstate.blocks_path, &ConsensusHash([2u8; 20]), &block.block_hash(), u16::max_value()).unwrap().is_none());
store_staging_block(&mut chainstate, &ConsensusHash([2u8; 20]), get_epoch_time_secs(), &block, &ConsensusHash([1u8; 20]), 1, 2);
store_staging_block(&mut chainstate, &ConsensusHash([2u8; 20]), &block, &ConsensusHash([1u8; 20]), 1, 2);
for mb in microblocks.iter() {
store_staging_microblock(&mut chainstate, &ConsensusHash([2u8; 20]), &block.block_hash(), mb);
}
@@ -4222,7 +4218,7 @@ pub mod test {
// store each block
for ((block, consensus_hash), parent_consensus_hash) in blocks.iter().zip(&consensus_hashes).zip(&parent_consensus_hashes) {
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, consensus_hash, &block.block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, consensus_hash, get_epoch_time_secs(), block, parent_consensus_hash, 1, 2);
store_staging_block(&mut chainstate, consensus_hash, block, parent_consensus_hash, 1, 2);
assert_block_staging_not_processed(&mut chainstate, consensus_hash, block);
}
@@ -4292,7 +4288,7 @@ pub mod test {
// store each block, in reverse order!
for ((block, consensus_hash), parent_consensus_hash) in blocks.iter().zip(&consensus_hashes).zip(&parent_consensus_hashes).rev() {
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, consensus_hash, &block.block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, consensus_hash, get_epoch_time_secs(), block, parent_consensus_hash, 1, 2);
store_staging_block(&mut chainstate, consensus_hash, block, parent_consensus_hash, 1, 2);
assert_block_staging_not_processed(&mut chainstate, consensus_hash, block);
}
@@ -4370,7 +4366,7 @@ pub mod test {
// store each block in reverse order, except for block_1
for ((block, consensus_hash), parent_consensus_hash) in blocks[1..].iter().zip(&consensus_hashes[1..]).zip(&parent_consensus_hashes[1..]).rev() {
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, consensus_hash, &block.block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, consensus_hash, get_epoch_time_secs(), block, parent_consensus_hash, 1, 2);
store_staging_block(&mut chainstate, consensus_hash, block, parent_consensus_hash, 1, 2);
assert_block_staging_not_processed(&mut chainstate, consensus_hash, block);
}
@@ -4384,7 +4380,7 @@ pub mod test {
// store block 1
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, &consensus_hashes[0], &block_1.block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, &consensus_hashes[0], get_epoch_time_secs(), &block_1, &parent_consensus_hashes[0], 1, 2);
store_staging_block(&mut chainstate, &consensus_hashes[0], &block_1, &parent_consensus_hashes[0], 1, 2);
assert_block_staging_not_processed(&mut chainstate, &consensus_hashes[0], &block_1);
// first block is attachable
@@ -4466,7 +4462,7 @@ pub mod test {
// store block 1 to staging
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, &consensus_hashes[0], &blocks[0].block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, &consensus_hashes[0], get_epoch_time_secs(), &blocks[0], &parent_consensus_hashes[0], 1, 2);
store_staging_block(&mut chainstate, &consensus_hashes[0], &blocks[0], &parent_consensus_hashes[0], 1, 2);
assert_block_staging_not_processed(&mut chainstate, &consensus_hashes[0], &blocks[0]);
set_block_processed(&mut chainstate, &consensus_hashes[0], &blocks[0].block_hash(), true);
@@ -4478,7 +4474,7 @@ pub mod test {
// this is what happens at the end of append_block()
// store block to staging and process it
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, &consensus_hashes[i], &blocks[i].block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, &consensus_hashes[i], get_epoch_time_secs(), &blocks[i], &parent_consensus_hashes[i], 1, 2);
store_staging_block(&mut chainstate, &consensus_hashes[i], &blocks[i], &parent_consensus_hashes[i], 1, 2);
assert_block_staging_not_processed(&mut chainstate, &consensus_hashes[i], &blocks[i]);
// set different parts of this stream as confirmed
@@ -4550,7 +4546,7 @@ pub mod test {
// store blocks to staging
for i in 0..blocks.len() {
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, &consensus_hashes[i], &blocks[i].block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, &consensus_hashes[i], get_epoch_time_secs(), &blocks[i], &parent_consensus_hashes[i], 1, 2);
store_staging_block(&mut chainstate, &consensus_hashes[i], &blocks[i], &parent_consensus_hashes[i], 1, 2);
assert_block_staging_not_processed(&mut chainstate, &consensus_hashes[i], &blocks[i]);
}
@@ -4615,7 +4611,7 @@ pub mod test {
// store block to staging
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, &consensus_hash, &block.block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, &consensus_hash, get_epoch_time_secs(), &block, &parent_consensus_hash, 1, 2);
store_staging_block(&mut chainstate, &consensus_hash, &block, &parent_consensus_hash, 1, 2);
assert_block_staging_not_processed(&mut chainstate, &consensus_hash, &block);
// drop microblocks
@@ -4676,7 +4672,7 @@ pub mod test {
}
// store block to staging
store_staging_block(&mut chainstate, &consensus_hash, get_epoch_time_secs(), &block, &parent_consensus_hash, 1, 2);
store_staging_block(&mut chainstate, &consensus_hash, &block, &parent_consensus_hash, 1, 2);
assert!(StacksChainState::has_block_indexed(&chainstate.blocks_path, &index_block_header).unwrap());
// accept it
@@ -4787,7 +4783,7 @@ pub mod test {
assert_eq!(stream, stream_2);
// store block to staging
store_staging_block(&mut chainstate, &consensus_hash, get_epoch_time_secs(), &block, &parent_consensus_hash, 1, 2);
store_staging_block(&mut chainstate, &consensus_hash, &block, &parent_consensus_hash, 1, 2);
// stream it back
let mut all_block_bytes = vec![];
@@ -4918,7 +4914,7 @@ pub mod test {
}
// store block to staging
store_staging_block(&mut chainstate, &consensus_hash, get_epoch_time_secs(), &block, &parent_consensus_hash, 1, 2);
store_staging_block(&mut chainstate, &consensus_hash, &block, &parent_consensus_hash, 1, 2);
// accept it
set_block_processed(&mut chainstate, &consensus_hash, &block.block_hash(), true);
@@ -5026,7 +5022,7 @@ pub mod test {
test_debug!("Store block {} to staging", i);
assert!(StacksChainState::load_staging_block_data(&chainstate.blocks_db, &chainstate.blocks_path, &consensus_hashes[i], &blocks[i].block_hash()).unwrap().is_none());
store_staging_block(&mut chainstate, &consensus_hashes[i], get_epoch_time_secs(), &blocks[i], &parent_consensus_hashes[i], 1, 2);
store_staging_block(&mut chainstate, &consensus_hashes[i], &blocks[i], &parent_consensus_hashes[i], 1, 2);
assert_block_staging_not_processed(&mut chainstate, &consensus_hashes[i], &blocks[i]);
// some anchored blocks are stored (to staging)

View File

@@ -123,6 +123,7 @@ impl StacksChainState {
let consensus_hash = &tip_info.consensus_hash;
let burn_header_hash = &tip_info.burn_header_hash;
let block_height = tip_info.block_height;
let burn_header_height = tip_info.burn_header_height;
let burn_header_timestamp = tip_info.burn_header_timestamp;
let total_work_str = format!("{}", header.total_work.work);
@@ -136,7 +137,8 @@ impl StacksChainState {
let args: &[&dyn ToSql] = &[
&header.version, &total_burn_str, &total_work_str, &header.proof, &header.parent_block, &header.parent_microblock, &header.parent_microblock_sequence,
&header.tx_merkle_root, &header.state_index_root, &header.microblock_pubkey_hash,
&block_hash, &index_block_hash, &consensus_hash, &burn_header_hash, &(burn_header_timestamp as i64), &(block_height as i64), &index_root];
&block_hash, &index_block_hash, &consensus_hash, &burn_header_hash, &(burn_header_height as i64),
&(burn_header_timestamp as i64), &(block_height as i64), &index_root];
tx.execute("INSERT INTO block_headers \
(version, \
@@ -153,10 +155,11 @@ impl StacksChainState {
index_block_hash, \
consensus_hash, \
burn_header_hash, \
burn_header_height, \
burn_header_timestamp, \
block_height, \
index_root) \
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17)", args)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18)", args)
.map_err(|e| Error::DBError(db_error::SqliteError(e)))?;
Ok(())

View File

@@ -161,6 +161,7 @@ pub struct StacksHeaderInfo {
pub index_root: TrieHash,
pub consensus_hash: ConsensusHash,
pub burn_header_hash: BurnchainHeaderHash,
pub burn_header_height: u32,
pub burn_header_timestamp: u64
}
@@ -190,6 +191,7 @@ impl StacksHeaderInfo {
block_height: 0,
index_root: root_hash,
burn_header_hash: FIRST_BURNCHAIN_BLOCK_HASH.clone(),
burn_header_height: FIRST_BURNCHAIN_BLOCK_HEIGHT,
consensus_hash: FIRST_BURNCHAIN_CONSENSUS_HASH.clone(),
burn_header_timestamp: FIRST_BURNCHAIN_BLOCK_TIMESTAMP
}
@@ -222,6 +224,7 @@ impl FromRow<StacksHeaderInfo> for StacksHeaderInfo {
let index_root = TrieHash::from_column(row, "index_root")?;
let consensus_hash = ConsensusHash::from_column(row, "consensus_hash")?;
let burn_header_hash = BurnchainHeaderHash::from_column(row, "burn_header_hash")?;
let burn_header_height = u64::from_column(row, "burn_header_height")? as u32;
let burn_header_timestamp = u64::from_column(row, "burn_header_timestamp")?;
let stacks_header = StacksBlockHeader::from_row(row)?;
@@ -236,6 +239,7 @@ impl FromRow<StacksHeaderInfo> for StacksHeaderInfo {
index_root: index_root,
consensus_hash: consensus_hash,
burn_header_hash: burn_header_hash,
burn_header_height: burn_header_height,
burn_header_timestamp: burn_header_timestamp
})
}
@@ -400,6 +404,7 @@ const STACKS_CHAIN_STATE_SQL : &'static [&'static str]= &[
index_root TEXT NOT NULL, -- root hash of the internal, not-consensus-critical MARF that allows us to track chainstate /fork metadata
consensus_hash TEXT UNIQUE NOT NULL, -- all consensus hashes are guaranteed to be unique
burn_header_hash TEXT NOT NULL, -- burn header hash corresponding to the consensus hash (NOT guaranteed to be unique, since we can have 2+ blocks per burn block if there's a PoX fork)
burn_header_height INT NOT NULL, -- height of the burnchain block header that generated this consensus hash
burn_header_timestamp INT NOT NULL, -- timestamp from burnchain block header that generated this consensus hash
PRIMARY KEY(consensus_hash,block_hash)
@@ -878,6 +883,8 @@ impl StacksChainState {
Ok((chainstate_tx, clarity_instance))
}
// NOTE: used for testing in the stacks testnet code.
// DO NOT CALL FROM PRODUCTION
pub fn clarity_eval_read_only(&mut self, parent_id_bhh: &StacksBlockId,
contract: &QualifiedContractIdentifier, code: &str) -> Value {
let result = self.clarity_state.eval_read_only(parent_id_bhh, &self.headers_db, contract, code);
@@ -1051,6 +1058,7 @@ impl StacksChainState {
new_tip: &StacksBlockHeader,
new_consensus_hash: &ConsensusHash,
new_burn_header_hash: &BurnchainHeaderHash,
new_burnchain_height: u32,
new_burnchain_timestamp: u64,
microblock_tail_opt: Option<StacksMicroblockHeader>,
block_reward: &MinerPaymentSchedule,
@@ -1090,6 +1098,7 @@ impl StacksChainState {
block_height: new_tip.total_work.work,
consensus_hash: new_consensus_hash.clone(),
burn_header_hash: new_burn_header_hash.clone(),
burn_header_height: new_burnchain_height,
burn_header_timestamp: new_burnchain_timestamp
};

View File

@@ -311,7 +311,7 @@ impl StacksBlockBuilder {
builder
}
fn first_pubkey_hash(miner_id: usize, genesis_consensus_hash: &ConsensusHash, genesis_burn_header_hash: &BurnchainHeaderHash, genesis_burn_header_timestamp: u64, proof: &VRFProof, pubkh: Hash160) -> StacksBlockBuilder {
fn first_pubkey_hash(miner_id: usize, genesis_consensus_hash: &ConsensusHash, genesis_burn_header_hash: &BurnchainHeaderHash, genesis_burn_header_height: u32, genesis_burn_header_timestamp: u64, proof: &VRFProof, pubkh: Hash160) -> StacksBlockBuilder {
let genesis_chain_tip = StacksHeaderInfo {
anchored_header: StacksBlockHeader::genesis_block_header(),
microblock_tail: None,
@@ -319,7 +319,8 @@ impl StacksBlockBuilder {
index_root: TrieHash([0u8; 32]),
consensus_hash: genesis_consensus_hash.clone(),
burn_header_hash: genesis_burn_header_hash.clone(),
burn_header_timestamp: genesis_burn_header_timestamp
burn_header_timestamp: genesis_burn_header_timestamp,
burn_header_height: genesis_burn_header_height,
};
let mut builder = StacksBlockBuilder::from_parent_pubkey_hash(miner_id, &genesis_chain_tip, &StacksWorkScore::initial(), proof, pubkh);
@@ -327,12 +328,12 @@ impl StacksBlockBuilder {
builder
}
pub fn first(miner_id: usize, genesis_consensus_hash: &ConsensusHash, genesis_burn_header_hash: &BurnchainHeaderHash, genesis_burn_header_timestamp: u64, proof: &VRFProof, microblock_privkey: &StacksPrivateKey) -> StacksBlockBuilder {
pub fn first(miner_id: usize, genesis_consensus_hash: &ConsensusHash, genesis_burn_header_hash: &BurnchainHeaderHash, genesis_burn_header_height: u32, genesis_burn_header_timestamp: u64, proof: &VRFProof, microblock_privkey: &StacksPrivateKey) -> StacksBlockBuilder {
let mut pubk = StacksPublicKey::from_private(microblock_privkey);
pubk.set_compressed(true);
let pubkh = Hash160::from_data(&pubk.to_bytes());
let mut builder = StacksBlockBuilder::first_pubkey_hash(miner_id, genesis_consensus_hash, genesis_burn_header_hash, genesis_burn_header_timestamp, proof, pubkh);
let mut builder = StacksBlockBuilder::first_pubkey_hash(miner_id, genesis_consensus_hash, genesis_burn_header_hash, genesis_burn_header_height, genesis_burn_header_timestamp, proof, pubkh);
builder.miner_privkey = microblock_privkey.clone();
builder
}
@@ -642,7 +643,7 @@ impl StacksBlockBuilder {
let builder =
if stacks_parent_header.consensus_hash == FIRST_BURNCHAIN_CONSENSUS_HASH {
StacksBlockBuilder::first_pubkey_hash(0, &FIRST_BURNCHAIN_CONSENSUS_HASH, &FIRST_BURNCHAIN_BLOCK_HASH, FIRST_BURNCHAIN_BLOCK_TIMESTAMP, &proof, pubkey_hash)
StacksBlockBuilder::first_pubkey_hash(0, &FIRST_BURNCHAIN_CONSENSUS_HASH, &FIRST_BURNCHAIN_BLOCK_HASH, FIRST_BURNCHAIN_BLOCK_HEIGHT, FIRST_BURNCHAIN_BLOCK_TIMESTAMP, &proof, pubkey_hash)
}
else {
// building off an existing stacks block
@@ -1258,7 +1259,13 @@ pub mod test {
let (builder, parent_block_snapshot_opt) = match parent_stacks_block {
None => {
// first stacks block
let builder = StacksBlockBuilder::first(miner.id, &burn_block.parent_snapshot.consensus_hash, &burn_block.parent_snapshot.burn_header_hash, burn_block.parent_snapshot.burn_header_timestamp, &proof, &miner.next_microblock_privkey());
let builder = StacksBlockBuilder::first(miner.id,
&burn_block.parent_snapshot.consensus_hash,
&burn_block.parent_snapshot.burn_header_hash,
burn_block.parent_snapshot.block_height as u32,
burn_block.parent_snapshot.burn_header_timestamp,
&proof,
&miner.next_microblock_privkey());
(builder, None)
},
Some(parent_stacks_block) => {
@@ -1325,7 +1332,7 @@ pub mod test {
// "discover" this stacks block
test_debug!("\n\nPreprocess Stacks block {}/{} ({})", &commit_snapshot.consensus_hash, &block_hash, StacksBlockHeader::make_index_block_hash(&commit_snapshot.consensus_hash, &block_hash));
let block_res = node.chainstate.preprocess_anchored_block(&ic, &commit_snapshot.consensus_hash, commit_snapshot.burn_header_timestamp, &stacks_block, &parent_block_consensus_hash).unwrap();
let block_res = node.chainstate.preprocess_anchored_block(&ic, &commit_snapshot.consensus_hash, &stacks_block, &parent_block_consensus_hash).unwrap();
// "discover" this stacks microblock stream
for mblock in stacks_microblocks.iter() {

View File

@@ -42,6 +42,7 @@ pub const NETWORK_P2P_PORT : u16 = 6265;
// first burnchain block hash
pub const FIRST_BURNCHAIN_CONSENSUS_HASH : ConsensusHash = ConsensusHash([0u8; 20]);
pub const FIRST_BURNCHAIN_BLOCK_HASH : BurnchainHeaderHash = BurnchainHeaderHash([0u8; 32]);
pub const FIRST_BURNCHAIN_BLOCK_HEIGHT : u32 = 0;
pub const FIRST_BURNCHAIN_BLOCK_TIMESTAMP : u64 = 0;
pub const FIRST_BURNCHAIN_BLOCK_HASH_TESTNET : BurnchainHeaderHash = BurnchainHeaderHash([1u8; 32]);

View File

@@ -2100,7 +2100,7 @@ pub mod test {
};
let ic = sortdb.index_conn();
node.chainstate.preprocess_anchored_block(&ic, &sn.consensus_hash, sn.burn_header_timestamp, block, &parent_sn.consensus_hash)
node.chainstate.preprocess_anchored_block(&ic, &sn.consensus_hash, block, &parent_sn.consensus_hash)
.map_err(|e| format!("Failed to preprocess anchored block: {:?}", &e))
};
self.sortdb = Some(sortdb);

View File

@@ -474,14 +474,6 @@ impl Relayer {
/// Insert a staging block
pub fn process_new_anchored_block(sort_ic: &SortitionDBConn, chainstate: &mut StacksChainState, consensus_hash: &ConsensusHash, block: &StacksBlock) -> Result<bool, chainstate_error> {
let sn = match SortitionDB::get_block_snapshot_consensus(sort_ic.conn, consensus_hash)? {
Some(sn) => sn,
None => {
debug!("Received unknown block {}/{}", consensus_hash, block.block_hash());
return Ok(false);
}
};
// find the snapshot of the parent of this block
let db_handle = SortitionHandleConn::open_reader_consensus(sort_ic, consensus_hash)?;
let parent_block_snapshot = match db_handle.get_block_snapshot_of_parent_stacks_block(consensus_hash, &block.block_hash())? {
@@ -492,7 +484,7 @@ impl Relayer {
}
};
chainstate.preprocess_anchored_block(sort_ic, consensus_hash, sn.burn_header_timestamp, block, &parent_block_snapshot.consensus_hash)
chainstate.preprocess_anchored_block(sort_ic, consensus_hash, block, &parent_block_snapshot.consensus_hash)
}
/// Coalesce a set of microblocks into relayer hints and MicroblocksData messages, as calculated by

View File

@@ -1606,7 +1606,7 @@ mod test {
let index_block_hash = StacksBlockHeader::make_index_block_hash(&peer_server_consensus_hash, &peer_server_block.block_hash());
test_debug!("Store peer server index block {:?}", &index_block_hash);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, get_epoch_time_secs(), &peer_server_block, &ConsensusHash([0x03; 20]), 456, 123);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, &peer_server_block, &ConsensusHash([0x03; 20]), 456, 123);
*server_block_cell.borrow_mut() = Some(peer_server_block);
@@ -1642,7 +1642,7 @@ mod test {
let index_block_hash = StacksBlockHeader::make_index_block_hash(&peer_server_consensus_hash, &peer_server_block.block_hash());
test_debug!("Store peer server index block {:?}", &index_block_hash);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, get_epoch_time_secs(), &peer_server_block, &ConsensusHash([0x03; 20]), 456, 123);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, &peer_server_block, &ConsensusHash([0x03; 20]), 456, 123);
set_block_processed(peer_server.chainstate(), &peer_server_consensus_hash, &peer_server_block.block_hash(), true);
*server_block_cell.borrow_mut() = Some(peer_server_block);

View File

@@ -729,7 +729,7 @@ mod test {
let index_block_hash = StacksBlockHeader::make_index_block_hash(&peer_server_consensus_hash, &peer_server_block.block_hash());
test_debug!("Store peer server index block {:?}", &index_block_hash);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, get_epoch_time_secs(), &peer_server_block, &ConsensusHash([client_id as u8; 20]), 456, 123);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, &peer_server_block, &ConsensusHash([client_id as u8; 20]), 456, 123);
let mut request = HttpRequestType::GetBlock(HttpRequestMetadata::from_host(PeerHost::from_host_port("127.0.0.1".to_string(), 51021)), index_block_hash);
request.metadata_mut().keep_alive = false;
@@ -764,7 +764,7 @@ mod test {
let index_block_hash = StacksBlockHeader::make_index_block_hash(&peer_server_consensus_hash, &peer_server_block.block_hash());
test_debug!("Store peer server index block {:?}", &index_block_hash);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, get_epoch_time_secs(), &peer_server_block, &ConsensusHash([client_id as u8; 20]), 456, 123);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, &peer_server_block, &ConsensusHash([client_id as u8; 20]), 456, 123);
let mut request = HttpRequestType::GetBlock(HttpRequestMetadata::from_host(PeerHost::from_host_port("127.0.0.1".to_string(), 51031)), index_block_hash);
request.metadata_mut().keep_alive = false;
@@ -965,7 +965,7 @@ mod test {
let index_block_hash = StacksBlockHeader::make_index_block_hash(&peer_server_consensus_hash, &peer_server_block.block_hash());
test_debug!("Store peer server index block {:?}", &index_block_hash);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, get_epoch_time_secs(), &peer_server_block, &ConsensusHash([client_id as u8; 20]), 456, 123);
store_staging_block(peer_server.chainstate(), &peer_server_consensus_hash, &peer_server_block, &ConsensusHash([client_id as u8; 20]), 456, 123);
let mut request = HttpRequestType::GetBlock(HttpRequestMetadata::from_host(PeerHost::from_host_port("127.0.0.1".to_string(), 51071)), index_block_hash);
request.metadata_mut().keep_alive = false;

View File

@@ -57,6 +57,7 @@ pub trait HeadersDB {
fn get_burn_header_hash_for_block(&self, id_bhh: &StacksBlockId) -> Option<BurnchainHeaderHash>;
fn get_vrf_seed_for_block(&self, id_bhh: &StacksBlockId) -> Option<VRFSeed>;
fn get_burn_block_time_for_block(&self, id_bhh: &StacksBlockId) -> Option<u64>;
fn get_burn_block_height_for_block(&self, id_bhh: &StacksBlockId) -> Option<u32>;
fn get_miner_address(&self, id_bhh: &StacksBlockId) -> Option<StacksAddress>;
}
@@ -92,6 +93,11 @@ impl HeadersDB for DBConn {
.map(|x| x.burn_header_timestamp)
}
fn get_burn_block_height_for_block(&self, id_bhh: &StacksBlockId) -> Option<u32> {
get_stacks_header_info(self, id_bhh)
.map(|x| x.burn_header_height)
}
fn get_vrf_seed_for_block(&self, id_bhh: &StacksBlockId) -> Option<VRFSeed> {
get_stacks_header_info(self, id_bhh)
.map(|x| VRFSeed::from_proof(&x.anchored_header.proof))
@@ -116,6 +122,9 @@ impl HeadersDB for &dyn HeadersDB {
fn get_burn_block_time_for_block(&self, bhh: &StacksBlockId) -> Option<u64> {
(*self).get_burn_block_time_for_block(bhh)
}
fn get_burn_block_height_for_block(&self, bhh: &StacksBlockId) -> Option<u32> {
(*self).get_burn_block_height_for_block(bhh)
}
fn get_miner_address(&self, bhh: &StacksBlockId) -> Option<StacksAddress> {
(*self).get_miner_address(bhh)
}
@@ -138,6 +147,9 @@ impl HeadersDB for NullHeadersDB {
fn get_burn_block_time_for_block(&self, _id_bhh: &StacksBlockId) -> Option<u64> {
None
}
fn get_burn_block_height_for_block(&self, _id_bhh: &StacksBlockId) -> Option<u32> {
None
}
fn get_miner_address(&self, _id_bhh: &StacksBlockId) -> Option<StacksAddress> {
None
}
@@ -297,6 +309,13 @@ impl <'a> ClarityDatabase <'a> {
self.store.get_current_block_height()
}
pub fn get_current_burnchain_block_height(&mut self) -> u32 {
let cur_stacks_height = self.store.get_current_block_height();
let cur_id_bhh = self.get_index_block_header_hash(cur_stacks_height);
self.get_burnchain_block_height(&cur_id_bhh)
.expect("Block header hash must return for provided burn block height")
}
pub fn get_block_header_hash(&mut self, block_height: u32) -> BlockHeaderHash {
let id_bhh = self.get_index_block_header_hash(block_height);
self.headers_db.get_stacks_block_header_hash_for_block(&id_bhh)
@@ -314,6 +333,10 @@ impl <'a> ClarityDatabase <'a> {
self.headers_db.get_burn_header_hash_for_block(&id_bhh)
.expect("Failed to get block data.")
}
pub fn get_burnchain_block_height(&mut self, id_bhh: &StacksBlockId) -> Option<u32> {
self.headers_db.get_burn_block_height_for_block(id_bhh)
}
pub fn get_block_vrf_seed(&mut self, block_height: u32) -> VRFSeed {
let id_bhh = self.get_index_block_header_hash(block_height);

View File

@@ -55,10 +55,17 @@ struct DefineAPI {
const BLOCK_HEIGHT: KeywordAPI = KeywordAPI {
name: "block-height",
output_type: "uint",
description: "Returns the current block height of the Stacks blockchain as an int",
description: "Returns the current block height of the Stacks blockchain as an uint",
example: "(> block-height 1000) ;; returns true if the current block-height has passed 1000 blocks."
};
const BURN_BLOCK_HEIGHT: KeywordAPI = KeywordAPI {
name: "burn-block-height",
output_type: "uint",
description: "Returns the current block height of the underlying burn blockchain as a uint",
example: "(> burn-block-height 1000) ;; returns true if the current height of the underlying burn blockchain has passed 1000 blocks."
};
const CONTRACT_CALLER_KEYWORD: KeywordAPI = KeywordAPI {
name: "contract-caller",
output_type: "principal",
@@ -1392,7 +1399,7 @@ fn make_keyword_reference(variable: &NativeVariables) -> Option<KeywordAPI> {
NativeVariables::NativeTrue => Some(TRUE_KEYWORD.clone()),
NativeVariables::NativeFalse => Some(FALSE_KEYWORD.clone()),
NativeVariables::BlockHeight => Some(BLOCK_HEIGHT.clone()),
NativeVariables::BurnBlockHeight => None,
NativeVariables::BurnBlockHeight => Some(BURN_BLOCK_HEIGHT.clone()),
}
}
@@ -1490,6 +1497,9 @@ mod test {
fn get_burn_block_time_for_block(&self, _id_bhh: &StacksBlockId) -> Option<u64> {
Some(1557860301)
}
fn get_burn_block_height_for_block(&self, _id_bhh: &StacksBlockId) -> Option<u32> {
Some(567890)
}
fn get_miner_address(&self, _id_bhh: &StacksBlockId) -> Option<StacksAddress> {
None
}

View File

@@ -31,7 +31,8 @@ pub fn lookup_reserved_variable(name: &str, _context: &LocalContext, env: &mut E
Ok(Some(Value::UInt(block_height as u128)))
},
NativeVariables::BurnBlockHeight => {
Err(RuntimeErrorType::NotImplemented.into())
let burn_block_height = env.global_context.database.get_current_burnchain_block_height();
Ok(Some(Value::UInt(burn_block_height as u128)))
},
NativeVariables::NativeNone => {
Ok(Some(Value::none()))

View File

@@ -29,7 +29,6 @@ use stacks::chainstate::stacks::StacksPublicKey;
use stacks::core::mempool::MemPoolDB;
use stacks::util::vrf::VRFPublicKey;
use stacks::util::get_epoch_time_secs;
use stacks::util::strings::UrlString;
use stacks::util::hash::{
Hash160, Sha256Sum, to_hex
@@ -123,7 +122,6 @@ fn inner_process_tenure(
chain_state.preprocess_anchored_block(
&ic,
consensus_hash,
get_epoch_time_secs(),
&anchored_block,
&parent_consensus_hash)?;
}

View File

@@ -27,7 +27,6 @@ use stacks::net::{
};
use stacks::util::vrf::VRFPublicKey;
use stacks::util::get_epoch_time_secs;
use stacks::util::strings::UrlString;
use stacks::util::hash::Sha256Sum;
use stacks::util::secp256k1::Secp256k1PrivateKey;
@@ -488,7 +487,6 @@ impl Node {
self.chain_state.preprocess_anchored_block(
&ic,
consensus_hash,
get_epoch_time_secs(),
&anchored_block,
&parent_consensus_hash).unwrap();

View File

@@ -43,6 +43,7 @@ const GET_INFO_CONTRACT: &'static str = "
(define-private (test-8) (get-block-info? miner-address u1))
(define-private (test-9) (get-block-info? miner-address block-height))
(define-private (test-10) (get-block-info? miner-address u100000))
(define-private (test-11) burn-block-height)
(define-private (get-block-id-hash (height uint)) (unwrap-panic
(get id-hash (map-get? block-data ((height height))))))
@@ -258,6 +259,13 @@ fn integration_test_get_info() {
chain_state.clarity_eval_read_only(
bhh, &contract_identifier, "(test-10)"),
Value::none());
// verify we can read the burn block height (should be 3, since we sent the
// contract at block 2)
assert_eq!(
chain_state.clarity_eval_read_only(
bhh, &contract_identifier, "(test-11)"),
Value::UInt(3));
},
3 => {