From 6ee5cb2a60b579019f6e1ae46d105f1b166f8584 Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Tue, 1 Nov 2022 10:42:55 -0400 Subject: [PATCH 1/5] feat: use epoch 2.1 marker, and collect the epoch-switch logic for checking it into its own function --- .../burn/operations/leader_block_commit.rs | 227 ++++++++++++++---- 1 file changed, 183 insertions(+), 44 deletions(-) diff --git a/src/chainstate/burn/operations/leader_block_commit.rs b/src/chainstate/burn/operations/leader_block_commit.rs index 925bb5588..b8c729b34 100644 --- a/src/chainstate/burn/operations/leader_block_commit.rs +++ b/src/chainstate/burn/operations/leader_block_commit.rs @@ -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()); From 8eaeee5051b8563ebad68feb69d29d5b3d234166 Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Tue, 1 Nov 2022 10:43:17 -0400 Subject: [PATCH 2/5] fix: mine with the epoch 2.1 marker --- testnet/stacks-node/src/neon_node.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testnet/stacks-node/src/neon_node.rs b/testnet/stacks-node/src/neon_node.rs index 3cf1dd85c..9180b878b 100644 --- a/testnet/stacks-node/src/neon_node.rs +++ b/testnet/stacks-node/src/neon_node.rs @@ -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, From e0be7378660b4ff2b7a47282b8fc06b0da919185 Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Tue, 1 Nov 2022 10:43:28 -0400 Subject: [PATCH 3/5] chore: integration test for mining through the epoch --- testnet/stacks-node/src/tests/epoch_21.rs | 160 ++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/testnet/stacks-node/src/tests/epoch_21.rs b/testnet/stacks-node/src/tests/epoch_21.rs index d31875453..4daccf5dd 100644 --- a/testnet/stacks-node/src/tests/epoch_21.rs +++ b/testnet/stacks-node/src/tests/epoch_21.rs @@ -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(); +} From a5cc9b39ab2dd3104e296c536f491160d81ac96b Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Tue, 1 Nov 2022 10:43:41 -0400 Subject: [PATCH 4/5] chore: run new integration test in CI --- .github/workflows/bitcoin-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/bitcoin-tests.yml b/.github/workflows/bitcoin-tests.yml index 297d0de9c..0aae172d2 100644 --- a/.github/workflows/bitcoin-tests.yml +++ b/.github/workflows/bitcoin-tests.yml @@ -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 From 0879920bc18de6323e9ad35975147e1a04d2121a Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Tue, 1 Nov 2022 15:30:39 -0400 Subject: [PATCH 5/5] fix: use the 2.1 marker pervasively in our tests --- src/burnchains/mod.rs | 3 +++ src/chainstate/coordinator/tests.rs | 4 ++-- testnet/stacks-node/src/node.rs | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/burnchains/mod.rs b/src/burnchains/mod.rs index d18fa011d..9d084a0c1 100644 --- a/src/burnchains/mod.rs +++ b/src/burnchains/mod.rs @@ -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())); diff --git a/src/chainstate/coordinator/tests.rs b/src/chainstate/coordinator/tests.rs index 0379a27ab..9f77c8b1d 100644 --- a/src/chainstate/coordinator/tests.rs +++ b/src/chainstate/coordinator/tests.rs @@ -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, diff --git a/testnet/stacks-node/src/node.rs b/testnet/stacks-node/src/node.rs index e2d63bb2b..ec7cee011 100644 --- a/testnet/stacks-node/src/node.rs +++ b/testnet/stacks-node/src/node.rs @@ -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,