mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-06-12 23:58:55 +08:00
Merge branch 'develop' into fix/2444-rbf-fallbacks
This commit is contained in:
@@ -19,6 +19,8 @@ incompatible, however.
|
||||
transaction. Second, fix the "same chainstate hash" fallback check.
|
||||
- Winning block txid lookups in the SortitionDB have been corrected
|
||||
to use the txid during the lookup.
|
||||
- The miner will no longer attempt to mine a new Stacks block if it receives a
|
||||
microblock in a discontinuous microblock stream.
|
||||
|
||||
## [2.0.5] - 2021-02-12
|
||||
|
||||
|
||||
@@ -1356,6 +1356,7 @@ impl StacksChainState {
|
||||
let mut ret = vec![];
|
||||
let mut tip: Option<StacksMicroblock> = None;
|
||||
let mut fork_poison = None;
|
||||
let mut expected_sequence = start_seq;
|
||||
|
||||
// load associated staging microblock data, but best-effort.
|
||||
// Stop loading once we find a fork juncture.
|
||||
@@ -1384,6 +1385,18 @@ impl StacksChainState {
|
||||
}
|
||||
};
|
||||
|
||||
if mblock.header.sequence > expected_sequence {
|
||||
warn!(
|
||||
"Discontinuous microblock stream: expected seq {}, got {}",
|
||||
expected_sequence, mblock.header.sequence
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// expect forks, so expected_sequence may not always increase
|
||||
expected_sequence =
|
||||
cmp::min(mblock.header.sequence, expected_sequence).saturating_add(1);
|
||||
|
||||
if let Some(tip_mblock) = tip {
|
||||
if mblock.header.sequence == tip_mblock.header.sequence {
|
||||
debug!(
|
||||
@@ -6912,6 +6925,133 @@ pub mod test {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stacks_db_staging_microblock_stream_load_continuous_streams() {
|
||||
let mut chainstate = instantiate_chainstate(
|
||||
false,
|
||||
0x80000000,
|
||||
"stacks_db_staging_microblock_stream_load_continuous_streams",
|
||||
);
|
||||
let privk = StacksPrivateKey::from_hex(
|
||||
"eb05c83546fdd2c79f10f5ad5434a90dd28f7e3acb7c092157aa1bc3656b012c01",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let block = make_empty_coinbase_block(&privk);
|
||||
let microblocks = make_sample_microblock_stream(&privk, &block.block_hash());
|
||||
let mut child_block = make_empty_coinbase_block(&privk);
|
||||
|
||||
child_block.header.parent_block = block.block_hash();
|
||||
child_block.header.parent_microblock = microblocks.first().as_ref().unwrap().block_hash();
|
||||
child_block.header.parent_microblock_sequence =
|
||||
microblocks.first().as_ref().unwrap().header.sequence;
|
||||
|
||||
assert!(StacksChainState::load_staging_microblock(
|
||||
&chainstate.db(),
|
||||
&ConsensusHash([2u8; 20]),
|
||||
&block.block_hash(),
|
||||
µblocks[0].block_hash()
|
||||
)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
assert!(StacksChainState::load_descendant_staging_microblock_stream(
|
||||
&chainstate.db(),
|
||||
&StacksBlockHeader::make_index_block_hash(
|
||||
&ConsensusHash([2u8; 20]),
|
||||
&block.block_hash()
|
||||
),
|
||||
0,
|
||||
u16::max_value()
|
||||
)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
|
||||
store_staging_block(
|
||||
&mut chainstate,
|
||||
&ConsensusHash([2u8; 20]),
|
||||
&block,
|
||||
&ConsensusHash([1u8; 20]),
|
||||
1,
|
||||
2,
|
||||
);
|
||||
|
||||
// don't store the first microblock, but store the rest
|
||||
for (i, mb) in microblocks.iter().enumerate() {
|
||||
if i > 0 {
|
||||
store_staging_microblock(
|
||||
&mut chainstate,
|
||||
&ConsensusHash([2u8; 20]),
|
||||
&block.block_hash(),
|
||||
mb,
|
||||
);
|
||||
}
|
||||
}
|
||||
store_staging_block(
|
||||
&mut chainstate,
|
||||
&ConsensusHash([3u8; 20]),
|
||||
&child_block,
|
||||
&ConsensusHash([2u8; 20]),
|
||||
1,
|
||||
2,
|
||||
);
|
||||
|
||||
// block should be stored to staging
|
||||
assert_block_staging_not_processed(&mut chainstate, &ConsensusHash([2u8; 20]), &block);
|
||||
assert_block_staging_not_processed(
|
||||
&mut chainstate,
|
||||
&ConsensusHash([3u8; 20]),
|
||||
&child_block,
|
||||
);
|
||||
assert_block_not_stored(&mut chainstate, &ConsensusHash([2u8; 20]), &block);
|
||||
assert_block_not_stored(&mut chainstate, &ConsensusHash([3u8; 20]), &child_block);
|
||||
|
||||
// missing head
|
||||
assert!(StacksChainState::load_staging_microblock(
|
||||
&chainstate.db(),
|
||||
&ConsensusHash([2u8; 20]),
|
||||
&block.block_hash(),
|
||||
µblocks[0].block_hash()
|
||||
)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
|
||||
// subsequent microblock stream should be stored to staging
|
||||
assert!(StacksChainState::load_staging_microblock(
|
||||
&chainstate.db(),
|
||||
&ConsensusHash([2u8; 20]),
|
||||
&block.block_hash(),
|
||||
µblocks[1].block_hash()
|
||||
)
|
||||
.unwrap()
|
||||
.is_some());
|
||||
assert_eq!(
|
||||
StacksChainState::load_staging_microblock(
|
||||
&chainstate.db(),
|
||||
&ConsensusHash([2u8; 20]),
|
||||
&block.block_hash(),
|
||||
µblocks[1].block_hash()
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.try_into_microblock()
|
||||
.unwrap(),
|
||||
microblocks[1]
|
||||
);
|
||||
|
||||
// can't load descendent stream because missing head
|
||||
assert!(StacksChainState::load_descendant_staging_microblock_stream(
|
||||
&chainstate.db(),
|
||||
&StacksBlockHeader::make_index_block_hash(
|
||||
&ConsensusHash([2u8; 20]),
|
||||
&block.block_hash()
|
||||
),
|
||||
0,
|
||||
u16::max_value()
|
||||
)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stacks_db_validate_parent_microblock_stream() {
|
||||
let privk = StacksPrivateKey::from_hex(
|
||||
|
||||
Reference in New Issue
Block a user