mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-05-24 08:09:52 +08:00
Merge pull request #3370 from stacks-network/feat/3346
Feat/3346: epoch marker for LeaderBlockCommitOp
This commit is contained in:
1
.github/workflows/bitcoin-tests.yml
vendored
1
.github/workflows/bitcoin-tests.yml
vendored
@@ -86,6 +86,7 @@ jobs:
|
||||
- tests::epoch_21::transition_adds_pay_to_contract
|
||||
- tests::epoch_21::transition_adds_get_pox_addr_recipients
|
||||
- tests::epoch_21::transition_removes_pox_sunset
|
||||
- tests::epoch_21::transition_empty_blocks
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download docker image
|
||||
|
||||
@@ -1074,6 +1074,9 @@ pub mod test {
|
||||
if epoch.epoch_id >= StacksEpochId::Epoch2_05 {
|
||||
txop.memo = vec![STACKS_EPOCH_2_05_MARKER];
|
||||
}
|
||||
if epoch.epoch_id >= StacksEpochId::Epoch21 {
|
||||
txop.memo = vec![STACKS_EPOCH_2_1_MARKER];
|
||||
}
|
||||
|
||||
self.txs
|
||||
.push(BlockstackOperationType::LeaderBlockCommit(txop.clone()));
|
||||
|
||||
@@ -658,6 +658,56 @@ impl LeaderBlockCommitOp {
|
||||
self.check_single_burn_output()
|
||||
}
|
||||
|
||||
/// Check the epoch marker in a block-commit to make sure it matches the right epoch.
|
||||
/// Valid in Stacks 2.05+
|
||||
fn check_epoch_commit_marker(&self, marker: u8) -> Result<(), op_error> {
|
||||
if self.memo.len() < 1 {
|
||||
debug!(
|
||||
"Invalid block commit";
|
||||
"reason" => "no epoch marker byte given",
|
||||
);
|
||||
return Err(op_error::BlockCommitBadEpoch);
|
||||
}
|
||||
if self.memo[0] < marker {
|
||||
debug!(
|
||||
"Invalid block commit";
|
||||
"reason" => "invalid epoch marker byte",
|
||||
"marker_byte" => self.memo[0],
|
||||
"expected_marker_byte" => marker,
|
||||
);
|
||||
return Err(op_error::BlockCommitBadEpoch);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check the epoch marker in the block commit, given the epoch we're in
|
||||
fn check_epoch_commit(&self, epoch_id: StacksEpochId) -> Result<(), op_error> {
|
||||
match epoch_id {
|
||||
StacksEpochId::Epoch10 => {
|
||||
panic!("FATAL: processed block-commit pre-Stacks 2.0");
|
||||
}
|
||||
StacksEpochId::Epoch20 => {
|
||||
// no-op, but log for helping node operators watch for old nodes
|
||||
if self.memo.len() < 1 {
|
||||
debug!(
|
||||
"Soon-to-be-invalid block commit";
|
||||
"reason" => "no epoch marker byte given",
|
||||
);
|
||||
} else if self.memo[0] < STACKS_EPOCH_2_05_MARKER {
|
||||
debug!(
|
||||
"Soon-to-be-invalid block commit";
|
||||
"reason" => "invalid epoch marker byte",
|
||||
"marker_byte" => self.memo[0],
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
StacksEpochId::Epoch2_05 => self.check_epoch_commit_marker(STACKS_EPOCH_2_05_MARKER),
|
||||
StacksEpochId::Epoch21 => self.check_epoch_commit_marker(STACKS_EPOCH_2_1_MARKER),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check(
|
||||
&self,
|
||||
burnchain: &Burnchain,
|
||||
@@ -860,46 +910,7 @@ impl LeaderBlockCommitOp {
|
||||
self.block_height
|
||||
));
|
||||
|
||||
match epoch.epoch_id {
|
||||
StacksEpochId::Epoch10 => {
|
||||
panic!("FATAL: processed block-commit pre-Stacks 2.0");
|
||||
}
|
||||
StacksEpochId::Epoch20 => {
|
||||
// no-op, but log for helping node operators watch for old nodes
|
||||
if self.memo.len() < 1 {
|
||||
debug!(
|
||||
"Soon-to-be-invalid block commit";
|
||||
"reason" => "no epoch marker byte given",
|
||||
);
|
||||
} else if self.memo[0] < STACKS_EPOCH_2_05_MARKER {
|
||||
debug!(
|
||||
"Soon-to-be-invalid block commit";
|
||||
"reason" => "invalid epoch marker byte",
|
||||
"marker_byte" => self.memo[0],
|
||||
"expected_marker_byte" => STACKS_EPOCH_2_05_MARKER
|
||||
);
|
||||
}
|
||||
}
|
||||
// Note: 2.05 and 2.1 share the same marker.
|
||||
StacksEpochId::Epoch2_05 | StacksEpochId::Epoch21 => {
|
||||
if self.memo.len() < 1 {
|
||||
debug!(
|
||||
"Invalid block commit";
|
||||
"reason" => "no epoch marker byte given",
|
||||
);
|
||||
return Err(op_error::BlockCommitBadEpoch);
|
||||
}
|
||||
if self.memo[0] < STACKS_EPOCH_2_05_MARKER {
|
||||
debug!(
|
||||
"Invalid block commit";
|
||||
"reason" => "invalid epoch marker byte",
|
||||
"marker_byte" => self.memo[0],
|
||||
"expected_marker_byte" => STACKS_EPOCH_2_05_MARKER
|
||||
);
|
||||
return Err(op_error::BlockCommitBadEpoch);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.check_epoch_commit(epoch.epoch_id)?;
|
||||
|
||||
// good to go!
|
||||
Ok(())
|
||||
@@ -924,7 +935,7 @@ mod tests {
|
||||
use crate::chainstate::stacks::StacksPublicKey;
|
||||
use crate::core::{
|
||||
StacksEpoch, StacksEpochId, PEER_VERSION_EPOCH_1_0, PEER_VERSION_EPOCH_2_0,
|
||||
PEER_VERSION_EPOCH_2_05, STACKS_EPOCH_MAX,
|
||||
PEER_VERSION_EPOCH_2_05, PEER_VERSION_EPOCH_2_1, STACKS_EPOCH_MAX,
|
||||
};
|
||||
use stacks_common::address::AddressHashMode;
|
||||
use stacks_common::deps_common::bitcoin::blockdata::transaction::Transaction;
|
||||
@@ -2900,7 +2911,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_epoch_marker_2_05() {
|
||||
fn test_epoch_marker() {
|
||||
let first_block_height = 121;
|
||||
let first_burn_hash = BurnchainHeaderHash::from_hex(
|
||||
"0000000000000000000000000000000000000000000000000000000000000001",
|
||||
@@ -2923,6 +2934,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let epoch_2_05_start = 125;
|
||||
let epoch_2_1_start = 130;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut buf = [0u8; 32];
|
||||
@@ -2955,10 +2967,17 @@ mod tests {
|
||||
StacksEpoch {
|
||||
epoch_id: StacksEpochId::Epoch2_05,
|
||||
start_height: epoch_2_05_start,
|
||||
end_height: STACKS_EPOCH_MAX,
|
||||
end_height: epoch_2_1_start,
|
||||
block_limit: ExecutionCost::max_value(),
|
||||
network_epoch: PEER_VERSION_EPOCH_2_05,
|
||||
},
|
||||
StacksEpoch {
|
||||
epoch_id: StacksEpochId::Epoch21,
|
||||
start_height: epoch_2_1_start,
|
||||
end_height: STACKS_EPOCH_MAX,
|
||||
block_limit: ExecutionCost::max_value(),
|
||||
network_epoch: PEER_VERSION_EPOCH_2_1,
|
||||
},
|
||||
],
|
||||
PoxConstants::test_default(),
|
||||
true,
|
||||
@@ -3126,6 +3145,122 @@ mod tests {
|
||||
burn_header_hash: BurnchainHeaderHash([0x00; 32]), // to be filled in
|
||||
};
|
||||
|
||||
let block_commit_post_2_1_valid = LeaderBlockCommitOp {
|
||||
sunset_burn: 0,
|
||||
block_header_hash: BlockHeaderHash([0x03; 32]),
|
||||
new_seed: VRFSeed([0x04; 32]),
|
||||
parent_block_ptr: 0,
|
||||
parent_vtxindex: 0,
|
||||
key_block_ptr: leader_key.block_height as u32,
|
||||
key_vtxindex: leader_key.vtxindex as u16,
|
||||
memo: vec![STACKS_EPOCH_2_1_MARKER],
|
||||
commit_outs: vec![],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: (Txid([0; 32]), 0),
|
||||
apparent_sender: BurnchainSigner {
|
||||
public_keys: vec![StacksPublicKey::from_hex(
|
||||
"024d8cdaef508d665dd9dd50ca7e9fbd9e7984ec8bfac8f02dea9f02a9232af1d7",
|
||||
)
|
||||
.unwrap()],
|
||||
num_sigs: 1,
|
||||
hash_mode: AddressHashMode::SerializeP2PKH,
|
||||
},
|
||||
|
||||
txid: Txid([0x03; 32]),
|
||||
vtxindex: 444,
|
||||
block_height: epoch_2_1_start,
|
||||
burn_parent_modulus: ((epoch_2_1_start - 1) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
|
||||
burn_header_hash: BurnchainHeaderHash([0x00; 32]), // to be filled in
|
||||
};
|
||||
|
||||
let block_commit_post_2_1_valid_bigger_epoch = LeaderBlockCommitOp {
|
||||
sunset_burn: 0,
|
||||
block_header_hash: BlockHeaderHash([0x03; 32]),
|
||||
new_seed: VRFSeed([0x04; 32]),
|
||||
parent_block_ptr: 0,
|
||||
parent_vtxindex: 0,
|
||||
key_block_ptr: leader_key.block_height as u32,
|
||||
key_vtxindex: leader_key.vtxindex as u16,
|
||||
memo: vec![STACKS_EPOCH_2_1_MARKER + 1],
|
||||
commit_outs: vec![],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: (Txid([0; 32]), 0),
|
||||
apparent_sender: BurnchainSigner {
|
||||
public_keys: vec![StacksPublicKey::from_hex(
|
||||
"024d8cdaef508d665dd9dd50ca7e9fbd9e7984ec8bfac8f02dea9f02a9232af1d7",
|
||||
)
|
||||
.unwrap()],
|
||||
num_sigs: 1,
|
||||
hash_mode: AddressHashMode::SerializeP2PKH,
|
||||
},
|
||||
|
||||
txid: Txid([0x13; 32]),
|
||||
vtxindex: 444,
|
||||
block_height: epoch_2_1_start,
|
||||
burn_parent_modulus: ((epoch_2_1_start - 1) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
|
||||
burn_header_hash: BurnchainHeaderHash([0x00; 32]), // to be filled in
|
||||
};
|
||||
|
||||
let block_commit_post_2_1_invalid_bad_memo = LeaderBlockCommitOp {
|
||||
sunset_burn: 0,
|
||||
block_header_hash: BlockHeaderHash([0x04; 32]),
|
||||
new_seed: VRFSeed([0x05; 32]),
|
||||
parent_block_ptr: 0,
|
||||
parent_vtxindex: 0,
|
||||
key_block_ptr: leader_key.block_height as u32,
|
||||
key_vtxindex: leader_key.vtxindex as u16,
|
||||
memo: vec![STACKS_EPOCH_2_1_MARKER - 1],
|
||||
commit_outs: vec![],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: (Txid([0; 32]), 0),
|
||||
apparent_sender: BurnchainSigner {
|
||||
public_keys: vec![StacksPublicKey::from_hex(
|
||||
"02b20f7d690afa0464d7eb17bdd86820261fb1acfdf489b2442a205a693da231ac",
|
||||
)
|
||||
.unwrap()],
|
||||
num_sigs: 1,
|
||||
hash_mode: AddressHashMode::SerializeP2PKH,
|
||||
},
|
||||
|
||||
txid: Txid([0x04; 32]),
|
||||
vtxindex: 445,
|
||||
block_height: epoch_2_1_start,
|
||||
burn_parent_modulus: ((epoch_2_1_start - 1) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
|
||||
burn_header_hash: BurnchainHeaderHash([0x00; 32]), // to be filled in
|
||||
};
|
||||
|
||||
let block_commit_post_2_1_invalid_no_memo = LeaderBlockCommitOp {
|
||||
sunset_burn: 0,
|
||||
block_header_hash: BlockHeaderHash([0x05; 32]),
|
||||
new_seed: VRFSeed([0x06; 32]),
|
||||
parent_block_ptr: 0,
|
||||
parent_vtxindex: 0,
|
||||
key_block_ptr: leader_key.block_height as u32,
|
||||
key_vtxindex: leader_key.vtxindex as u16,
|
||||
memo: vec![],
|
||||
commit_outs: vec![],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: (Txid([0; 32]), 0),
|
||||
apparent_sender: BurnchainSigner {
|
||||
public_keys: vec![StacksPublicKey::from_hex(
|
||||
"02e371309f1c25abc5f00353d74632c6f5b95eb80e1e1edb9ba53e14b0d47bc0de",
|
||||
)
|
||||
.unwrap()],
|
||||
num_sigs: 1,
|
||||
hash_mode: AddressHashMode::SerializeP2PKH,
|
||||
},
|
||||
|
||||
txid: Txid([0x05; 32]),
|
||||
vtxindex: 446,
|
||||
block_height: epoch_2_1_start,
|
||||
burn_parent_modulus: ((epoch_2_1_start - 1) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
|
||||
burn_header_hash: BurnchainHeaderHash([0x00; 32]), // to be filled in
|
||||
};
|
||||
|
||||
let all_leader_key_ops = vec![leader_key];
|
||||
|
||||
let all_block_commit_ops = vec![
|
||||
@@ -3134,10 +3269,14 @@ mod tests {
|
||||
(block_commit_post_2_05_valid_bigger_epoch, true),
|
||||
(block_commit_post_2_05_invalid_bad_memo, false),
|
||||
(block_commit_post_2_05_invalid_no_memo, false),
|
||||
(block_commit_post_2_1_valid, true),
|
||||
(block_commit_post_2_1_valid_bigger_epoch, true),
|
||||
(block_commit_post_2_1_invalid_bad_memo, false),
|
||||
(block_commit_post_2_1_invalid_no_memo, false),
|
||||
];
|
||||
|
||||
let mut sn = SortitionDB::get_first_block_snapshot(db.conn()).unwrap();
|
||||
for i in sn.block_height..(epoch_2_05_start + 2) {
|
||||
for i in sn.block_height..(epoch_2_1_start + 2) {
|
||||
eprintln!("Block {}", i);
|
||||
let mut byte_pattern = [0u8; 32];
|
||||
byte_pattern[24..32].copy_from_slice(&i.to_be_bytes());
|
||||
|
||||
@@ -569,7 +569,7 @@ fn make_genesis_block_with_recipients(
|
||||
},
|
||||
key_block_ptr: 1, // all registers happen in block height 1
|
||||
key_vtxindex: (1 + key_index) as u16,
|
||||
memo: vec![STACKS_EPOCH_2_05_MARKER],
|
||||
memo: vec![STACKS_EPOCH_2_1_MARKER],
|
||||
new_seed: VRFSeed::from_proof(&proof),
|
||||
commit_outs,
|
||||
|
||||
@@ -791,7 +791,7 @@ fn make_stacks_block_with_input(
|
||||
},
|
||||
key_block_ptr: 1, // all registers happen in block height 1
|
||||
key_vtxindex: (1 + key_index) as u16,
|
||||
memo: vec![STACKS_EPOCH_2_05_MARKER],
|
||||
memo: vec![STACKS_EPOCH_2_1_MARKER],
|
||||
new_seed: VRFSeed::from_proof(&proof),
|
||||
commit_outs,
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ use stacks::chainstate::stacks::{
|
||||
use stacks::codec::StacksMessageCodec;
|
||||
use stacks::core::mempool::MemPoolDB;
|
||||
use stacks::core::FIRST_BURNCHAIN_CONSENSUS_HASH;
|
||||
use stacks::core::STACKS_EPOCH_2_05_MARKER;
|
||||
use stacks::core::STACKS_EPOCH_2_1_MARKER;
|
||||
use stacks::cost_estimates::metrics::CostMetric;
|
||||
use stacks::cost_estimates::metrics::UnitMetric;
|
||||
use stacks::cost_estimates::UnitEstimator;
|
||||
@@ -1285,7 +1285,7 @@ impl BlockMinerThread {
|
||||
apparent_sender: sender,
|
||||
key_block_ptr: key.block_height as u32,
|
||||
key_vtxindex: key.op_vtxindex as u16,
|
||||
memo: vec![STACKS_EPOCH_2_05_MARKER],
|
||||
memo: vec![STACKS_EPOCH_2_1_MARKER],
|
||||
new_seed: vrf_seed,
|
||||
parent_block_ptr,
|
||||
parent_vtxindex,
|
||||
|
||||
@@ -18,7 +18,7 @@ use stacks::chainstate::stacks::{
|
||||
};
|
||||
use stacks::chainstate::{burn::db::sortdb::SortitionDB, stacks::db::StacksEpochReceipt};
|
||||
use stacks::core::mempool::MemPoolDB;
|
||||
use stacks::core::STACKS_EPOCH_2_05_MARKER;
|
||||
use stacks::core::STACKS_EPOCH_2_1_MARKER;
|
||||
use stacks::cost_estimates::metrics::UnitMetric;
|
||||
use stacks::cost_estimates::UnitEstimator;
|
||||
use stacks::net::atlas::AttachmentInstance;
|
||||
@@ -1030,7 +1030,7 @@ impl Node {
|
||||
apparent_sender: self.keychain.get_burnchain_signer(),
|
||||
key_block_ptr: key.block_height as u32,
|
||||
key_vtxindex: key.op_vtxindex as u16,
|
||||
memo: vec![STACKS_EPOCH_2_05_MARKER],
|
||||
memo: vec![STACKS_EPOCH_2_1_MARKER],
|
||||
new_seed: vrf_seed,
|
||||
parent_block_ptr,
|
||||
parent_vtxindex,
|
||||
|
||||
@@ -23,8 +23,10 @@ use stacks::core;
|
||||
|
||||
use stacks::chainstate::burn::db::sortdb::SortitionDB;
|
||||
use stacks::chainstate::burn::distribution::BurnSamplePoint;
|
||||
use stacks::chainstate::burn::operations::leader_block_commit::BURN_BLOCK_MINED_AT_MODULUS;
|
||||
use stacks::chainstate::burn::operations::leader_block_commit::OUTPUTS_PER_COMMIT;
|
||||
use stacks::chainstate::burn::operations::BlockstackOperationType;
|
||||
use stacks::chainstate::burn::operations::LeaderBlockCommitOp;
|
||||
use stacks::chainstate::burn::operations::PreStxOp;
|
||||
use stacks::chainstate::burn::operations::TransferStxOp;
|
||||
|
||||
@@ -39,7 +41,9 @@ use crate::stacks_common::address::AddressHashMode;
|
||||
use crate::stacks_common::types::Address;
|
||||
use crate::stacks_common::util::hash::{bytes_to_hex, hex_bytes};
|
||||
|
||||
use stacks_common::types::chainstate::BlockHeaderHash;
|
||||
use stacks_common::types::chainstate::BurnchainHeaderHash;
|
||||
use stacks_common::types::chainstate::VRFSeed;
|
||||
use stacks_common::util::hash::Hash160;
|
||||
use stacks_common::util::secp256k1::Secp256k1PublicKey;
|
||||
|
||||
@@ -1557,3 +1561,159 @@ fn transition_removes_pox_sunset() {
|
||||
test_observer::clear();
|
||||
channel.stop_chains_coordinator();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn transition_empty_blocks() {
|
||||
// very simple test to verify that the miner will keep making valid (empty) blocks after the
|
||||
// transition. Really tests that the block-commits are well-formed before and after the epoch
|
||||
// transition.
|
||||
if env::var("BITCOIND_TEST") != Ok("1".into()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let epoch_2_05 = 210;
|
||||
let epoch_2_1 = 215;
|
||||
|
||||
let (mut conf, miner_account) = neon_integration_test_conf();
|
||||
|
||||
let mut epochs = core::STACKS_EPOCHS_REGTEST.to_vec();
|
||||
epochs[1].end_height = epoch_2_05;
|
||||
epochs[2].start_height = epoch_2_05;
|
||||
epochs[2].end_height = epoch_2_1;
|
||||
epochs[3].start_height = epoch_2_1;
|
||||
|
||||
conf.node.mine_microblocks = false;
|
||||
conf.burnchain.max_rbf = 1000000;
|
||||
conf.miner.first_attempt_time_ms = 5_000;
|
||||
conf.miner.subsequent_attempt_time_ms = 10_000;
|
||||
conf.node.wait_time_for_blocks = 0;
|
||||
|
||||
conf.burnchain.epochs = Some(epochs);
|
||||
|
||||
let keychain = Keychain::default(conf.node.seed.clone());
|
||||
|
||||
let mut btcd_controller = BitcoinCoreController::new(conf.clone());
|
||||
btcd_controller
|
||||
.start_bitcoind()
|
||||
.map_err(|_e| ())
|
||||
.expect("Failed starting bitcoind");
|
||||
|
||||
let mut btc_regtest_controller = BitcoinRegtestController::new(conf.clone(), None);
|
||||
let http_origin = format!("http://{}", &conf.node.rpc_bind);
|
||||
|
||||
btc_regtest_controller.bootstrap_chain(201);
|
||||
|
||||
eprintln!("Chain bootstrapped...");
|
||||
|
||||
let mut run_loop = neon::RunLoop::new(conf.clone());
|
||||
let blocks_processed = run_loop.get_blocks_processed_arc();
|
||||
|
||||
let channel = run_loop.get_coordinator_channel().unwrap();
|
||||
|
||||
thread::spawn(move || run_loop.start(None, 0));
|
||||
|
||||
// give the run loop some time to start up!
|
||||
wait_for_runloop(&blocks_processed);
|
||||
|
||||
// first block wakes up the run loop
|
||||
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);
|
||||
|
||||
// first block will hold our VRF registration
|
||||
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);
|
||||
|
||||
let tip_info = get_chain_info(&conf);
|
||||
let key_block_ptr = tip_info.burn_block_height as u32;
|
||||
let key_vtxindex = 1; // nothing else here but the coinbase
|
||||
|
||||
// second block will be the first mined Stacks block
|
||||
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);
|
||||
|
||||
let burnchain = Burnchain::regtest(&conf.get_burn_db_path());
|
||||
let mut bitcoin_controller = BitcoinRegtestController::new_dummy(conf.clone());
|
||||
|
||||
// these should all succeed across the epoch boundary
|
||||
for _i in 0..15 {
|
||||
// also, make *huge* block-commits with invalid marker bytes once we reach the new
|
||||
// epoch, and verify that it fails.
|
||||
let tip_info = get_chain_info(&conf);
|
||||
|
||||
// this block is the epoch transition?
|
||||
let (chainstate, _) = StacksChainState::open(
|
||||
false,
|
||||
conf.burnchain.chain_id,
|
||||
&conf.get_chainstate_path_str(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let res = StacksChainState::block_crosses_epoch_boundary(
|
||||
&chainstate.db(),
|
||||
&tip_info.stacks_tip_consensus_hash,
|
||||
&tip_info.stacks_tip,
|
||||
)
|
||||
.unwrap();
|
||||
debug!(
|
||||
"Epoch transition at {} ({}/{}) height {}: {}",
|
||||
&StacksBlockHeader::make_index_block_hash(
|
||||
&tip_info.stacks_tip_consensus_hash,
|
||||
&tip_info.stacks_tip
|
||||
),
|
||||
&tip_info.stacks_tip_consensus_hash,
|
||||
&tip_info.stacks_tip,
|
||||
tip_info.burn_block_height,
|
||||
res
|
||||
);
|
||||
|
||||
if tip_info.burn_block_height == epoch_2_05 || tip_info.burn_block_height == epoch_2_1 {
|
||||
assert!(res);
|
||||
} else {
|
||||
assert!(!res);
|
||||
}
|
||||
|
||||
if tip_info.burn_block_height + 1 >= epoch_2_1 {
|
||||
let burn_fee_cap = 100000000; // 1 BTC
|
||||
let commit_outs = if !burnchain.is_in_prepare_phase(tip_info.burn_block_height + 1) {
|
||||
vec![
|
||||
PoxAddress::standard_burn_address(conf.is_mainnet()),
|
||||
PoxAddress::standard_burn_address(conf.is_mainnet()),
|
||||
]
|
||||
} else {
|
||||
vec![PoxAddress::standard_burn_address(conf.is_mainnet())]
|
||||
};
|
||||
|
||||
// let's commit
|
||||
let burn_parent_modulus =
|
||||
(tip_info.burn_block_height % BURN_BLOCK_MINED_AT_MODULUS) as u8;
|
||||
let op = BlockstackOperationType::LeaderBlockCommit(LeaderBlockCommitOp {
|
||||
sunset_burn: 0,
|
||||
block_header_hash: BlockHeaderHash([0xff; 32]),
|
||||
burn_fee: burn_fee_cap,
|
||||
input: (Txid([0; 32]), 0),
|
||||
apparent_sender: keychain.get_burnchain_signer(),
|
||||
key_block_ptr,
|
||||
key_vtxindex,
|
||||
memo: vec![0], // bad epoch marker
|
||||
new_seed: VRFSeed([0x11; 32]),
|
||||
parent_block_ptr: 0,
|
||||
parent_vtxindex: 0,
|
||||
// to be filled in
|
||||
vtxindex: 0,
|
||||
txid: Txid([0u8; 32]),
|
||||
block_height: 0,
|
||||
burn_header_hash: BurnchainHeaderHash::zero(),
|
||||
burn_parent_modulus,
|
||||
commit_outs,
|
||||
});
|
||||
let mut op_signer = keychain.generate_op_signer();
|
||||
let res = bitcoin_controller.submit_operation(op, &mut op_signer, 1);
|
||||
assert!(res, "Failed to submit block-commit");
|
||||
}
|
||||
|
||||
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);
|
||||
}
|
||||
|
||||
let account = get_account(&http_origin, &miner_account);
|
||||
assert_eq!(account.nonce, 16);
|
||||
|
||||
channel.stop_chains_coordinator();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user