diff --git a/components/ordhook-core/src/core/pipeline/processors/inscription_indexing.rs b/components/ordhook-core/src/core/pipeline/processors/inscription_indexing.rs index e17a4bdb..e9828ad0 100644 --- a/components/ordhook-core/src/core/pipeline/processors/inscription_indexing.rs +++ b/components/ordhook-core/src/core/pipeline/processors/inscription_indexing.rs @@ -344,49 +344,81 @@ pub fn process_block( mod test { use std::sync::Arc; - use chainhook_sdk::{types::OrdinalOperation, utils::Context}; + use chainhook_sdk::{ + types::{bitcoin::TxOut, OrdinalOperation}, + utils::Context, + }; use crate::{ config::Config, - core::{ - meta_protocols::brc20::cache::brc20_new_cache, new_traversals_lazy_cache, - protocol::inscription_sequencing::SequenceCursor, - }, + core::{new_traversals_lazy_cache, protocol::inscription_sequencing::SequenceCursor}, db::{ - blocks::open_blocks_db_with_retry, drop_sqlite_dbs, initialize_sqlite_dbs, + blocks::{insert_standardized_block, open_blocks_db_with_retry}, + drop_all_dbs, initialize_sqlite_dbs, ordinals::open_ordinals_db_rw, }, utils::{ monitoring::PrometheusMonitoring, - test_helpers::{new_test_block, new_test_reveal_tx}, + test_helpers::{TestBlockBuilder, TestTransactionBuilder, TestTxInBuilder}, }, }; use super::process_blocks; #[test] - fn process_block_with_inscription() { + fn process_block_with_inscription_reveal() { let ctx = Context::empty(); let config = Config::test_default(); - - // Create DBs - drop_sqlite_dbs(&config); - let db_conns = initialize_sqlite_dbs(&config, &ctx); - let _ = open_blocks_db_with_retry(true, &config, &ctx); - - // Insert block into rocksdb - - let mut next_blocks = vec![new_test_block(vec![new_test_reveal_tx()])]; - let mut sequence_cursor = SequenceCursor::new(&db_conns.ordinals); + drop_all_dbs(&config); + let sqlite_dbs = initialize_sqlite_dbs(&config, &ctx); + let blocks_db = open_blocks_db_with_retry(true, &config, &ctx); + + // Block 0: A coinbase tx generating the inscription sat. + let coinbase0 = TestTransactionBuilder::new() + .hash("0xa321c61c83563a377f82ef59301f2527079f6bda7c2d04f9f5954c873f42e8ac".to_string()) + .build(); + let block0 = TestBlockBuilder::new() + .hash("0x00000000000000000001b228f9faca9e7d11fcecff9d463bd05546ff0aa4651a".to_string()) + .height(849999) + .add_transaction(coinbase0) + .build(); + insert_standardized_block(&block0, &blocks_db, &ctx); + + // Block 1: The actual inscription. + let coinbase1 = TestTransactionBuilder::new().build(); + let tx1 = TestTransactionBuilder::new() + .hash("0xc62d436323e14cdcb91dd21cb7814fd1ac5b9ecb6e3cc6953b54c02a343f7ec9".to_string()) + .add_input( + TestTxInBuilder::new() + .prev_out_block_height(849999) + .prev_out_tx_hash( + "0xa321c61c83563a377f82ef59301f2527079f6bda7c2d04f9f5954c873f42e8ac" + .to_string(), + ) + .build(), + ) + .add_output(TxOut { + value: 10000, + script_pubkey: "0x00145e5f0d045e441bf001584eaeca6cd84da04b1084".to_string(), + }) + .build(); + let block1 = TestBlockBuilder::new() + .hash("0xb61b0172d95e266c18aea0c624db987e971a5d6d4ebc2aaed85da4642d635735".to_string()) + .height(850000) + .add_transaction(coinbase1) + .add_transaction(tx1) + .build(); + insert_standardized_block(&block1, &blocks_db, &ctx); + + let mut next_blocks = vec![block1]; + let mut sequence_cursor = SequenceCursor::new(&sqlite_dbs.ordinals); let cache_l2 = Arc::new(new_traversals_lazy_cache(2048)); - let mut inscriptions_db_conn_rw = - open_ordinals_db_rw(&config.expected_cache_path(), &ctx).expect(""); let results = process_blocks( &mut next_blocks, &mut sequence_cursor, &cache_l2, - &mut inscriptions_db_conn_rw, + &mut open_ordinals_db_rw(&config.expected_cache_path(), &ctx).expect(""), &mut None, &mut None, &None, @@ -395,53 +427,62 @@ mod test { &ctx, ); - assert_eq!(results.len(), 1); - let transactions = &results[0].transactions; - assert_eq!(transactions.len(), 1); - let parsed_tx = &transactions[0]; - assert_eq!(parsed_tx.metadata.ordinal_operations.len(), 1); + let result_tx = &results[0].transactions[1]; + assert_eq!(result_tx.metadata.ordinal_operations.len(), 1); let OrdinalOperation::InscriptionRevealed(reveal) = - &parsed_tx.metadata.ordinal_operations[0] + &result_tx.metadata.ordinal_operations[0] else { panic!(); }; assert_eq!( reveal.inscription_id, - "b61b0172d95e266c18aea0c624db987e971a5d6d4ebc2aaed85da4642d635735i0".to_string() + "c62d436323e14cdcb91dd21cb7814fd1ac5b9ecb6e3cc6953b54c02a343f7ec9i0".to_string() ); + assert_eq!(reveal.inscription_number.jubilee, 0); assert_eq!(reveal.content_bytes, "0x7b200a20202270223a20226272632d3230222c0a2020226f70223a20226465706c6f79222c0a2020227469636b223a20226f726469222c0a2020226d6178223a20223231303030303030222c0a2020226c696d223a202231303030220a7d".to_string()); assert_eq!(reveal.content_length, 94); - } - - #[test] - fn process_block_with_brc20_inscription() { - let ctx = Context::empty(); - let mut config = Config::mainnet_default(); - config.storage.working_dir = "tmp".to_string(); - config.meta_protocols.brc20 = true; - drop_sqlite_dbs(&config); - let mut db_conns = initialize_sqlite_dbs(&config, &ctx); - let mut next_blocks = vec![new_test_block(vec![new_test_reveal_tx()])]; - let mut sequence_cursor = SequenceCursor::new(&db_conns.ordinals); - let cache_l2 = Arc::new(new_traversals_lazy_cache(2048)); - let mut inscriptions_db_conn_rw = - open_ordinals_db_rw(&config.expected_cache_path(), &ctx).expect(""); - let mut brc20_cache = brc20_new_cache(&config); - - let _ = process_blocks( - &mut next_blocks, - &mut sequence_cursor, - &cache_l2, - &mut inscriptions_db_conn_rw, - &mut brc20_cache, - &mut db_conns.brc20, - &None, - &PrometheusMonitoring::new(), - &config, - &ctx, + assert_eq!(reveal.content_type, "text/plain;charset=utf-8".to_string()); + assert_eq!( + reveal.inscriber_address, + Some("bc1qte0s6pz7gsdlqq2cf6hv5mxcfksykyyyjkdfd5".to_string()) + ); + assert_eq!(reveal.ordinal_number, 1971874687500000); + assert_eq!(reveal.ordinal_block_height, 849999); + assert_eq!( + reveal.satpoint_post_inscription, + "c62d436323e14cdcb91dd21cb7814fd1ac5b9ecb6e3cc6953b54c02a343f7ec9:0:0".to_string() ); - - // let op = get_brc20_operations_on_block(838964, &db_conns.brc20.unwrap(), &ctx); - // assert_eq!(op.len(), 1); } + + // #[test] + // fn process_block_with_brc20_inscription() { + // let ctx = Context::empty(); + // let mut config = Config::mainnet_default(); + // config.storage.working_dir = "tmp".to_string(); + // config.meta_protocols.brc20 = true; + // drop_sqlite_dbs(&config); + // let mut db_conns = initialize_sqlite_dbs(&config, &ctx); + // let mut next_blocks = vec![new_test_block(vec![new_test_reveal_tx()])]; + // let mut sequence_cursor = SequenceCursor::new(&db_conns.ordinals); + // let cache_l2 = Arc::new(new_traversals_lazy_cache(2048)); + // let mut inscriptions_db_conn_rw = + // open_ordinals_db_rw(&config.expected_cache_path(), &ctx).expect(""); + // let mut brc20_cache = brc20_new_cache(&config); + + // let _ = process_blocks( + // &mut next_blocks, + // &mut sequence_cursor, + // &cache_l2, + // &mut inscriptions_db_conn_rw, + // &mut brc20_cache, + // &mut db_conns.brc20, + // &None, + // &PrometheusMonitoring::new(), + // &config, + // &ctx, + // ); + + // // let op = get_brc20_operations_on_block(838964, &db_conns.brc20.unwrap(), &ctx); + // // assert_eq!(op.len(), 1); + // } } diff --git a/components/ordhook-core/src/core/protocol/inscription_parsing.rs b/components/ordhook-core/src/core/protocol/inscription_parsing.rs index 8d911b14..bf1c4cfe 100644 --- a/components/ordhook-core/src/core/protocol/inscription_parsing.rs +++ b/components/ordhook-core/src/core/protocol/inscription_parsing.rs @@ -247,7 +247,17 @@ mod test { use std::collections::HashMap; use chainhook_sdk::{ - types::{BitcoinBlockData, BitcoinNetwork, OrdinalOperation}, + bitcoin::Amount, + indexer::bitcoin::{ + BitcoinBlockFullBreakdown, BitcoinTransactionFullBreakdown, + BitcoinTransactionInputFullBreakdown, BitcoinTransactionInputPrevoutFullBreakdown, + GetRawTransactionResultVinScriptSig, + }, + types::{ + BitcoinBlockData, BitcoinNetwork, BitcoinTransactionData, + OrdinalInscriptionTransferData, OrdinalInscriptionTransferDestination, + OrdinalOperation, + }, utils::Context, }; @@ -255,10 +265,7 @@ mod test { use crate::{ config::Config, - utils::test_helpers::{ - new_test_block, new_test_raw_block, new_test_reveal_raw_tx, new_test_reveal_tx, - new_test_reveal_tx_with_operation, new_test_transfer_tx_with_operation, - }, + utils::test_helpers::{TestBlockBuilder, TestTransactionBuilder, TestTxInBuilder}, }; use super::{ @@ -266,26 +273,90 @@ mod test { parse_inscriptions_and_standardize_block, parse_inscriptions_in_standardized_block, }; - #[test_case(&new_test_block(vec![]) => 0; "with empty block")] - #[test_case(&new_test_block(vec![new_test_reveal_tx_with_operation()]) => 1; "with reveal transaction")] - #[test_case(&new_test_block(vec![new_test_transfer_tx_with_operation()]) => 0; "with transfer transaction")] + pub fn new_test_transfer_tx_with_operation() -> BitcoinTransactionData { + TestTransactionBuilder::new() + .ordinal_operations(vec![OrdinalOperation::InscriptionTransferred( + OrdinalInscriptionTransferData { + ordinal_number: 300144140535834, + destination: OrdinalInscriptionTransferDestination::Transferred( + "bc1pcwway0ne322s0lrc5e905f3chuclvnyy3z6wn86azkgmgcprf3tqvyy7ws" + .to_string(), + ), + satpoint_pre_transfer: + "ab2683db34e335c89a5c1d634e6c5bd8d8bca8ded281be84f71f921c9e8783b2:0:0" + .to_string(), + satpoint_post_transfer: + "42fa098abab8d5cca1c303a97bd0404cf8e9b8faaab6dd228a309e66daff8fae:1:0" + .to_string(), + post_transfer_output_value: Some(546), + tx_index: 54, + }, + )]) + .build() + } + + pub fn new_test_raw_block( + transactions: Vec, + ) -> BitcoinBlockFullBreakdown { + BitcoinBlockFullBreakdown { + hash: "000000000000000000018ddf8a6484db391fb85c9f9ddc384f03a92729423aaf".to_string(), + height: 838964, + tx: transactions, + time: 1712982301, + nonce: 100, + previousblockhash: Some( + "000000000000000000021f8b96d34c0f223281d7d825dd3588c2858c96e689d4".to_string(), + ), + confirmations: 200, + } + } + + pub fn new_test_reveal_raw_tx() -> BitcoinTransactionFullBreakdown { + BitcoinTransactionFullBreakdown { + txid: "b61b0172d95e266c18aea0c624db987e971a5d6d4ebc2aaed85da4642d635735".to_string(), + vin: vec![BitcoinTransactionInputFullBreakdown { + sequence: 4294967293, + txid: Some("a321c61c83563a377f82ef59301f2527079f6bda7c2d04f9f5954c873f42e8ac".to_string()), + vout: Some(0), + script_sig: Some(GetRawTransactionResultVinScriptSig { hex: "".to_string()}), + txinwitness: Some(vec![ + "6c00eb3c4d35fedd257051333b4ca81d1a25a37a9af4891f1fec2869edd56b14180eafbda8851d63138a724c9b15384bc5f0536de658bd294d426a36212e6f08".to_string(), + "209e2849b90a2353691fccedd467215c88eec89a5d0dcf468e6cf37abed344d746ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d38004c5e7b200a20202270223a20226272632d3230222c0a2020226f70223a20226465706c6f79222c0a2020227469636b223a20226f726469222c0a2020226d6178223a20223231303030303030222c0a2020226c696d223a202231303030220a7d68".to_string(), + "c19e2849b90a2353691fccedd467215c88eec89a5d0dcf468e6cf37abed344d746".to_string(), + ]), + prevout: Some( + BitcoinTransactionInputPrevoutFullBreakdown { height: 779878, value: Amount::from_sat(14830) } + ), + }], + vout: vec![], + } + } + + #[test_case(&TestBlockBuilder::new().build() => 0; "with empty block")] + #[test_case(&TestBlockBuilder::new().transactions(vec![TestTransactionBuilder::new_with_operation().build()]).build() => 1; "with reveal transaction")] + #[test_case(&TestBlockBuilder::new().transactions(vec![new_test_transfer_tx_with_operation()]).build() => 0; "with transfer transaction")] fn gets_reveals_in_block(block: &BitcoinBlockData) -> usize { get_inscriptions_revealed_in_block(block).len() } - #[test_case(&new_test_block(vec![]) => 0; "with empty block")] - #[test_case(&new_test_block(vec![new_test_reveal_tx_with_operation()]) => 0; "with reveal transaction")] - #[test_case(&new_test_block(vec![new_test_transfer_tx_with_operation()]) => 1; "with transfer transaction")] + #[test_case(&TestBlockBuilder::new().build() => 0; "with empty block")] + #[test_case(&TestBlockBuilder::new().transactions(vec![TestTransactionBuilder::new_with_operation().build()]).build() => 0; "with reveal transaction")] + #[test_case(&TestBlockBuilder::new().transactions(vec![new_test_transfer_tx_with_operation()]).build() => 1; "with transfer transaction")] fn gets_transfers_in_block(block: &BitcoinBlockData) -> usize { get_inscriptions_transferred_in_block(block).len() } #[test] fn parses_inscriptions_in_block() { - let mut block = new_test_block(vec![new_test_reveal_tx()]); let ctx = Context::empty(); - let mut config = Config::mainnet_default(); - config.storage.working_dir = "tmp".to_string(); + let config = Config::test_default(); + let mut block = TestBlockBuilder::new() + .add_transaction( + TestTransactionBuilder::new() + .add_input(TestTxInBuilder::new().build()) + .build(), + ) + .build(); parse_inscriptions_in_standardized_block(&mut block, &mut HashMap::new(), &config, &ctx); let OrdinalOperation::InscriptionRevealed(reveal) = &block.transactions[0].metadata.ordinal_operations[0] diff --git a/components/ordhook-core/src/core/protocol/inscription_sequencing.rs b/components/ordhook-core/src/core/protocol/inscription_sequencing.rs index b51dd028..43f7990f 100644 --- a/components/ordhook-core/src/core/protocol/inscription_sequencing.rs +++ b/components/ordhook-core/src/core/protocol/inscription_sequencing.rs @@ -981,10 +981,9 @@ mod test { config::Config, core::protocol::inscription_sequencing::SequenceCursor, db::{ - drop_sqlite_dbs, initialize_sqlite_dbs, - ordinals::update_sequence_metadata_with_block, + drop_all_dbs, initialize_sqlite_dbs, ordinals::update_sequence_metadata_with_block, }, - utils::test_helpers::{new_test_block, new_test_reveal_tx_with_operation}, + utils::test_helpers::{TestBlockBuilder, TestTransactionBuilder}, }; #[test_case((780000, false) => (2, 2); "with blessed pre jubilee")] @@ -994,9 +993,11 @@ mod test { fn picks_next((block_height, cursed): (u64, bool)) -> (i64, i64) { let ctx = Context::empty(); let config = Config::test_default(); - drop_sqlite_dbs(&config); + drop_all_dbs(&config); let db_conns = initialize_sqlite_dbs(&config, &ctx); - let mut block = new_test_block(vec![new_test_reveal_tx_with_operation()]); + let mut block = TestBlockBuilder::new() + .transactions(vec![TestTransactionBuilder::new_with_operation().build()]) + .build(); block.block_identifier.index = block_height; // Pick next twice so we can test all cases. @@ -1026,9 +1027,11 @@ mod test { fn resets_on_previous_block() { let ctx = Context::empty(); let config = Config::test_default(); - drop_sqlite_dbs(&config); + drop_all_dbs(&config); let db_conns = initialize_sqlite_dbs(&config, &ctx); - let block = new_test_block(vec![new_test_reveal_tx_with_operation()]); + let block = TestBlockBuilder::new() + .transactions(vec![TestTransactionBuilder::new_with_operation().build()]) + .build(); update_sequence_metadata_with_block(&block, &db_conns.ordinals, &ctx); let mut cursor = SequenceCursor::new(&db_conns.ordinals); let _ = cursor.pick_next( diff --git a/components/ordhook-core/src/db/blocks.rs b/components/ordhook-core/src/db/blocks.rs index 93d3585e..6bf3f029 100644 --- a/components/ordhook-core/src/db/blocks.rs +++ b/components/ordhook-core/src/db/blocks.rs @@ -234,3 +234,33 @@ pub fn delete_blocks_in_block_range( .put(b"metadata::last_insert", start_block_bytes) .expect("unable to insert metadata"); } + +#[cfg(test)] +pub fn insert_standardized_block( + block: &chainhook_sdk::types::BitcoinBlockData, + blocks_db_rw: &DB, + ctx: &Context, +) { + let block_bytes = match super::cursor::BlockBytesCursor::from_standardized_block(&block) { + Ok(block_bytes) => block_bytes, + Err(e) => { + try_error!( + ctx, + "Unable to compress block #{}: #{}", + block.block_identifier.index, + e.to_string() + ); + return; + } + }; + insert_entry_in_blocks( + block.block_identifier.index as u32, + &block_bytes, + true, + &blocks_db_rw, + &ctx, + ); + if let Err(e) = blocks_db_rw.flush() { + try_error!(ctx, "{}", e.to_string()); + } +} diff --git a/components/ordhook-core/src/db/mod.rs b/components/ordhook-core/src/db/mod.rs index ec988d61..b6c9f72d 100644 --- a/components/ordhook-core/src/db/mod.rs +++ b/components/ordhook-core/src/db/mod.rs @@ -88,21 +88,11 @@ pub fn drop_block_data_from_all_dbs( Ok(()) } +/// Drops DB files in a test environment. #[cfg(test)] -/// Drops SQLite DB files in a test environment. -pub fn drop_sqlite_dbs(config: &Config) { - let Ok(dir) = std::fs::read_dir(&config.expected_cache_path()) else { - return; - }; - for entry in dir { - let entry = entry.unwrap(); - let path = entry.path(); - if path.is_file() { - if let Some(extension) = path.extension().and_then(|ext| ext.to_str()) { - if extension.starts_with("sqlite") { - let _ = std::fs::remove_file(&path); - } - } - } +pub fn drop_all_dbs(config: &Config) { + let dir_path = &config.expected_cache_path(); + if dir_path.exists() { + std::fs::remove_dir_all(dir_path).expect(""); } } diff --git a/components/ordhook-core/src/utils/test_helpers.rs b/components/ordhook-core/src/utils/test_helpers.rs index dce06ae2..7046b767 100644 --- a/components/ordhook-core/src/utils/test_helpers.rs +++ b/components/ordhook-core/src/utils/test_helpers.rs @@ -1,139 +1,84 @@ -use chainhook_sdk::{ - bitcoin::Amount, - indexer::bitcoin::{ - BitcoinBlockFullBreakdown, BitcoinTransactionFullBreakdown, - BitcoinTransactionInputFullBreakdown, BitcoinTransactionInputPrevoutFullBreakdown, - GetRawTransactionResultVinScriptSig, - }, - types::{ - bitcoin::{OutPoint, TxIn}, - BitcoinBlockData, BitcoinBlockMetadata, BitcoinNetwork, BitcoinTransactionData, - BitcoinTransactionMetadata, BlockIdentifier, OrdinalInscriptionNumber, - OrdinalInscriptionRevealData, OrdinalInscriptionTransferData, - OrdinalInscriptionTransferDestination, OrdinalOperation, TransactionIdentifier, - }, +use chainhook_sdk::types::{ + bitcoin::{OutPoint, TxIn, TxOut}, BitcoinBlockData, BitcoinBlockMetadata, BitcoinNetwork, + BitcoinTransactionData, BitcoinTransactionMetadata, BlockIdentifier, OrdinalInscriptionNumber, + OrdinalInscriptionRevealData, OrdinalOperation, TransactionIdentifier, }; -pub fn new_test_block(transactions: Vec) -> BitcoinBlockData { - // Add a coinbase transaction. - let mut txs = vec![BitcoinTransactionData { - transaction_identifier: TransactionIdentifier { - hash: "0xd92cf8bb6f0767a52f82d72365a1bdfbc2009eb2248e945a4d85ae7da81d11c2".to_string(), - }, - operations: vec![], - metadata: BitcoinTransactionMetadata { - inputs: vec![], - outputs: vec![], - ordinal_operations: vec![], - stacks_operations: vec![], - brc20_operation: None, - proof: None, - fee: 0, - index: 0, - }, - }]; - txs.extend(transactions); - BitcoinBlockData { - block_identifier: BlockIdentifier { - index: 838964, +pub struct TestBlockBuilder { + pub height: u64, + pub hash: String, + pub transactions: Vec, +} + +impl TestBlockBuilder { + pub fn new() -> Self { + TestBlockBuilder { + height: 838964, hash: "0x000000000000000000018ddf8a6484db391fb85c9f9ddc384f03a92729423aaf".to_string(), - }, - parent_block_identifier: BlockIdentifier { - hash: "0x000000000000000000021f8b96d34c0f223281d7d825dd3588c2858c96e689d4".to_string(), - index: 838963, - }, - timestamp: 1712982301, - transactions: txs, - metadata: BitcoinBlockMetadata { - network: BitcoinNetwork::Mainnet, - }, + transactions: vec![], + } } -} -pub fn new_test_raw_block( - transactions: Vec, -) -> BitcoinBlockFullBreakdown { - // Add a coinbase transaction. - let mut txs = vec![BitcoinTransactionFullBreakdown { - txid: "d92cf8bb6f0767a52f82d72365a1bdfbc2009eb2248e945a4d85ae7da81d11c2".to_string(), - vin: vec![], - vout: vec![], - }]; - txs.extend(transactions); - BitcoinBlockFullBreakdown { - hash: "000000000000000000018ddf8a6484db391fb85c9f9ddc384f03a92729423aaf".to_string(), - height: 838964, - tx: txs, - time: 1712982301, - nonce: 100, - previousblockhash: Some( - "000000000000000000021f8b96d34c0f223281d7d825dd3588c2858c96e689d4".to_string(), - ), - confirmations: 200, + pub fn height(mut self, height: u64) -> Self { + self.height = height; + self } -} -pub fn new_test_reveal_tx() -> BitcoinTransactionData { - // Represents the `ordi` BRC-20 token deploy. - BitcoinTransactionData { - transaction_identifier: TransactionIdentifier { - hash: "0xb61b0172d95e266c18aea0c624db987e971a5d6d4ebc2aaed85da4642d635735".to_string(), - }, - operations: vec![], - metadata: BitcoinTransactionMetadata { - inputs: vec![ - TxIn { - previous_output: OutPoint { - txid: TransactionIdentifier { hash: "0xa321c61c83563a377f82ef59301f2527079f6bda7c2d04f9f5954c873f42e8ac".to_string() }, - vout: 0, - value: 14830, - block_height: 779878, - }, - script_sig: "".to_string(), - sequence: 4294967293, - witness: vec![ - "0x6c00eb3c4d35fedd257051333b4ca81d1a25a37a9af4891f1fec2869edd56b14180eafbda8851d63138a724c9b15384bc5f0536de658bd294d426a36212e6f08".to_string(), - "0x209e2849b90a2353691fccedd467215c88eec89a5d0dcf468e6cf37abed344d746ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d38004c5e7b200a20202270223a20226272632d3230222c0a2020226f70223a20226465706c6f79222c0a2020227469636b223a20226f726469222c0a2020226d6178223a20223231303030303030222c0a2020226c696d223a202231303030220a7d68".to_string(), - "0xc19e2849b90a2353691fccedd467215c88eec89a5d0dcf468e6cf37abed344d746".to_string(), - ], - }, - ], - outputs: vec![], - ordinal_operations: vec![], - stacks_operations: vec![], - brc20_operation: None, - proof: None, - fee: 0, - index: 0, - }, + pub fn hash(mut self, hash: String) -> Self { + self.hash = hash; + self } -} -pub fn new_test_reveal_raw_tx() -> BitcoinTransactionFullBreakdown { - BitcoinTransactionFullBreakdown { - txid: "b61b0172d95e266c18aea0c624db987e971a5d6d4ebc2aaed85da4642d635735".to_string(), - vin: vec![BitcoinTransactionInputFullBreakdown { - sequence: 4294967293, - txid: Some("a321c61c83563a377f82ef59301f2527079f6bda7c2d04f9f5954c873f42e8ac".to_string()), - vout: Some(0), - script_sig: Some(GetRawTransactionResultVinScriptSig { hex: "".to_string()}), - txinwitness: Some(vec![ - "6c00eb3c4d35fedd257051333b4ca81d1a25a37a9af4891f1fec2869edd56b14180eafbda8851d63138a724c9b15384bc5f0536de658bd294d426a36212e6f08".to_string(), - "209e2849b90a2353691fccedd467215c88eec89a5d0dcf468e6cf37abed344d746ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d38004c5e7b200a20202270223a20226272632d3230222c0a2020226f70223a20226465706c6f79222c0a2020227469636b223a20226f726469222c0a2020226d6178223a20223231303030303030222c0a2020226c696d223a202231303030220a7d68".to_string(), - "c19e2849b90a2353691fccedd467215c88eec89a5d0dcf468e6cf37abed344d746".to_string(), - ]), - prevout: Some( - BitcoinTransactionInputPrevoutFullBreakdown { height: 779878, value: Amount::from_sat(14830) } - ), - }], - vout: vec![], + pub fn transactions(mut self, transactions: Vec) -> Self { + self.transactions = transactions; + self + } + + pub fn add_transaction(mut self, transaction: BitcoinTransactionData) -> Self { + self.transactions.push(transaction); + self } + + pub fn build(&self) -> BitcoinBlockData { + BitcoinBlockData { + block_identifier: BlockIdentifier { + index: self.height, + hash: self.hash.clone(), + }, + parent_block_identifier: BlockIdentifier { + hash: "0x000000000000000000021f8b96d34c0f223281d7d825dd3588c2858c96e689d4" + .to_string(), + index: self.height - 1, + }, + timestamp: 1712982301, + transactions: self.transactions.clone(), + metadata: BitcoinBlockMetadata { + network: BitcoinNetwork::Mainnet, + }, + } + } +} + +pub struct TestTransactionBuilder { + hash: String, + inputs: Vec, + outputs: Vec, + ordinal_operations: Vec, } -pub fn new_test_reveal_tx_with_operation() -> BitcoinTransactionData { - let mut data = new_test_reveal_tx(); - data.metadata.ordinal_operations = vec![ - OrdinalOperation::InscriptionRevealed( +impl TestTransactionBuilder { + pub fn new() -> Self { + TestTransactionBuilder { + hash: "0xb61b0172d95e266c18aea0c624db987e971a5d6d4ebc2aaed85da4642d635735".to_string(), + ordinal_operations: vec![], + inputs: vec![], + outputs: vec![], + } + } + + pub fn new_with_operation() -> Self { + let mut tx = Self::new(); + tx.ordinal_operations = vec![OrdinalOperation::InscriptionRevealed( OrdinalInscriptionRevealData { content_bytes: "0x7b200a20202270223a20226272632d3230222c0a2020226f70223a20226465706c6f79222c0a2020227469636b223a20226f726469222c0a2020226d6178223a20223231303030303030222c0a2020226c696d223a202231303030220a7d".to_string(), content_type: "text/plain;charset=utf-8".to_string(), @@ -157,59 +102,96 @@ pub fn new_test_reveal_tx_with_operation() -> BitcoinTransactionData { satpoint_post_inscription: "".to_string(), curse_type: None, }, - ) - ]; - data -} + )]; + tx + } -pub fn new_test_transfer_tx() -> BitcoinTransactionData { - BitcoinTransactionData { - transaction_identifier: TransactionIdentifier { - hash: "0x42fa098abab8d5cca1c303a97bd0404cf8e9b8faaab6dd228a309e66daff8fae".to_string(), - }, - operations: vec![], - metadata: BitcoinTransactionMetadata { - inputs: vec![ - TxIn { - previous_output: OutPoint { - txid: TransactionIdentifier { hash: "0xab2683db34e335c89a5c1d634e6c5bd8d8bca8ded281be84f71f921c9e8783b2".to_string() }, - vout: 0, - value: 546, - block_height: 779878, - }, - script_sig: "".to_string(), - sequence: 4294967293, - witness: vec![ - "0x17afbd7f7e4b1acff7c8d01ee74fc644ad4b7244559074c46aa0477f8685267b66716486f282e924433ddcf864fe4538d3514b084f3011edfc38223b8724a122".to_string(), - ], - }, - ], - outputs: vec![], - ordinal_operations: vec![], - stacks_operations: vec![], - brc20_operation: None, - proof: None, - fee: 0, - index: 0, - }, + pub fn hash(mut self, hash: String) -> Self { + self.hash = hash; + self + } + + pub fn inputs(mut self, inputs: Vec) -> Self { + self.inputs = inputs; + self + } + + pub fn add_input(mut self, input: TxIn) -> Self { + self.inputs.push(input); + self } + + pub fn outputs(mut self, outputs: Vec) -> Self { + self.outputs = outputs; + self + } + + pub fn add_output(mut self, output: TxOut) -> Self { + self.outputs.push(output); + self + } + + pub fn ordinal_operations(mut self, ordinal_operations: Vec) -> Self { + self.ordinal_operations = ordinal_operations; + self + } + + pub fn build(self) -> BitcoinTransactionData { + BitcoinTransactionData { + transaction_identifier: TransactionIdentifier { hash: self.hash }, + operations: vec![], + metadata: BitcoinTransactionMetadata { + inputs: self.inputs, + outputs: self.outputs, + ordinal_operations: self.ordinal_operations, + stacks_operations: vec![], + brc20_operation: None, + proof: None, + fee: 0, + index: 0, + }, + } + } +} + +pub struct TestTxInBuilder { + prev_out_block_height: u64, + prev_out_tx_hash: String, } -pub fn new_test_transfer_tx_with_operation() -> BitcoinTransactionData { - let mut data = new_test_transfer_tx(); - data.metadata.ordinal_operations = vec![OrdinalOperation::InscriptionTransferred( - OrdinalInscriptionTransferData { - ordinal_number: 300144140535834, - destination: OrdinalInscriptionTransferDestination::Transferred( - "bc1pcwway0ne322s0lrc5e905f3chuclvnyy3z6wn86azkgmgcprf3tqvyy7ws".to_string(), - ), - satpoint_pre_transfer: - "ab2683db34e335c89a5c1d634e6c5bd8d8bca8ded281be84f71f921c9e8783b2:0:0".to_string(), - satpoint_post_transfer: - "42fa098abab8d5cca1c303a97bd0404cf8e9b8faaab6dd228a309e66daff8fae:1:0".to_string(), - post_transfer_output_value: Some(546), - tx_index: 54, - }, - )]; - data +impl TestTxInBuilder { + pub fn new() -> Self { + TestTxInBuilder { + prev_out_block_height: 849999, + prev_out_tx_hash: "0xa321c61c83563a377f82ef59301f2527079f6bda7c2d04f9f5954c873f42e8ac".to_string(), + } + } + + pub fn prev_out_block_height(mut self, block_height: u64) -> Self { + self.prev_out_block_height = block_height; + self + } + + pub fn prev_out_tx_hash(mut self, hash: String) -> Self { + self.prev_out_tx_hash = hash; + self + } + + pub fn build(self) -> TxIn { + TxIn { + previous_output: OutPoint { + txid: TransactionIdentifier { hash: self.prev_out_tx_hash }, + vout: 0, + value: 10000, + block_height: self.prev_out_block_height, + }, + script_sig: "".to_string(), + sequence: 4294967293, + witness: vec![ + "0x6c00eb3c4d35fedd257051333b4ca81d1a25a37a9af4891f1fec2869edd56b14180eafbda8851d63138a724c9b15384bc5f0536de658bd294d426a36212e6f08".to_string(), + "0x209e2849b90a2353691fccedd467215c88eec89a5d0dcf468e6cf37abed344d746ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d38004c5e7b200a20202270223a20226272632d3230222c0a2020226f70223a20226465706c6f79222c0a2020227469636b223a20226f726469222c0a2020226d6178223a20223231303030303030222c0a2020226c696d223a202231303030220a7d68".to_string(), + "0xc19e2849b90a2353691fccedd467215c88eec89a5d0dcf468e6cf37abed344d746".to_string(), + ], + } + } }