From 42b497ff6503bf363da79c920cb11d1ac54a0868 Mon Sep 17 00:00:00 2001 From: nym21 Date: Sat, 4 Apr 2026 12:16:15 +0200 Subject: [PATCH] server: ms endpoint fixes --- crates/brk_client/src/lib.rs | 2 +- crates/brk_query/src/impl/block/txs.rs | 7 +------ crates/brk_types/src/lib.rs | 2 ++ crates/brk_types/src/tx.rs | 7 ++++--- crates/brk_types/src/tx_version_raw.rs | 16 +++++++++++++++ crates/brk_types/src/txin.rs | 24 +++++++++++++++++----- modules/brk-client/index.js | 11 ++++++++-- modules/brk-client/package.json | 2 +- packages/brk_client/brk_client/__init__.py | 14 ++++++++----- packages/brk_client/pyproject.toml | 2 +- 10 files changed, 63 insertions(+), 24 deletions(-) create mode 100644 crates/brk_types/src/tx_version_raw.rs diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index be9f53f65..ec85be58a 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -8198,7 +8198,7 @@ pub struct BrkClient { impl BrkClient { /// Client version. - pub const VERSION: &'static str = "v0.3.0-alpha.3"; + pub const VERSION: &'static str = "v0.3.0-alpha.4"; /// Create a new client with the given base URL. pub fn new(base_url: impl Into) -> Self { diff --git a/crates/brk_query/src/impl/block/txs.rs b/crates/brk_query/src/impl/block/txs.rs index 9cb9bc8ad..3d295ed3b 100644 --- a/crates/brk_query/src/impl/block/txs.rs +++ b/crates/brk_query/src/impl/block/txs.rs @@ -53,11 +53,6 @@ impl Query { .transactions .height .collect_range_at(start, end); - let versions = indexer - .vecs - .transactions - .tx_version - .collect_range_at(start, end); let lock_times = indexer .vecs .transactions @@ -185,7 +180,7 @@ impl Query { let mut transaction = Transaction { index: Some(TxIndex::from(start + i)), txid: txids[i].clone(), - version: versions[i], + version: tx.version.into(), lock_time: lock_times[i], total_size: *total_sizes[i] as usize, weight, diff --git a/crates/brk_types/src/lib.rs b/crates/brk_types/src/lib.rs index ddab00d99..4bef38aaf 100644 --- a/crates/brk_types/src/lib.rs +++ b/crates/brk_types/src/lib.rs @@ -171,6 +171,7 @@ mod tx; mod tx_index; mod tx_status; mod tx_version; +mod tx_version_raw; mod tx_with_hex; mod txid; mod txid_prefix; @@ -361,6 +362,7 @@ pub use tx::*; pub use tx_index::*; pub use tx_status::*; pub use tx_version::*; +pub use tx_version_raw::*; pub use tx_with_hex::*; pub use txid::*; pub use txid_prefix::*; diff --git a/crates/brk_types/src/tx.rs b/crates/brk_types/src/tx.rs index c0a291766..d20b831be 100644 --- a/crates/brk_types/src/tx.rs +++ b/crates/brk_types/src/tx.rs @@ -1,5 +1,6 @@ use crate::{ - FeeRate, RawLockTime, Sats, TxIn, TxIndex, TxOut, TxStatus, TxVersion, Txid, VSize, Weight, + FeeRate, RawLockTime, Sats, TxIn, TxIndex, TxOut, TxStatus, TxVersionRaw, Txid, VSize, + Weight, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -16,9 +17,9 @@ pub struct Transaction { #[schemars(example = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")] pub txid: Txid, - /// Transaction version + /// Transaction version (raw i32 from Bitcoin protocol, may contain non-standard values in coinbase txs) #[schemars(example = 2)] - pub version: TxVersion, + pub version: TxVersionRaw, /// Transaction lock time #[schemars(example = 0)] diff --git a/crates/brk_types/src/tx_version_raw.rs b/crates/brk_types/src/tx_version_raw.rs new file mode 100644 index 000000000..87e1fc6dd --- /dev/null +++ b/crates/brk_types/src/tx_version_raw.rs @@ -0,0 +1,16 @@ +use derive_more::Deref; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +/// Raw transaction version (i32) from Bitcoin protocol. +/// Unlike TxVersion (u8, indexed), this preserves non-standard values +/// used in coinbase txs for miner signaling/branding. +#[derive(Debug, Deref, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +pub struct TxVersionRaw(i32); + +impl From for TxVersionRaw { + #[inline] + fn from(value: bitcoin::transaction::Version) -> Self { + Self(value.0) + } +} diff --git a/crates/brk_types/src/txin.rs b/crates/brk_types/src/txin.rs index 50f6f1fc5..7f7a525cc 100644 --- a/crates/brk_types/src/txin.rs +++ b/crates/brk_types/src/txin.rs @@ -54,8 +54,12 @@ impl Serialize for TxIn { let has_witness = !self.witness.is_empty(); let has_scriptsig = !self.script_sig.is_empty(); - // P2SH-wrapped SegWit: both scriptsig and witness present (not coinbase) - let inner_redeem = if has_scriptsig && has_witness && !self.is_coinbase { + // P2SH / P2SH-wrapped SegWit: extract redeemscript from scriptsig + let is_p2sh = self + .prevout + .as_ref() + .is_some_and(|p| p.script_pubkey.is_p2sh()); + let inner_redeem = if has_scriptsig && is_p2sh && !self.is_coinbase { self.script_sig .redeem_script() .map(|s| s.to_asm_string()) @@ -64,10 +68,20 @@ impl Serialize for TxIn { String::new() }; - // P2WSH / P2SH-P2WSH: witness has >2 items, last is the witnessScript + // P2WSH/P2SH-P2WSH: last witness item is the witnessScript + // P2TR script path: second-to-last is the script, last is the control block + let is_p2tr = self + .prevout + .as_ref() + .is_some_and(|p| p.script_pubkey.is_p2tr()); let inner_witness = if has_witness && self.witness.len() > 2 { - if let Some(last) = self.witness.last() { - let bytes: Vec = bitcoin::hex::FromHex::from_hex(last).unwrap_or_default(); + let script_hex = if is_p2tr { + self.witness.get(self.witness.len() - 2) + } else { + self.witness.last() + }; + if let Some(hex) = script_hex { + let bytes: Vec = bitcoin::hex::FromHex::from_hex(hex).unwrap_or_default(); ScriptBuf::from(bytes).to_asm_string() } else { String::new() diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index a8d32eef0..b8a24a86a 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -1004,7 +1004,7 @@ * @typedef {Object} Transaction * @property {(TxIndex|null)=} index - Internal transaction index (brk-specific, not in mempool.space) * @property {Txid} txid - Transaction ID - * @property {TxVersion} version - Transaction version + * @property {TxVersionRaw} version - Transaction version (raw i32 from Bitcoin protocol, may contain non-standard values in coinbase txs) * @property {RawLockTime} locktime - Transaction lock time * @property {TxIn[]} vin - Transaction inputs * @property {TxOut[]} vout - Transaction outputs @@ -1067,6 +1067,13 @@ * * @typedef {number} TxVersion */ +/** + * Raw transaction version (i32) from Bitcoin protocol. + * Unlike TxVersion (u8, indexed), this preserves non-standard values + * used in coinbase txs for miner signaling/branding. + * + * @typedef {number} TxVersionRaw + */ /** * Transaction ID (hash) * @@ -6566,7 +6573,7 @@ function createTransferPattern(client, acc) { * @extends BrkClientBase */ class BrkClient extends BrkClientBase { - VERSION = "v0.3.0-alpha.3"; + VERSION = "v0.3.0-alpha.4"; INDEXES = /** @type {const} */ ([ "minute10", diff --git a/modules/brk-client/package.json b/modules/brk-client/package.json index c8d625439..7ea33c9ea 100644 --- a/modules/brk-client/package.json +++ b/modules/brk-client/package.json @@ -40,5 +40,5 @@ "url": "git+https://github.com/bitcoinresearchkit/brk.git" }, "type": "module", - "version": "0.3.0-alpha.3" + "version": "0.3.0-alpha.4" } diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index d2b526d0d..c213ca787 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -198,12 +198,16 @@ StoredU64 = int TimePeriod = Literal["24h", "3d", "1w", "1m", "3m", "6m", "1y", "2y", "3y"] # Index of the output being spent in the previous transaction Vout = int -# Transaction version number -TxVersion = int +# Raw transaction version (i32) from Bitcoin protocol. +# Unlike TxVersion (u8, indexed), this preserves non-standard values +# used in coinbase txs for miner signaling/branding. +TxVersionRaw = int TxInIndex = int TxOutIndex = int # Input index in the spending transaction Vin = int +# Transaction version number +TxVersion = int UnknownOutputIndex = TypeIndex Week1 = int Year1 = int @@ -1380,7 +1384,7 @@ class Transaction(TypedDict): Attributes: index: Internal transaction index (brk-specific, not in mempool.space) txid: Transaction ID - version: Transaction version + version: Transaction version (raw i32 from Bitcoin protocol, may contain non-standard values in coinbase txs) locktime: Transaction lock time vin: Transaction inputs vout: Transaction outputs @@ -1392,7 +1396,7 @@ class Transaction(TypedDict): """ index: Union[TxIndex, None] txid: Txid - version: TxVersion + version: TxVersionRaw locktime: RawLockTime vin: List[TxIn] vout: List[TxOut] @@ -6007,7 +6011,7 @@ class SeriesTree: class BrkClient(BrkClientBase): """Main BRK client with series tree and API methods.""" - VERSION = "v0.3.0-alpha.3" + VERSION = "v0.3.0-alpha.4" INDEXES = [ "minute10", diff --git a/packages/brk_client/pyproject.toml b/packages/brk_client/pyproject.toml index d6210e050..ad378c749 100644 --- a/packages/brk_client/pyproject.toml +++ b/packages/brk_client/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "brk-client" -version = "0.3.0-alpha.3" +version = "0.3.0-alpha.4" description = "Bitcoin on-chain analytics client — thousands of metrics, block explorer, and address index" readme = "README.md" requires-python = ">=3.9"