From 999152b5944a431fdf904037a2a27cd017948da1 Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Thu, 8 Sep 2022 14:37:21 -0400 Subject: [PATCH] feat: update the bitcoin block parser to epoch-gate logic that will, at and after epoch 2.1, parse transactions with native segwit outputs and witness-bearing inputs --- src/burnchains/bitcoin/blocks.rs | 428 +++++++++++++++++++++++++------ 1 file changed, 346 insertions(+), 82 deletions(-) diff --git a/src/burnchains/bitcoin/blocks.rs b/src/burnchains/bitcoin/blocks.rs index 3b02fb24a..0800425ca 100644 --- a/src/burnchains/bitcoin/blocks.rs +++ b/src/burnchains/bitcoin/blocks.rs @@ -48,6 +48,8 @@ use stacks_common::util::log; use crate::types::chainstate::BurnchainHeaderHash; +use crate::core::StacksEpochId; + #[derive(Debug, Clone, PartialEq)] pub struct BitcoinHeaderIPC { pub block_header: LoneBlockHeader, @@ -239,6 +241,16 @@ impl BitcoinBlockParser { } } + /// Allow raw inputs? + fn allow_raw_inputs(epoch_id: StacksEpochId) -> bool { + epoch_id >= StacksEpochId::Epoch21 + } + + /// Allow segwit outputs? + fn allow_segwit_outputs(epoch_id: StacksEpochId) -> bool { + epoch_id >= StacksEpochId::Epoch21 + } + /// Verify that a block matches a header pub fn check_block(block: &Block, header: &LoneBlockHeader) -> bool { if header.header.bitcoin_hash() != block.bitcoin_hash() { @@ -299,21 +311,39 @@ impl BitcoinBlockParser { /// Is this an acceptable transaction? It must have /// * an OP_RETURN output at output 0 /// * only p2pkh or p2sh outputs for outputs 1...n - fn maybe_burnchain_tx(&self, tx: &Transaction) -> bool { + fn maybe_burnchain_tx(&self, tx: &Transaction, epoch_id: StacksEpochId) -> bool { if self.parse_data(&tx.output[0].script_pubkey).is_none() { test_debug!("Tx {:?} has no valid OP_RETURN", tx.txid()); return false; } for i in 1..tx.output.len() { - if !tx.output[i].script_pubkey.is_p2pkh() && !tx.output[i].script_pubkey.is_p2sh() { - // unrecognized output type - test_debug!( - "Tx {:?} has unrecognized output type in output {}", - tx.txid(), - i - ); - return false; + if epoch_id < StacksEpochId::Epoch21 { + // only support legacy addresses pre-2.1 + if !tx.output[i].script_pubkey.is_p2pkh() && !tx.output[i].script_pubkey.is_p2sh() { + // unrecognized output type + test_debug!( + "Tx {:?} has unrecognized output type in output {}", + tx.txid(), + i + ); + return false; + } + } else { + // in 2.1 and later, support it if the output decodes + if BitcoinAddress::from_scriptpubkey( + BitcoinNetworkType::Mainnet, + &tx.output[i].script_pubkey.to_bytes(), + ) + .is_none() + { + test_debug!( + "Tx {:?} has unrecognized output type in output {}", + tx.txid(), + i + ); + return false; + } } } @@ -321,11 +351,12 @@ impl BitcoinBlockParser { } /// Parse a transaction's inputs into burnchain tx inputs. - /// Succeeds only if we can parse each input. - fn parse_inputs(&self, tx: &Transaction) -> Option> { + /// Succeeds only if we can parse each input into a structured input. + /// (this is the behavior of Stacks 2.05 and earlier) + fn parse_inputs_structured(tx: &Transaction) -> Option> { let mut ret = vec![]; for inp in &tx.input { - match BitcoinTxInput::from_bitcoin_txin(&inp) { + match BitcoinTxInput::from_bitcoin_txin_structured(&inp) { None => { test_debug!("Failed to parse input"); return None; @@ -338,13 +369,35 @@ impl BitcoinBlockParser { Some(ret) } + /// Parse a transaction's inputs into raw burnchain tx inputs. + /// (this is the behavior of Stacks 2.1 and later) + fn parse_inputs_raw(tx: &Transaction) -> Vec { + let mut ret = vec![]; + for inp in &tx.input { + ret.push(BitcoinTxInput::from_bitcoin_txin_raw(&inp)); + } + ret + } + /// Parse a transaction's outputs into burnchain tx outputs. - /// Succeeds only if we can parse each output. /// Does not parse the first output -- this is the OP_RETURN - fn parse_outputs(&self, tx: &Transaction) -> Option> { + fn parse_outputs( + &self, + tx: &Transaction, + epoch_id: StacksEpochId, + ) -> Option> { + if tx.output.len() == 0 { + return None; + } + let mut ret = vec![]; for outp in &tx.output[1..tx.output.len()] { - match BitcoinTxOutput::from_bitcoin_txout(self.network_id, &outp) { + let out_opt = if BitcoinBlockParser::allow_segwit_outputs(epoch_id) { + BitcoinTxOutput::from_bitcoin_txout(self.network_id, &outp) + } else { + BitcoinTxOutput::from_bitcoin_txout_legacy(self.network_id, &outp) + }; + match out_opt { None => { test_debug!("Failed to parse output"); return None; @@ -357,9 +410,17 @@ impl BitcoinBlockParser { Some(ret) } - /// Parse a Bitcoin transaction into a Burnchain transaction - pub fn parse_tx(&self, tx: &Transaction, vtxindex: usize) -> Option { - if !self.maybe_burnchain_tx(tx) { + /// Parse a Bitcoin transaction into a Burnchain transaction. + /// If `self.allow_raw_inputs()` is true, then scriptSigs will not be decoded. + /// Otherwise, they will be; if decoding fails, None will be returned. + /// In all cases, attempt to decode scriptPubKeys (and if this fails, return None) + pub fn parse_tx( + &self, + tx: &Transaction, + vtxindex: usize, + epoch_id: StacksEpochId, + ) -> Option { + if !self.maybe_burnchain_tx(tx, epoch_id) { test_debug!("Not a burnchain tx"); return None; } @@ -373,8 +434,12 @@ impl BitcoinBlockParser { let data_amt = tx.output[0].value; let (opcode, data) = data_opt.unwrap(); - let inputs_opt = self.parse_inputs(tx); - let outputs_opt = self.parse_outputs(tx); + let inputs_opt = if BitcoinBlockParser::allow_raw_inputs(epoch_id) { + Some(BitcoinBlockParser::parse_inputs_raw(tx)) + } else { + BitcoinBlockParser::parse_inputs_structured(tx) + }; + let outputs_opt = self.parse_outputs(tx, epoch_id); match (inputs_opt, outputs_opt) { (Some(inputs), Some(outputs)) => { @@ -396,13 +461,18 @@ impl BitcoinBlockParser { } /// Given a Bitcoin block, extract the transactions that have OP_RETURN . - /// All outputs must also either be p2pkh or p2sh, and all inputs must encode - /// eiher a p2pkh or multisig p2sh scriptsig. - pub fn parse_block(&self, block: &Block, block_height: u64) -> BitcoinBlock { + /// Uses the internal epoch id to determine whether or not to parse segwit outputs, and whether + /// or not to decode scriptSigs. + pub fn parse_block( + &self, + block: &Block, + block_height: u64, + epoch_id: StacksEpochId, + ) -> BitcoinBlock { let mut accepted_txs = vec![]; for i in 0..block.txdata.len() { let tx = &block.txdata[i]; - match self.parse_tx(tx, i) { + match self.parse_tx(tx, i, epoch_id) { Some(bitcoin_tx) => { accepted_txs.push(bitcoin_tx); } @@ -431,6 +501,7 @@ impl BitcoinBlockParser { block: &Block, header: &LoneBlockHeader, height: u64, + epoch_id: StacksEpochId, ) -> Option { // block header contents must match if !BitcoinBlockParser::check_block(block, header) { @@ -443,7 +514,7 @@ impl BitcoinBlockParser { } // parse it - let burn_block = self.parse_block(&block, height); + let burn_block = self.parse_block(&block, height, epoch_id); Some(burn_block) } } @@ -451,13 +522,18 @@ impl BitcoinBlockParser { impl BurnchainBlockParser for BitcoinBlockParser { type D = BitcoinBlockDownloader; - fn parse(&mut self, ipc_block: &BitcoinBlockIPC) -> Result { + fn parse( + &mut self, + ipc_block: &BitcoinBlockIPC, + epoch_id: StacksEpochId, + ) -> Result { match ipc_block.block_message { btc_message::NetworkMessage::Block(ref block) => { match self.process_block( &block, &ipc_block.header_data.block_header, ipc_block.header_data.block_height, + epoch_id, ) { None => Err(burnchain_error::ParseError), Some(block_data) => Ok(BurnchainBlock::Bitcoin(block_data)), @@ -472,17 +548,20 @@ impl BurnchainBlockParser for BitcoinBlockParser { #[cfg(test)] mod tests { - use crate::burnchains::bitcoin::address::{BitcoinAddress, BitcoinAddressType}; + use crate::burnchains::bitcoin::address::{BitcoinAddress, LegacyBitcoinAddressType}; use crate::burnchains::bitcoin::keys::BitcoinPublicKey; use crate::burnchains::bitcoin::BitcoinNetworkType; use crate::burnchains::bitcoin::{ - BitcoinBlock, BitcoinInputType, BitcoinTransaction, BitcoinTxInput, BitcoinTxOutput, + BitcoinBlock, BitcoinInputType, BitcoinTransaction, BitcoinTxInput, BitcoinTxInputRaw, + BitcoinTxInputStructured, BitcoinTxOutput, }; use crate::burnchains::{BurnchainBlock, BurnchainTransaction, MagicBytes, Txid}; + use crate::core::StacksEpochId; use stacks_common::deps_common::bitcoin::blockdata::block::{Block, LoneBlockHeader}; use stacks_common::deps_common::bitcoin::blockdata::transaction::Transaction; use stacks_common::deps_common::bitcoin::network::encodable::VarInt; use stacks_common::deps_common::bitcoin::network::serialize::deserialize; + use stacks_common::types::Address; use stacks_common::util::hash::hex_bytes; use stacks_common::util::log; @@ -544,7 +623,7 @@ mod tests { } #[test] - fn maybe_burnchain_tx_test() { + fn maybe_burnchain_tx_test_2_05() { let tx_fixtures = vec![ TxParseFixture { // valid @@ -566,13 +645,15 @@ mod tests { let parser = BitcoinBlockParser::new(BitcoinNetworkType::Testnet, MagicBytes([105, 100])); // "id" for tx_fixture in tx_fixtures { let tx = make_tx(&tx_fixture.txstr).unwrap(); - let res = parser.maybe_burnchain_tx(&tx); + let res = parser.maybe_burnchain_tx(&tx, StacksEpochId::Epoch2_05); assert_eq!(res, tx_fixture.result); } } + /// Parse transactions in epoch 2.05 and earlier. + /// All inputs should be BittcoinTxInputStructured #[test] - fn parse_tx_test() { + fn parse_tx_test_2_05() { let vtxindex = 4; let tx_fixtures = vec![ TxFixture { @@ -585,39 +666,39 @@ mod tests { opcode: '+' as u8, data: hex_bytes("fae543ff5672fb607fe15e16b1c3ef38737c631c7c5d911c6617993c21fba731363f1cfe").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("040fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc806b9a4f07579934774cc0c155e781d45c989f94336765e88a66d91cfb9f060b0").unwrap(), ], num_required: 1, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("420577d5f81b5430badcb64cd71e417842c89dd263f845199c0da8d1bc81a020").unwrap(), 2), - }, - BitcoinTxInput { + }.into(), + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("040fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc806b9a4f07579934774cc0c155e781d45c989f94336765e88a66d91cfb9f060b0").unwrap(), ], num_required: 1, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("420577d5f81b5430badcb64cd71e417842c89dd263f845199c0da8d1bc81a020").unwrap(), 1), - }, - BitcoinTxInput { + }.into(), + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("04c77f262dda02580d65c9069a8a34c56bd77325bba4110b693b90216f5a3edc0bebc8ce28d61aa86b414aa91ecb29823b11aeed06098fcd97fee4bc73d54b1e96").unwrap(), ], num_required: 1, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("420577d5f81b5430badcb64cd71e417842c89dd263f845199c0da8d1bc81a020").unwrap(), 4), - } + }.into() ], outputs: vec![ BitcoinTxOutput { units: 27500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("395f3643cea07ec4eec73b4d9a973dcce56b9bf1").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("395f3643cea07ec4eec73b4d9a973dcce56b9bf1").unwrap()).unwrap() }, BitcoinTxOutput { units: 70341, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("9f2660e75380675206b6f1e2b4f106ae33266be4").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("9f2660e75380675206b6f1e2b4f106ae33266be4").unwrap()).unwrap() } ] }) @@ -632,7 +713,7 @@ mod tests { opcode: '~' as u8, data: hex_bytes("7061747269636b7374616e6c6579322e6964").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("04ff897d48c25c48c598aea0d6b1e835008e6679bddbc8d41d7d9f73e6a0dc2b8fe1402487ce2ba1e5365ee28fed024093499c11b8485fb6758a357c7573055767").unwrap(), BitcoinPublicKey::from_hex("04f9478048ce8ff9cfc188a184c8c8c0a3e3dee68f96f6c3bc6f0f7e043ca8d241d5a03ab50157422ad43e9ee1a0a80b0dd17f0b0023f891dbd85daa3069554e2b").unwrap(), @@ -641,8 +722,8 @@ mod tests { num_required: 2, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("22148b29b7099b68f373d56cc7054b3a5f38bad85db6f6f0541636defec2c2b4").unwrap(), 1), - }, - BitcoinTxInput { + }.into(), + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("046097f22211c1f4832e54f0cc76c06b80a4e1fcf237ea487561c80bd5b28b6a483706a04d99038cb434eee82306902193e7b1a368dba33ad14b3f30e004c95e6e").unwrap(), BitcoinPublicKey::from_hex("048e264f76559020fdf50d3a7d9f57ccd548f3dfb962837f958e446add48429951d61e99a109cded2ba9812ee152ebba53a2a6c7b6dfb3c61fcba1b08529283749").unwrap(), @@ -651,16 +732,16 @@ mod tests { num_required: 2, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("22148b29b7099b68f373d56cc7054b3a5f38bad85db6f6f0541636defec2c2b4").unwrap(), 2), - }, + }.into(), ], outputs: vec![ BitcoinTxOutput { units: 11000, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::ScriptHash, &hex_bytes("eb1881fb0682c2eb37e478bf918525a2c61bc404").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("eb1881fb0682c2eb37e478bf918525a2c61bc404").unwrap()).unwrap() }, BitcoinTxOutput { units: 1293677, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::ScriptHash, &hex_bytes("c26afc6cb80ca477c280780902b40cbef8cd804d").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("c26afc6cb80ca477c280780902b40cbef8cd804d").unwrap()).unwrap() } ] }) @@ -675,23 +756,23 @@ mod tests { opcode: ':' as u8, data: hex_bytes("666f6f2e74657374").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("02d341f728783eb93e6fb5921a1ebe9d149e941de31e403cd69afa2f0f1e698e81").unwrap() ], num_required: 1, in_type: BitcoinInputType::SegwitP2SH, tx_ref: (Txid::from_hex("9ec1e4c25610b96cc1afa2b00b2919ce31a7052081c069c586d72a72092befa7").unwrap(), 1), - } + }.into() ], outputs: vec![ BitcoinTxOutput { units: 5500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::ScriptHash, &hex_bytes("4b85301ba8e42bf98472b8ed4939d5f76b98fcea").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("4b85301ba8e42bf98472b8ed4939d5f76b98fcea").unwrap()).unwrap() }, BitcoinTxOutput { units: 4993076500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::ScriptHash, &hex_bytes("31f8968eb1730c83fb58409a9a560a0a0835027f").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("31f8968eb1730c83fb58409a9a560a0a0835027f").unwrap()).unwrap() } ] }) @@ -706,7 +787,7 @@ mod tests { opcode: '?' as u8, data: hex_bytes("9fab7f294936ddb6524a48feff691ecbd0ca9e8f107d845c417a5438d1cb441e827c5126").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("02d341f728783eb93e6fb5921a1ebe9d149e941de31e403cd69afa2f0f1e698e81").unwrap(), BitcoinPublicKey::from_hex("02f21b29694df4c2188bee97103d10d017d1865fb40528f25589af9db6e0786b65").unwrap(), @@ -715,16 +796,16 @@ mod tests { num_required: 2, in_type: BitcoinInputType::SegwitP2SH, tx_ref: (Txid::from_hex("22bd4eed46f8fd3f2947f54b6b2a76984698cda514c65074a203857b96dc11e4").unwrap(), 1), - } + }.into() ], outputs: vec![ BitcoinTxOutput { units: 4993326000, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::ScriptHash, &hex_bytes("87a0487869af70b6b1cc79bd374b75ba1be5cff9").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("87a0487869af70b6b1cc79bd374b75ba1be5cff9").unwrap()).unwrap() }, BitcoinTxOutput { units: 6400000, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("0000000000000000000000000000000000000000").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("0000000000000000000000000000000000000000").unwrap()).unwrap() }, ] }) @@ -734,18 +815,200 @@ mod tests { let parser = BitcoinBlockParser::new(BitcoinNetworkType::Testnet, MagicBytes([105, 100])); // "id" for tx_fixture in tx_fixtures { let tx = make_tx(&tx_fixture.txstr).unwrap(); - let burnchain_tx = parser.parse_tx(&tx, vtxindex as usize); + let burnchain_tx = parser.parse_tx(&tx, vtxindex as usize, StacksEpochId::Epoch2_05); + assert!(burnchain_tx.is_some()); + assert_eq!(burnchain_tx, tx_fixture.result); + } + } + + /// Parse transactions in epoch 2.1 + /// All inputs should be BitcoinTxInputRaw + #[test] + fn parse_tx_test_2_1() { + let vtxindex = 4; + let tx_fixtures = vec![ + TxFixture { + // NAME_UPDATE transaction with 3 singlesig inputs + txstr: "010000000320a081bcd1a80d9c1945f863d29dc84278411ed74cb6dcba30541bf8d5770542020000008b483045022100be57031bf2c095945ba2876e97b3f86ee051643a29b908f22ed45ccf58620103022061e056e5f48c5a51c66604a1ca28e4bfaabab1478424c9bbb396cc6afe5c222e0141040fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc806b9a4f07579934774cc0c155e781d45c989f94336765e88a66d91cfb9f060b0feffffff20a081bcd1a80d9c1945f863d29dc84278411ed74cb6dcba30541bf8d5770542010000008b483045022100fd9c04b330810694cb4bfef793b193f9cbfaa07325700f217b9cb03e5207005302202f07e7c9c6774c5619a043752444f6da6fd81b9d9d008ec965796d87271598de0141040fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc806b9a4f07579934774cc0c155e781d45c989f94336765e88a66d91cfb9f060b0feffffff20a081bcd1a80d9c1945f863d29dc84278411ed74cb6dcba30541bf8d5770542040000008a47304402205e24943a40b8ef876cc218a7e8994f4be7afb7aa02403bb73510fac01b33ead3022033e5fb811c396b2fb50a825cd1d86e82eb83483901a1793d0eb15e3e9f1d1c5b814104c77f262dda02580d65c9069a8a34c56bd77325bba4110b693b90216f5a3edc0bebc8ce28d61aa86b414aa91ecb29823b11aeed06098fcd97fee4bc73d54b1e96feffffff030000000000000000296a2769642bfae543ff5672fb607fe15e16b1c3ef38737c631c7c5d911c6617993c21fba731363f1cfe6c6b0000000000001976a914395f3643cea07ec4eec73b4d9a973dcce56b9bf188acc5120100000000001976a9149f2660e75380675206b6f1e2b4f106ae33266be488ac00000000".to_owned(), + result: Some(BitcoinTransaction { + data_amt: 0, + txid: to_txid(&hex_bytes("185c112401590b11acdfea6bb26d2a8e37cb31f24a0c89dbb8cc14b3d6271fb1").unwrap()), + vtxindex: vtxindex, + opcode: '+' as u8, + data: hex_bytes("fae543ff5672fb607fe15e16b1c3ef38737c631c7c5d911c6617993c21fba731363f1cfe").unwrap(), + inputs: vec![ + BitcoinTxInputRaw { + scriptSig: hex_bytes("483045022100be57031bf2c095945ba2876e97b3f86ee051643a29b908f22ed45ccf58620103022061e056e5f48c5a51c66604a1ca28e4bfaabab1478424c9bbb396cc6afe5c222e0141040fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc806b9a4f07579934774cc0c155e781d45c989f94336765e88a66d91cfb9f060b0").unwrap(), + witness: vec![], + tx_ref: (Txid::from_hex("420577d5f81b5430badcb64cd71e417842c89dd263f845199c0da8d1bc81a020").unwrap(), 2), + }.into(), + BitcoinTxInputRaw { + scriptSig: hex_bytes("483045022100fd9c04b330810694cb4bfef793b193f9cbfaa07325700f217b9cb03e5207005302202f07e7c9c6774c5619a043752444f6da6fd81b9d9d008ec965796d87271598de0141040fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc806b9a4f07579934774cc0c155e781d45c989f94336765e88a66d91cfb9f060b0").unwrap(), + witness: vec![], + tx_ref: (Txid::from_hex("420577d5f81b5430badcb64cd71e417842c89dd263f845199c0da8d1bc81a020").unwrap(), 1), + }.into(), + BitcoinTxInputRaw { + scriptSig: hex_bytes("47304402205e24943a40b8ef876cc218a7e8994f4be7afb7aa02403bb73510fac01b33ead3022033e5fb811c396b2fb50a825cd1d86e82eb83483901a1793d0eb15e3e9f1d1c5b814104c77f262dda02580d65c9069a8a34c56bd77325bba4110b693b90216f5a3edc0bebc8ce28d61aa86b414aa91ecb29823b11aeed06098fcd97fee4bc73d54b1e96").unwrap(), + witness: vec![], + tx_ref: (Txid::from_hex("420577d5f81b5430badcb64cd71e417842c89dd263f845199c0da8d1bc81a020").unwrap(), 4), + }.into() + ], + outputs: vec![ + BitcoinTxOutput { + units: 27500, + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Mainnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("395f3643cea07ec4eec73b4d9a973dcce56b9bf1").unwrap()).unwrap() + }, + BitcoinTxOutput { + units: 70341, + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Mainnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("9f2660e75380675206b6f1e2b4f106ae33266be4").unwrap()).unwrap() + } + ] + }) + }, + TxFixture { + // NAME_REVOKE with 2 2-of-3 multisig inputs + txstr: "0100000002b4c2c2fede361654f0f6b65dd8ba385f3a4b05c76cd573f3689b09b7298b142201000000fd5c010047304402203537b5ded3716553b6f3fc7ccc7e55bc42b6caa1c069c9b2ce068d57f9024de7022026eb81e226b0de30448732835424eef52a3b9d67020c62b48df75974c5fe09870147304402201cc22e43302688d975df3bcad70065c8dad497b092a58e97c6c306b65176c70802200b9c3a62b22865e957331578d6e5d684cad87279fd8b852fcc2d34d3911e8643014cc9524104ff897d48c25c48c598aea0d6b1e835008e6679bddbc8d41d7d9f73e6a0dc2b8fe1402487ce2ba1e5365ee28fed024093499c11b8485fb6758a357c75730557674104f9478048ce8ff9cfc188a184c8c8c0a3e3dee68f96f6c3bc6f0f7e043ca8d241d5a03ab50157422ad43e9ee1a0a80b0dd17f0b0023f891dbd85daa3069554e2b41046fd8c7330fbe307a0fad0bf9472ca080f4941f4b6edea7ab090e3e26075e7277a0bd61f42eff54daf3e6141de46a98a5a8265c9e8d58bd1a86cf36d418788ab853aeffffffffb4c2c2fede361654f0f6b65dd8ba385f3a4b05c76cd573f3689b09b7298b142202000000fd5d0100473044022070cfd1e13d9844db995111ed5cc0578ca4d03504fdec1cf1636cd0054dffeeed022046c8d87291367402f4b54c2ef985a0171e400fe079da5234c912103cf2dd683b0148304502210099f092b12000dc78074934135443656091c606b40c7925bae30a6285946e36b9022062b5fa5e28986e0c27aad11f8fdb1409eb87a169972dc1ebbd91aa45810f9d9a014cc95241046097f22211c1f4832e54f0cc76c06b80a4e1fcf237ea487561c80bd5b28b6a483706a04d99038cb434eee82306902193e7b1a368dba33ad14b3f30e004c95e6e41048e264f76559020fdf50d3a7d9f57ccd548f3dfb962837f958e446add48429951d61e99a109cded2ba9812ee152ebba53a2a6c7b6dfb3c61fcba1b0852928374941044c9f30b4546c1f30087001fa6450e52c645bd49e91a18c9c16965b72f5153f0e4b04712218b42b2bc578017b471beaa7d8c0a9eb69174ad50714d7ef4117863d53aeffffffff030000000000000000176a1569647e7061747269636b7374616e6c6579322e6964f82a00000000000017a914eb1881fb0682c2eb37e478bf918525a2c61bc404876dbd13000000000017a914c26afc6cb80ca477c280780902b40cbef8cd804d8700000000".to_owned(), + result: Some(BitcoinTransaction { + data_amt: 0, + txid: to_txid(&hex_bytes("eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f").unwrap()), + vtxindex: vtxindex, + opcode: '~' as u8, + data: hex_bytes("7061747269636b7374616e6c6579322e6964").unwrap(), + inputs: vec![ + BitcoinTxInputRaw { + scriptSig: hex_bytes("0047304402203537b5ded3716553b6f3fc7ccc7e55bc42b6caa1c069c9b2ce068d57f9024de7022026eb81e226b0de30448732835424eef52a3b9d67020c62b48df75974c5fe09870147304402201cc22e43302688d975df3bcad70065c8dad497b092a58e97c6c306b65176c70802200b9c3a62b22865e957331578d6e5d684cad87279fd8b852fcc2d34d3911e8643014cc9524104ff897d48c25c48c598aea0d6b1e835008e6679bddbc8d41d7d9f73e6a0dc2b8fe1402487ce2ba1e5365ee28fed024093499c11b8485fb6758a357c75730557674104f9478048ce8ff9cfc188a184c8c8c0a3e3dee68f96f6c3bc6f0f7e043ca8d241d5a03ab50157422ad43e9ee1a0a80b0dd17f0b0023f891dbd85daa3069554e2b41046fd8c7330fbe307a0fad0bf9472ca080f4941f4b6edea7ab090e3e26075e7277a0bd61f42eff54daf3e6141de46a98a5a8265c9e8d58bd1a86cf36d418788ab853ae").unwrap(), + witness: vec![], + tx_ref: (Txid::from_hex("22148b29b7099b68f373d56cc7054b3a5f38bad85db6f6f0541636defec2c2b4").unwrap(), 1), + }.into(), + BitcoinTxInputRaw { + scriptSig: hex_bytes("00473044022070cfd1e13d9844db995111ed5cc0578ca4d03504fdec1cf1636cd0054dffeeed022046c8d87291367402f4b54c2ef985a0171e400fe079da5234c912103cf2dd683b0148304502210099f092b12000dc78074934135443656091c606b40c7925bae30a6285946e36b9022062b5fa5e28986e0c27aad11f8fdb1409eb87a169972dc1ebbd91aa45810f9d9a014cc95241046097f22211c1f4832e54f0cc76c06b80a4e1fcf237ea487561c80bd5b28b6a483706a04d99038cb434eee82306902193e7b1a368dba33ad14b3f30e004c95e6e41048e264f76559020fdf50d3a7d9f57ccd548f3dfb962837f958e446add48429951d61e99a109cded2ba9812ee152ebba53a2a6c7b6dfb3c61fcba1b0852928374941044c9f30b4546c1f30087001fa6450e52c645bd49e91a18c9c16965b72f5153f0e4b04712218b42b2bc578017b471beaa7d8c0a9eb69174ad50714d7ef4117863d53ae").unwrap(), + witness: vec![], + tx_ref: (Txid::from_hex("22148b29b7099b68f373d56cc7054b3a5f38bad85db6f6f0541636defec2c2b4").unwrap(), 2), + }.into(), + ], + outputs: vec![ + BitcoinTxOutput { + units: 11000, + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Mainnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("eb1881fb0682c2eb37e478bf918525a2c61bc404").unwrap()).unwrap() + }, + BitcoinTxOutput { + units: 1293677, + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Mainnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("c26afc6cb80ca477c280780902b40cbef8cd804d").unwrap()).unwrap() + } + ] + }) + }, + TxFixture { + // NAME_REGISTRATION with p2wpkh-p2sh segwit input + txstr: "01000000000101a7ef2b09722ad786c569c0812005a731ce19290bb0a2afc16cb91056c2e4c19e0100000017160014393ffec4f09b38895b8502377693f23c6ae00f19ffffffff0300000000000000000d6a0b69643a666f6f2e746573747c1500000000000017a9144b85301ba8e42bf98472b8ed4939d5f76b98fcea87144d9c290100000017a91431f8968eb1730c83fb58409a9a560a0a0835027f8702483045022100fc82815edf1c0ef0c601cf1e26494626d7b01597be5ab83df025ff1ee67730130220016c4c29d77aadb5ff57c0c9272a43950ca29b84d8adfaed95ac69db90b35d5b012102d341f728783eb93e6fb5921a1ebe9d149e941de31e403cd69afa2f0f1e698e8100000000".to_owned(), + result: Some(BitcoinTransaction { + data_amt: 0, + txid: to_txid(&hex_bytes("b908952b30ccfdfa59985dc1ffdd2a22ef054d20fa253510d2af7797dddee459").unwrap()), + vtxindex: vtxindex, + opcode: ':' as u8, + data: hex_bytes("666f6f2e74657374").unwrap(), + inputs: vec![ + BitcoinTxInputRaw { + scriptSig: hex_bytes("160014393ffec4f09b38895b8502377693f23c6ae00f19").unwrap(), + witness: vec![ + hex_bytes("3045022100fc82815edf1c0ef0c601cf1e26494626d7b01597be5ab83df025ff1ee67730130220016c4c29d77aadb5ff57c0c9272a43950ca29b84d8adfaed95ac69db90b35d5b01").unwrap(), + hex_bytes("02d341f728783eb93e6fb5921a1ebe9d149e941de31e403cd69afa2f0f1e698e81").unwrap() + ], + tx_ref: (Txid::from_hex("9ec1e4c25610b96cc1afa2b00b2919ce31a7052081c069c586d72a72092befa7").unwrap(), 1), + }.into(), + ], + outputs: vec![ + BitcoinTxOutput { + units: 5500, + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Mainnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("4b85301ba8e42bf98472b8ed4939d5f76b98fcea").unwrap()).unwrap() + }, + BitcoinTxOutput { + units: 4993076500, + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Mainnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("31f8968eb1730c83fb58409a9a560a0a0835027f").unwrap()).unwrap() + } + ] + }) + }, + TxFixture { + // NAME_PREORDER with a 2-of-3 p2wsh-p2sh multisig segwit input + txstr: "01000000000101e411dc967b8503a27450c614a5cd984698762a6b4bf547293ffdf846ed4ebd22010000002322002067091a41e9871c5ae20b0c69a786f02df5d3c7aa632689b608069181b43a28a2ffffffff030000000000000000296a2769643f9fab7f294936ddb6524a48feff691ecbd0ca9e8f107d845c417a5438d1cb441e827c5126b01ba0290100000017a91487a0487869af70b6b1cc79bd374b75ba1be5cff98700a86100000000001976a914000000000000000000000000000000000000000088ac0400473044022064c5b5f61baad8bb8ecad98666b99e09f1777ef805df41a1c7926f8468b6b6df02205eac177c77f274acb670cd24d504f01b27de767e0241c818c91e479cb0ddcf18014730440220053ce777bc7bb842d8eef83769a027797567624ab9eed5722889ed3192f431b30220256e8aaef8de2a571198acde708fcbca02fb18780ac470c0d7f811734af729af0169522102d341f728783eb93e6fb5921a1ebe9d149e941de31e403cd69afa2f0f1e698e812102f21b29694df4c2188bee97103d10d017d1865fb40528f25589af9db6e0786b6521028791dc45c049107fb99e673265a38a096536aacdf78aa90710a32fff7750f9f953ae00000000".to_owned(), + result: Some(BitcoinTransaction { + data_amt: 0, + txid: to_txid(&hex_bytes("16751ca54407b922e3072830cf4be58c5562a6dc350f6703192b673c4cc86182").unwrap()), + vtxindex: vtxindex, + opcode: '?' as u8, + data: hex_bytes("9fab7f294936ddb6524a48feff691ecbd0ca9e8f107d845c417a5438d1cb441e827c5126").unwrap(), + inputs: vec![ + BitcoinTxInputRaw { + scriptSig: hex_bytes("22002067091a41e9871c5ae20b0c69a786f02df5d3c7aa632689b608069181b43a28a2").unwrap(), + witness: vec![ + vec![], + hex_bytes("3044022064c5b5f61baad8bb8ecad98666b99e09f1777ef805df41a1c7926f8468b6b6df02205eac177c77f274acb670cd24d504f01b27de767e0241c818c91e479cb0ddcf1801").unwrap(), + hex_bytes("30440220053ce777bc7bb842d8eef83769a027797567624ab9eed5722889ed3192f431b30220256e8aaef8de2a571198acde708fcbca02fb18780ac470c0d7f811734af729af01").unwrap(), + hex_bytes("522102d341f728783eb93e6fb5921a1ebe9d149e941de31e403cd69afa2f0f1e698e812102f21b29694df4c2188bee97103d10d017d1865fb40528f25589af9db6e0786b6521028791dc45c049107fb99e673265a38a096536aacdf78aa90710a32fff7750f9f953ae").unwrap() + ], + tx_ref: (Txid::from_hex("22bd4eed46f8fd3f2947f54b6b2a76984698cda514c65074a203857b96dc11e4").unwrap(), 1), + }.into(), + ], + outputs: vec![ + BitcoinTxOutput { + units: 4993326000, + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Mainnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("87a0487869af70b6b1cc79bd374b75ba1be5cff9").unwrap()).unwrap() + }, + BitcoinTxOutput { + units: 6400000, + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Mainnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("0000000000000000000000000000000000000000").unwrap()).unwrap() + }, + ] + }) + }, + TxFixture { + // NAMESPACE_REVEAL with a segwit p2wpkh script pubkey + txstr: "0100000001fde2146ec3ecf037ad515c0c1e2ba8abee348bd2b3c6a576bf909d78b0b18cd2010000006a47304402203ec06f11bc5b7e79fad54b2d69a375ba78576a2a0293f531a082fcfe13a9e9e802201afcf0038d9ccb9c88113248faaf812321b65d7b09b4a6e2f04f463d2741101e012103d6fd1ba0effaf1e8d94ea7b7a3d0ef26fea00a14ce5ffcc1495fe588a2c6d0f3ffffffff0300000000000000001a6a186964260000cd73fa046543210000000000aa0001746573747c1500000000000016001482093b62a3699282d926981bed7665e8384caa552076fd29010000001976a91474178497e927ff3ff1428a241be454d393c3c91c88ac00000000".to_owned(), + result: Some(BitcoinTransaction { + data_amt: 0, + txid: to_txid(&hex_bytes("8b8a12909d48fd86c06e92270133d320498fb36caa0fdcb3292a8bba99669ebd").unwrap()), + vtxindex: vtxindex, + opcode: '&' as u8, + data: hex_bytes("0000cd73fa046543210000000000aa000174657374").unwrap(), + inputs: vec![ + BitcoinTxInputRaw { + scriptSig: hex_bytes("47304402203ec06f11bc5b7e79fad54b2d69a375ba78576a2a0293f531a082fcfe13a9e9e802201afcf0038d9ccb9c88113248faaf812321b65d7b09b4a6e2f04f463d2741101e012103d6fd1ba0effaf1e8d94ea7b7a3d0ef26fea00a14ce5ffcc1495fe588a2c6d0f3").unwrap(), + witness: vec![], + tx_ref: (Txid::from_hex("d28cb1b0789d90bf76a5c6b3d28b34eeaba82b1e0c5c51ad37f0ecc36e14e2fd").unwrap(), 1), + }.into() + ], + outputs: vec![ + BitcoinTxOutput { + units: 5500, + address: BitcoinAddress::from_string("bc1qsgynkc4rdxfg9kfxnqd76an9aquye2j4kdnk7c").unwrap(), + }, + BitcoinTxOutput { + units: 4999444000, + address: BitcoinAddress::from_string("1BaqZJqwt2dcdxt6oa3mwSK4DiEyfXCgnZ").unwrap(), + }, + ], + }), + } + ]; + + let parser = BitcoinBlockParser::new(BitcoinNetworkType::Mainnet, MagicBytes([105, 100])); // "id" + for tx_fixture in tx_fixtures { + test_debug!("parse {}", &tx_fixture.txstr); + let tx = make_tx(&tx_fixture.txstr).unwrap(); + let burnchain_tx = parser.parse_tx(&tx, vtxindex as usize, StacksEpochId::Epoch21); assert!(burnchain_tx.is_some()); assert_eq!(burnchain_tx, tx_fixture.result); } } #[test] - fn parse_tx_strange() { + fn parse_tx_strange_2_05() { let vtxindex = 4; let tx_fixtures_strange : Vec = vec![ TxFixture { - // NAMESPACE_REVEAL with a segwit p2wpkh script pubkey (shouldn't parse) + // NAMESPACE_REVEAL with a segwit p2wpkh script pubkey (shouldn't parse in epoch + // 2.05) txstr: "0100000001fde2146ec3ecf037ad515c0c1e2ba8abee348bd2b3c6a576bf909d78b0b18cd2010000006a47304402203ec06f11bc5b7e79fad54b2d69a375ba78576a2a0293f531a082fcfe13a9e9e802201afcf0038d9ccb9c88113248faaf812321b65d7b09b4a6e2f04f463d2741101e012103d6fd1ba0effaf1e8d94ea7b7a3d0ef26fea00a14ce5ffcc1495fe588a2c6d0f3ffffffff0300000000000000001a6a186964260000cd73fa046543210000000000aa0001746573747c1500000000000016001482093b62a3699282d926981bed7665e8384caa552076fd29010000001976a91474178497e927ff3ff1428a241be454d393c3c91c88ac00000000".to_owned(), result: None }, @@ -760,7 +1023,7 @@ mod tests { let parser = BitcoinBlockParser::new(BitcoinNetworkType::Testnet, MagicBytes([105, 100])); // "id" for tx_fixture in tx_fixtures_strange { let tx = make_tx(&tx_fixture.txstr).unwrap(); - let burnchain_tx = parser.parse_tx(&tx, vtxindex as usize); + let burnchain_tx = parser.parse_tx(&tx, vtxindex as usize, StacksEpochId::Epoch2_05); assert!(burnchain_tx.is_none()); } } @@ -786,23 +1049,23 @@ mod tests { opcode: ':' as u8, data: hex_bytes("666f6f2e74657374").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("02d341f728783eb93e6fb5921a1ebe9d149e941de31e403cd69afa2f0f1e698e81").unwrap() ], num_required: 1, in_type: BitcoinInputType::SegwitP2SH, tx_ref: (Txid::from_hex("9ec1e4c25610b96cc1afa2b00b2919ce31a7052081c069c586d72a72092befa7").unwrap(), 1), - } + }.into(), ], outputs: vec![ BitcoinTxOutput { units: 5500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::ScriptHash, &hex_bytes("4b85301ba8e42bf98472b8ed4939d5f76b98fcea").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("4b85301ba8e42bf98472b8ed4939d5f76b98fcea").unwrap()).unwrap() }, BitcoinTxOutput { units: 4993076500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::ScriptHash, &hex_bytes("31f8968eb1730c83fb58409a9a560a0a0835027f").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::ScriptHash, &hex_bytes("31f8968eb1730c83fb58409a9a560a0a0835027f").unwrap()).unwrap() } ] } @@ -829,23 +1092,23 @@ mod tests { opcode: '$' as u8, data: hex_bytes("7c503a2e30a905cb515cfbc291766dfa00000000000000000000000000535441434b530000000000000064").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("03d6fd1ba0effaf1e8d94ea7b7a3d0ef26fea00a14ce5ffcc1495fe588a2c6d0f3").unwrap() ], num_required: 1, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("f741c40e6ad746f96be5a483d45b874f37158302d4a5d71da4f874a349ff17c5").unwrap(), 1), - } + }.into() ], outputs: vec![ BitcoinTxOutput { units: 5500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("41a349571d89decfac52ffecd92300b6a97b2841").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("41a349571d89decfac52ffecd92300b6a97b2841").unwrap()).unwrap() }, BitcoinTxOutput { units: 4986192000, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("74178497e927ff3ff1428a241be454d393c3c91c").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("74178497e927ff3ff1428a241be454d393c3c91c").unwrap()).unwrap() } ] }, @@ -857,23 +1120,23 @@ mod tests { opcode: '$' as u8, data: hex_bytes("7c503a2e30a905cb515cfbc291766dfa00000000000000000000000000535441434b530000000000000064").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("04ef29f16c10aa2d0468d7841cfedb8b5729689ebca4db38fb8f3fc9ab158e799b6d6dfc2bca52fe490f7acd38e351bf1d28b8f1f48736a0b022f806dd107a8385").unwrap() ], num_required: 1, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("ba53c1d5b3d18115d7a9f7402e7c96281a05af1835f98dc8d729158c96d31193").unwrap(), 0), - } + }.into() ], outputs: vec![ BitcoinTxOutput { units: 5500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("e1762290e3f035ea4e7f8cbf72a9d9386c4020ab").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("e1762290e3f035ea4e7f8cbf72a9d9386c4020ab").unwrap()).unwrap() }, BitcoinTxOutput { units: 211500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("41a349571d89decfac52ffecd92300b6a97b2841").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("41a349571d89decfac52ffecd92300b6a97b2841").unwrap()).unwrap() } ] }, @@ -885,23 +1148,23 @@ mod tests { opcode: '$' as u8, data: hex_bytes("7c503a2e30a905cb515cfbc291766dfa00000000000000000000000000535441434b530000000000000064").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("0479ff722ee4dfd880e307d06fc50a248a9f73a57998a65fd95c48436400280372cf9e99a9952ded7723a68118d4dcf658efbaed2a73265fc63b44789d2d459637").unwrap() ], num_required: 1, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("bb8c5223c42c740c056afb147264c0982a96bafd4801e121669da99fc3ca33f4").unwrap(), 0), - } + }.into() ], outputs: vec![ BitcoinTxOutput { units: 5500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("f3c49407d41b82f30636f5180718bb658ce7fe94").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("f3c49407d41b82f30636f5180718bb658ce7fe94").unwrap()).unwrap() }, BitcoinTxOutput { units: 211500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("e1762290e3f035ea4e7f8cbf72a9d9386c4020ab").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("e1762290e3f035ea4e7f8cbf72a9d9386c4020ab").unwrap()).unwrap() } ] }, @@ -913,23 +1176,23 @@ mod tests { opcode: '$' as u8, data: hex_bytes("7c503a2e30a905cb515cfbc291766dfa00000000000000000000000000535441434b530000000000000064").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("04447019ded953edd1bcecffbc66a555f822675257bacc0d357c1dc5194849367354c551e2c2e2048cb927985c8528e24120addd9aa0a2c68b23b462f337caaebc").unwrap() ], num_required: 1, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("a8e317854cf5e11e13539f44cabdcf29767d838ae684a865f849a8405c3d96b4").unwrap(), 0), - } + }.into() ], outputs: vec![ BitcoinTxOutput { units: 5500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("afc75a8f8fbcb922248a663dec927b33dccaed37").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("afc75a8f8fbcb922248a663dec927b33dccaed37").unwrap()).unwrap() }, BitcoinTxOutput { units: 211500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("f3c49407d41b82f30636f5180718bb658ce7fe94").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("f3c49407d41b82f30636f5180718bb658ce7fe94").unwrap()).unwrap() } ] }, @@ -941,23 +1204,23 @@ mod tests { opcode: '$' as u8, data: hex_bytes("7c503a2e30a905cb515cfbc291766dfa00000000000000000000000000535441434b530000000000000064").unwrap(), inputs: vec![ - BitcoinTxInput { + BitcoinTxInputStructured { keys: vec![ BitcoinPublicKey::from_hex("04a96a8355b6c3597bb9425c2ef264ab8179ca8acd3032b62980d2067261b37666b66510983e6d60d49bbd28129f0bae4dbcaa97c2bc61a6b2e48ca1625ce81335").unwrap() ], num_required: 1, in_type: BitcoinInputType::Standard, tx_ref: (Txid::from_hex("be8b8ec102773e2c2e6179584684280a0f42c83c11dc1a30610310c91796c804").unwrap(), 0), - } + }.into() ], outputs: vec![ BitcoinTxOutput { units: 5500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("74178497e927ff3ff1428a241be454d393c3c91c").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("74178497e927ff3ff1428a241be454d393c3c91c").unwrap()).unwrap() }, BitcoinTxOutput { units: 211500, - address: BitcoinAddress::from_bytes(BitcoinNetworkType::Testnet, BitcoinAddressType::PublicKeyHash, &hex_bytes("afc75a8f8fbcb922248a663dec927b33dccaed37").unwrap()).unwrap() + address: BitcoinAddress::from_bytes_legacy(BitcoinNetworkType::Testnet, LegacyBitcoinAddressType::PublicKeyHash, &hex_bytes("afc75a8f8fbcb922248a663dec927b33dccaed37").unwrap()).unwrap() } ] } @@ -979,7 +1242,8 @@ mod tests { let header = make_block_header(&block_fixture.header).unwrap(); let height = block_fixture.height; - let parsed_block_opt = parser.process_block(&block, &header, height); + let parsed_block_opt = + parser.process_block(&block, &header, height, StacksEpochId::Epoch2_05); assert_eq!(parsed_block_opt, block_fixture.result); } }