diff --git a/Cargo.lock b/Cargo.lock index f4f4266..9fa44b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,7 +86,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" dependencies = [ "bitcoin-internals", - "bitcoin_hashes", + "bitcoin_hashes 0.14.1", ] [[package]] @@ -107,12 +107,24 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "bech32" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" +[[package]] +name = "bimap" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" + [[package]] name = "bindex" version = "0.0.18" @@ -125,6 +137,9 @@ dependencies = [ "rayon", "rusqlite", "rust-rocksdb", + "serde", + "serde_json", + "silentpayments", "tempfile", "thiserror", "ureq", @@ -171,12 +186,12 @@ checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ "base58ck", "base64 0.21.7", - "bech32", + "bech32 0.11.1", "bitcoin-internals", "bitcoin-io", "bitcoin-units", - "bitcoin_hashes", - "hex-conservative", + "bitcoin_hashes 0.14.1", + "hex-conservative 0.2.2", "hex_lit", "secp256k1", "serde", @@ -207,6 +222,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoin_hashes" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446819536d8121575eeb7e89efdbadb3f055e87e4bb66c6679a6d5cc2f4b64fd" +dependencies = [ + "hex-conservative 0.1.2", +] + [[package]] name = "bitcoin_hashes" version = "0.14.1" @@ -214,7 +238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ "bitcoin-io", - "hex-conservative", + "hex-conservative 0.2.2", "serde", ] @@ -225,7 +249,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943d4257fdfc85afe2a13d2b539a5213e97bb978329dd79b624acbce73042fb" dependencies = [ "bitcoin", - "bitcoin_hashes", + "bitcoin_hashes 0.14.1", ] [[package]] @@ -529,6 +553,21 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + [[package]] name = "hex-conservative" version = "0.2.2" @@ -928,7 +967,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.14.1", "secp256k1-sys", "serde", ] @@ -991,6 +1030,19 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "silentpayments" +version = "0.5.0" +source = "git+https://github.com/cygnet3/spdk?rev=ce68148d8621e58a33abe251e28b7587b04998dd#ce68148d8621e58a33abe251e28b7587b04998dd" +dependencies = [ + "bech32 0.9.1", + "bimap", + "bitcoin_hashes 0.13.1", + "hex", + "secp256k1", + "serde", +] + [[package]] name = "smallvec" version = "1.15.1" diff --git a/bindex-lib/Cargo.toml b/bindex-lib/Cargo.toml index c909800..477488b 100644 --- a/bindex-lib/Cargo.toml +++ b/bindex-lib/Cargo.toml @@ -28,4 +28,7 @@ rust-rocksdb = { version = "0.36.0", default-features = false, features = ["zstd hex_lit = "0.1" # bitcoind path should be specified via BITCOIND_EXE corepc-node = { version = "0.10", default-features = false, features = ["29_0"] } +serde = "1.0" +serde_json = "1.0" tempfile = "3" +silentpayments = { git = "https://github.com/cygnet3/spdk", rev = "ce68148d8621e58a33abe251e28b7587b04998dd" } diff --git a/bindex-lib/src/chain.rs b/bindex-lib/src/chain.rs index d376516..26d73c2 100644 --- a/bindex-lib/src/chain.rs +++ b/bindex-lib/src/chain.rs @@ -252,7 +252,7 @@ impl IndexedChain { use rayon::prelude::*; let mut batches = Vec::with_capacity(headers.len()); - for chunk in headers.chunks(10) { + for chunk in headers.chunks(128) { let items: Vec<_> = chunk .par_iter() .map(|header| self.fetch_data(header.block_hash())) @@ -287,10 +287,8 @@ impl IndexedChain { for batch in batches { self.headers.add(batch.header); } - - stats.elapsed = t.elapsed(); if stats.indexed_blocks > 0 { - self.store.flush()?; + stats.elapsed = t.elapsed(); info!( "block={} height={}: indexed {} blocks, {:.3}[MB], dt = {:.3}[s]: {:.3} [ms/block], {:.3} [MB/block], {:.3} [MB/s]", self.headers.tip_hash(), @@ -302,6 +300,7 @@ impl IndexedChain { stats.size_read as f64 / (1e6 * stats.indexed_blocks as f64), stats.size_read as f64 / (1e6 * stats.elapsed.as_secs_f64()), ); + self.store.flush()?; } else { // Start autocompactions when there are no new indexed blocks self.store.start_compactions()?; diff --git a/bindex-lib/src/db.rs b/bindex-lib/src/db.rs index 69fd6b0..91e2b77 100644 --- a/bindex-lib/src/db.rs +++ b/bindex-lib/src/db.rs @@ -35,8 +35,9 @@ const HEADERS_CF: &str = "headers"; const SCRIPT_HASH_CF: &str = "script_hash"; const TXPOS_CF: &str = "txpos"; const TXID_CF: &str = "txid"; +const SPTWEAK_CF: &str = "sptweak"; -const COLUMN_FAMILIES: &[&str] = &[HEADERS_CF, TXPOS_CF, TXID_CF, SCRIPT_HASH_CF]; +const COLUMN_FAMILIES: &[&str] = &[HEADERS_CF, TXPOS_CF, TXID_CF, SPTWEAK_CF, SCRIPT_HASH_CF]; fn cf_descriptors( opts: &rocksdb::Options, @@ -114,6 +115,18 @@ impl DB { .map(index::TxBlockPosRow::serialize) .for_each(|(k, v)| f(&mut write_batch, cf, &k, &v)); + // key = next_txnum || txid_prefix || tweak + let cf = self.cf(SPTWEAK_CF); + // Batch are grouped by `txnum`. + for batch in batches { + let mut rows: Vec<&index::TxTweakRow> = batch.sptweak_rows.iter().collect(); + // Sort row group by `txid` prefix. + rows.sort_unstable_by_key(|item| &item.txid); + for row in rows { + f(&mut write_batch, cf, &row.serialize(&batch.header), b""); + } + } + // key = next_txnum, value = blockhash || blockheader let cf = self.cf(HEADERS_CF); for batch in batches { diff --git a/bindex-lib/src/index/mod.rs b/bindex-lib/src/index/mod.rs index bc5affc..47cf51b 100644 --- a/bindex-lib/src/index/mod.rs +++ b/bindex-lib/src/index/mod.rs @@ -1,5 +1,6 @@ mod header; mod scripthash; +mod sptweak; mod txid; mod txpos; @@ -8,6 +9,7 @@ use bitcoin_slices::bsl; pub use header::IndexedHeader; pub use scripthash::ScriptHash; +pub use sptweak::TxTweakRow; pub use txpos::{TxBlockPos, TxBlockPosRow}; #[derive(thiserror::Error, Debug)] @@ -150,6 +152,14 @@ impl BlockBytes { pub fn txs_count(&self) -> u32 { parse_txs_count(&self.0[bitcoin::block::Header::SIZE..]) } + + #[cfg(test)] + pub fn txdata(&self) -> Vec { + use bitcoin::consensus::encode::deserialize; + + let block: bitcoin::Block = deserialize(&self.0).expect("invalid block"); + block.txdata + } } pub struct SpentBytes(Vec); @@ -194,6 +204,7 @@ pub struct Batch { pub scripthash_rows: Vec, pub txid_rows: Vec, pub txpos_rows: Vec, + pub sptweak_rows: Vec, pub header: IndexedHeader, } @@ -208,16 +219,19 @@ impl Batch { let scripthash = scripthash::index(block, spent, first_txnum)?; let txpos = txpos::index(block, first_txnum)?; let txid = txid::index(block, first_txnum)?; + let sptweak = sptweak::index(block, spent, first_txnum)?; // All must have the same number of transactions assert_eq!(txnum_range.next, scripthash.next_txnum); assert_eq!(txnum_range.next, txpos.next_txnum); assert_eq!(txnum_range.next, txid.next_txnum); + assert_eq!(txnum_range.next, sptweak.next_txnum); Ok(Batch { scripthash_rows: scripthash.rows, txpos_rows: txpos.rows, txid_rows: txid.rows, + sptweak_rows: sptweak.rows, header: IndexedHeader::new(txnum_range.next, blockhash, block), }) } diff --git a/bindex-lib/src/index/sptweak.rs b/bindex-lib/src/index/sptweak.rs new file mode 100644 index 0000000..cb01821 --- /dev/null +++ b/bindex-lib/src/index/sptweak.rs @@ -0,0 +1,490 @@ +use bitcoin::{consensus::Decodable, secp256k1, Transaction, Txid}; +use bitcoin::{ + hashes::{sha256t_hash_newtype, Hash, HashEngine}, + OutPoint, +}; +use secp256k1::{PublicKey, Scalar, XOnlyPublicKey}; + +use crate::index::{self, BlockBytes, Error, IndexedBlock, SpentBytes, TxNum}; + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +pub struct TxTweakRow { + pub txid: Txid, + pub tweak: PublicKey, +} + +impl TxTweakRow { + const TXID_PREFIX_LEN: usize = 8; + const KEY_LEN: usize = TxNum::LEN + Self::TXID_PREFIX_LEN; + const LEN: usize = Self::KEY_LEN + secp256k1::constants::PUBLIC_KEY_SIZE; + + pub fn serialize(&self, header: &index::IndexedHeader) -> [u8; Self::LEN] { + let mut key = [0; Self::LEN]; + // group by block height + order by txid prefix + + key[..TxNum::LEN].copy_from_slice(&header.next_txnum().serialize()); + key[TxNum::LEN..Self::KEY_LEN].copy_from_slice(&self.txid[..Self::TXID_PREFIX_LEN]); + key[Self::KEY_LEN..].copy_from_slice(&self.tweak.serialize()); + key + } +} + +struct PerInput<'a> { + outpoint: &'a OutPoint, + pubkey: PublicKey, +} + +impl<'a> PerInput<'a> { + fn new(txin: &'a bitcoin::TxIn, pubkey: PublicKey) -> Self { + Self { + outpoint: &txin.previous_output, + pubkey, + } + } + + fn combine(self, other: PerInput<'a>) -> Result { + Ok(PerInput { + outpoint: self.outpoint.min(other.outpoint), + pubkey: self.pubkey.combine(&other.pubkey)?, + }) + } +} + +pub fn index( + block: &BlockBytes, + spent: &SpentBytes, + next_txnum: TxNum, +) -> Result, Error> { + let secp = secp256k1::Secp256k1::verification_only(); // OPTIMIZE + let mut result = IndexedBlock::new(next_txnum); + let block = bitcoin::Block::consensus_decode_from_finite_reader(&mut &block.0[..])?; + let spent = decode_spent(&spent.0)?; + assert_eq!(block.txdata.len(), spent.len()); + for (tx, txouts_spent) in block.txdata.into_iter().zip(spent.into_iter()) { + result.next_txnum.increment_by(1); + if !maybe_silent_payment(&tx) { + // no taproot outputs, or coinbase + continue; + } + assert_eq!(tx.input.len(), txouts_spent.len()); + // let per_input_entries = tx.input.into_iter().zip(txouts_spent.into_iter()); + // Iterate through each input of the transaction and collect its eligible pubkey: + let per_input_entries = tx + .input + .iter() + .zip(txouts_spent.into_iter()) + .filter_map(|(txin, spent_txout)| get_pubkey_from_input(txin, spent_txout).transpose()); + + // Reduce into (smallest_outpoint, A_sum) pair: + let total = match per_input_entries.into_iter().reduce(|a, b| a?.combine(b?)) { + Some(Ok(total)) => total, + Some(Err(err)) => { + log::warn!("skipping {}: {}", tx.compute_txid(), err); + continue; + } + None => continue, + }; + // Calculate the tweak data based on the public keys and outpoints + let tweak = compute_tweak(total, &secp); + let txid = tx.compute_txid(); + result.rows.push(TxTweakRow { txid, tweak }); + } + Ok(result) +} + +fn maybe_silent_payment(tx: &Transaction) -> bool { + if tx.is_coinbase() { + return false; + } + tx.output.iter().any(|txo| txo.script_pubkey.is_p2tr()) +} + +fn compute_tweak(total: PerInput, secp: &secp256k1::Secp256k1) -> PublicKey { + let PerInput { + outpoint: smallest_outpoint, + pubkey: sum_pubkeys, + } = total; + let input_hash = InputsHash::new(smallest_outpoint, sum_pubkeys).to_scalar(); + sum_pubkeys + .mul_tweak(secp, &input_hash) + .expect("`mul_tweak()` failed") +} + +sha256t_hash_newtype! { + pub(crate) struct InputsTag = hash_str("BIP0352/Inputs"); + + /// BIP0352-tagged hash with tag \"Inputs\". + /// + /// This is used for computing the inputs hash. + #[hash_newtype(forward)] + pub(crate) struct InputsHash(_); +} + +impl InputsHash { + fn new(smallest_outpoint: &OutPoint, sum_pubkeys: PublicKey) -> InputsHash { + let mut eng = InputsHash::engine(); + eng.input(&smallest_outpoint.txid[..]); + eng.input(&smallest_outpoint.vout.to_le_bytes()); + eng.input(&sum_pubkeys.serialize()); + InputsHash::from_engine(eng) + } + fn to_scalar(self) -> Scalar { + // This is statistically extremely unlikely to panic. + Scalar::from_be_bytes(self.to_byte_array()).expect("hash value greater than curve order") + } +} + +fn decode_spent(buf: &[u8]) -> Result>, Error> { + let mut r = bitcoin::io::Cursor::new(buf); + let txs_count = bitcoin::VarInt::consensus_decode_from_finite_reader(&mut r)?.0 as usize; + let mut block_result = Vec::with_capacity(txs_count); + for _ in 0..txs_count { + let outputs_count = + bitcoin::VarInt::consensus_decode_from_finite_reader(&mut r)?.0 as usize; + let mut tx_result = Vec::with_capacity(outputs_count); + for _ in 0..outputs_count { + let output = bitcoin::TxOut::consensus_decode_from_finite_reader(&mut r)?; + tx_result.push(output); + } + block_result.push(tx_result); + } + Ok(block_result) +} + +// !!! The code below has been vendored from https://github.com/cygnet3/spdk/blob/ce68148d8621e58a33abe251e28b7587b04998dd/silentpayments/src/utils/receiving.rs !!! + +/// [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki)-defined 'Nothing Up My Sleeve' point. +pub const NUMS_H: [u8; 32] = [ + 0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e, + 0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0, +]; + +// Define OP_CODES used in script template matching for readability +const OP_1: u8 = 0x51; +const OP_0: u8 = 0x00; +const OP_PUSHBYTES_20: u8 = 0x14; +const OP_PUSHBYTES_32: u8 = 0x20; +const OP_HASH160: u8 = 0xA9; +const OP_EQUAL: u8 = 0x87; +const OP_DUP: u8 = 0x76; +const OP_EQUALVERIFY: u8 = 0x88; +const OP_CHECKSIG: u8 = 0xAC; + +// Only compressed pubkeys are supported for silent payments +const COMPRESSED_PUBKEY_SIZE: usize = 33; + +#[derive(thiserror::Error, Debug)] +enum SpError { + #[error("invalid vin: {0}")] + InvalidVin(&'static str), + #[error("secp256k1 error: {0}")] + Secp256k1Error(#[from] secp256k1::Error), +} + +/// Get the public keys from a set of input data. +/// +/// # Arguments +/// +/// * `script_sig` - The script signature as a byte array. +/// * `txinwitness` - The witness data. +/// * `script_pub_key` - The scriptpubkey from the output spent. This requires looking up the previous output. +/// +/// # Returns +/// +/// If no errors occur, this function will optionally return a [PublicKey] if this input is silent payment-eligible. +/// +/// # Errors +/// +/// This function will error if: +/// +/// * The provided Vin data is incorrect. +fn get_pubkey_from_input( + txin: &bitcoin::TxIn, + spent_txout: bitcoin::TxOut, +) -> Result>, SpError> { + use bitcoin::hashes::{hash160, Hash}; + + let txinwitness = &txin.witness; + let script_sig = txin.script_sig.as_bytes(); + let script_pub_key = spent_txout.script_pubkey.as_bytes(); + + if is_p2pkh(script_pub_key) { + match (txinwitness.is_empty(), script_sig.is_empty()) { + (true, false) => { + let spk_hash = &script_pub_key[3..23]; + for i in (COMPRESSED_PUBKEY_SIZE..=script_sig.len()).rev() { + if let Some(pubkey_bytes) = script_sig.get(i - COMPRESSED_PUBKEY_SIZE..i) { + let pubkey_hash = hash160::Hash::hash(pubkey_bytes); + if &pubkey_hash[..] == spk_hash { + let pubkey = PublicKey::from_slice(pubkey_bytes) + .map_err(SpError::Secp256k1Error)?; + return Ok(Some(PerInput::new(txin, pubkey))); + } + } else { + return Ok(None); + } + } + } + (_, true) => return Err(SpError::InvalidVin("Empty script_sig for spending a p2pkh")), + (false, _) => { + return Err(SpError::InvalidVin( + "non empty witness for spending a p2pkh", + )) + } + } + } else if is_p2sh(script_pub_key) { + match (txinwitness.is_empty(), script_sig.is_empty()) { + (false, false) => { + let redeem_script = &script_sig[1..]; + if is_p2wpkh(redeem_script) { + if let Some(value) = txinwitness.last() { + match ( + PublicKey::from_slice(value), + value.len() == COMPRESSED_PUBKEY_SIZE, + ) { + (Ok(pubkey), true) => { + return Ok(Some(PerInput::new(txin, pubkey))); + } + (_, false) => { + return Ok(None); + } + // Not sure how we could get an error here, so just return none for now + // if the pubkey cant be parsed + (Err(_), _) => { + return Ok(None); + } + } + } + } + } + (_, true) => return Err(SpError::InvalidVin("Empty script_sig for spending a p2sh")), + (true, false) => return Ok(None), + } + } else if is_p2wpkh(script_pub_key) { + match (txinwitness.is_empty(), script_sig.is_empty()) { + (false, true) => { + if let Some(value) = txinwitness.last() { + match ( + PublicKey::from_slice(value), + value.len() == COMPRESSED_PUBKEY_SIZE, + ) { + (Ok(pubkey), true) => { + return Ok(Some(PerInput::new(txin, pubkey))); + } + (_, false) => { + return Ok(None); + } + // Not sure how we could get an error here, so just return none for now + // if the pubkey cant be parsed + (Err(_), _) => { + return Ok(None); + } + } + } else { + return Err(SpError::InvalidVin("Empty witness")); + } + } + (_, false) => { + return Err(SpError::InvalidVin( + "Non empty script sig for spending a segwit output", + )) + } + (true, _) => { + return Err(SpError::InvalidVin( + "Empty witness for spending a segwit output", + )) + } + } + } else if is_p2tr(script_pub_key) { + match (txinwitness.is_empty(), script_sig.is_empty()) { + (false, true) => { + // check for the optional annex + let annex = match txinwitness.last().and_then(|value| value.first()) { + Some(&0x50) => 1, + Some(_) => 0, + None => return Err(SpError::InvalidVin("Empty or invalid witness")), + }; + + // Check for script path + let stack_size = txinwitness.len(); + if stack_size > annex && txinwitness[stack_size - annex - 1][1..33] == NUMS_H { + return Ok(None); + } + + // Return the pubkey from the script pubkey + return XOnlyPublicKey::from_slice(&script_pub_key[2..34]) + .map_err(SpError::Secp256k1Error) + .map(|x_only_public_key| { + Some(PerInput::new( + txin, + x_only_public_key.public_key(secp256k1::Parity::Even), + )) + }); + } + (_, false) => { + return Err(SpError::InvalidVin( + "Non empty script sig for spending a segwit output", + )) + } + (true, _) => { + return Err(SpError::InvalidVin( + "Empty witness for spending a segwit output", + )) + } + } + } + Ok(None) +} + +// script templates for inputs allowed in BIP352 shared secret derivation + +/// Check if a script_pub_key is taproot. +fn is_p2tr(spk: &[u8]) -> bool { + matches!(spk, [OP_1, OP_PUSHBYTES_32, ..] if spk.len() == 34) +} + +fn is_p2wpkh(spk: &[u8]) -> bool { + matches!(spk, [OP_0, OP_PUSHBYTES_20, ..] if spk.len() == 22) +} + +fn is_p2sh(spk: &[u8]) -> bool { + matches!(spk, [OP_HASH160, OP_PUSHBYTES_20, .., OP_EQUAL] if spk.len() == 23) +} + +fn is_p2pkh(spk: &[u8]) -> bool { + matches!(spk, [OP_DUP, OP_HASH160, OP_PUSHBYTES_20, .., OP_EQUALVERIFY, OP_CHECKSIG] if spk.len() == 25) +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + use std::path::Path; + + use bitcoin::{hex::prelude::*, key::TweakedPublicKey, ScriptBuf}; + use hex_lit::hex; + use secp256k1::SecretKey; + use serde::Deserialize; + + use super::*; + + #[derive(Deserialize)] + struct TestVector { + bip352_tweaks: Vec, + } + + impl TestVector { + fn read>(path: P) -> Result> { + let data = std::fs::read(path)?; + Ok(serde_json::from_slice(&data)?) + } + + fn assert_equal(&self, indexed: &IndexedBlock) { + assert_eq!(self.bip352_tweaks.len(), indexed.rows.len()); + for (hex_tweak, row) in self.bip352_tweaks.iter().zip(&indexed.rows) { + assert_eq!(*hex_tweak, row.tweak.serialize().to_lower_hex_string()); + } + } + } + + #[test] + fn test_index_signet_block_200000() -> Result<(), Box> { + const TXS_COUNT: u32 = 141; + + // Generated by `curl -v http://localhost:38332/rest/block/0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.bin`. + let block_bytes = BlockBytes(std::fs::read("src/tests/signet/block_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.bin")?); + assert_eq!(block_bytes.txs_count(), TXS_COUNT); + + // Generated by `curl -v http://localhost:38332/rest/spenttxouts/000000182c6f19960871023d851d2b758fc1123aa14645c56666e54673386780.bin`. + let spent_bytes = SpentBytes(std::fs::read("src/tests/signet/spent_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.bin")?); + assert_eq!(spent_bytes.txs_count(), TXS_COUNT); + + let mut txnum = TxNum(100000); + let indexed = index(&block_bytes, &spent_bytes, txnum)?; + txnum.increment_by(TXS_COUNT); + assert_eq!(indexed.next_txnum, txnum); + + // Generated by `bitcoin-cli -signet getsilentpaymentblockdata 0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c`. + // (https://github.com/Sjors/bitcoin/pull/86/changes/03ce1ad0a58c044937f51d67e5cad5ccc3f206b0) + TestVector::read("src/tests/signet/bip352_tweaks_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.json")?.assert_equal(&indexed); + Ok(()) + } + + #[test] + fn test_scan_signet_block_295125() -> Result<(), Box> { + let secp = secp256k1::Secp256k1::new(); // TODO + + let block_bytes = BlockBytes(std::fs::read("src/tests/signet/block_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.bin")?); + let spent_bytes = SpentBytes(std::fs::read("src/tests/signet/spent_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.bin")?); + let indexed = index(&block_bytes, &spent_bytes, TxNum::default())?; + assert_eq!(indexed.next_txnum, TxNum(68)); + TestVector::read("src/tests/signet/bip352_tweaks_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.json")?.assert_equal(&indexed); + + let scan_sk = SecretKey::from_slice(&[0x01; 32]).unwrap(); + let scan_pk = scan_sk.public_key(&secp); + let spend_sk = SecretKey::from_slice(&[0x02; 32]).unwrap(); + let spend_pk = spend_sk.public_key(&secp); + + use silentpayments::receiving::{Label, Receiver}; + + let change_label = Label::new(scan_sk, 0); + let recv = Receiver::new( + 0, + scan_pk, + spend_pk, + change_label, + silentpayments::Network::Testnet, + )?; + + let txs: HashMap = block_bytes + .txdata() + .into_iter() + .map(|tx| (tx.compute_txid(), tx)) + .collect(); + + let mut found = HashMap::, Vec<(XOnlyPublicKey, Scalar)>>::new(); + for row in indexed.rows { + let txouts = &txs.get(&row.txid).expect("missing tx").output[..]; + let shared = row.tweak.mul_tweak(&secp, &scan_sk.into()).unwrap(); + // Scan transaction for relevant P2TR public keys and key tweaks + let matches = recv.scan_transaction(&shared, p2tr_pubkeys(&txouts))?; + for (label, items) in matches { + found.entry(label).or_default().extend(items.into_iter()); + } + } + assert_eq!(found.len(), 1); + let pubkey = XOnlyPublicKey::from_slice(&hex!( + "dbd93fdd869e3522405749a594c2e3f4833ac98d0f4e70da6e7294f6623258c3" + )) + .unwrap(); + let tweak = Scalar::from_be_bytes(hex!( + "78258954dccdba6597729dab70068bc4353ebd046f7156d9a3f8db8438b62aa5" + )) + .unwrap(); + assert_eq!(found, HashMap::from_iter([(None, vec![(pubkey, tweak)])])); + + // Verify that tweaked spending secret key matches tweaked public key + let tweaked_spend_sk = spend_sk.add_tweak(&tweak).unwrap(); + let tweaked_spend_pk = tweaked_spend_sk.x_only_public_key(&secp).0; + assert_eq!(tweaked_spend_pk, pubkey); + + // Verify the relevant transaction (93a9b81f81244f8e6be29d8d6b0a9dbe6d6de6d2d4b018001ebf855bc870be88): + assert_eq!( + block_bytes.txdata()[33].output[0].script_pubkey, + ScriptBuf::new_p2tr_tweaked(TweakedPublicKey::dangerous_assume_tweaked(pubkey)) + ); + Ok(()) + } + + fn p2tr_pubkeys(txos: &[bitcoin::TxOut]) -> Vec { + txos.iter() + .filter_map(|txo| { + let script = &txo.script_pubkey; + if !script.is_p2tr() { + return None; + } + let bytes = &script.as_bytes()[2..]; + Some(XOnlyPublicKey::from_slice(bytes).expect("invalid public key")) + }) + .collect() + } +} diff --git a/bindex-lib/src/tests/signet/bip352_tweaks_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.json b/bindex-lib/src/tests/signet/bip352_tweaks_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.json new file mode 100644 index 0000000..d6e3c17 --- /dev/null +++ b/bindex-lib/src/tests/signet/bip352_tweaks_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.json @@ -0,0 +1,45 @@ +{ + "bip352_tweaks": [ + "022d383831d3f689d94e44b906801d6fea6f98bf8d17e7ef0b49ec5515dd105702", + "035991fb9d25be112cad28e562a70e5a4c27f56fd7abdeab4eace2059368efa416", + "026aa748d7237396fbc32106e239804b0964a15b323aa15d2d9d43101d5726bc09", + "038a3fa263797330fad2a672632f40586e4d4cf0d5c08722ee3ca053a2952e3012", + "0219c549bc9c4fb4a24899d13e800746af15eceb33cb9924340163fb1334c6d15f", + "039edecdce943720eb28567a72b44bc8d93546ba817457e818cd6bac36b5e7219d", + "025e2501b6d12f07eb711b6c34a8ac16ff779026c96858334650c74da1c3593caf", + "03cbfe148d589f721a8c7e19efd3e995e031d3a4c738f099687bfc0056d08d75bb", + "036a07996051db70d0229e8f19b045d4498c07dac13a9ab4c40134e2f1f6430521", + "026003edb12a497984bfa6f1cbb78a54f2c0b149863358eb3bd35219d72f5dd67b", + "0350c67fec92c55a9df97e0e302788bc187ab0a254c172558338230e1fef65fa06", + "03b2680a3c5f68e51a275ac98180f737662fe3f45d3b74ce5d4ee1c70b908f345b", + "0390554e8aa0154cc528048ff44a593bf0b884a3bde14c8befe8ac37d61d51544f", + "030b5ab98a026781783130d6324e112abba9e2ac77a4a6914da8d62aa7b26501bd", + "03c831f8afad6c819c9bf04528a2e308f6ebee5e2a51d0168e73d9c74bff94fb68", + "035bd0e67734121fcb64c8f6c377c69fa2ca80403cd4efd3d8a55579086ace31c8", + "0383f6f4a90d2923709ee2b58660ad7c660af7451a7019c77b763c32b63ad7d622", + "02c69288357ad98bf076ae4ee330203036c82fa7c8ddcdfa1079f4bbd3076da048", + "02294a7a5ecf578915a64adb8ad8425d386d02d8a01a4b4b114a145a7ee714a8a6", + "02e6275c8bb15e040e20e43ddc8ca4fed9560332850c52f370437b9f0f340aef5b", + "0368cdbadf7533556e61b028f093965891c040b3ef2d4da4faa8bf4779f3c588c4", + "027f5510cb82d5c4131c2f87fd63f52242e74fb4deea6507b4ce79faa2975080b1", + "02ceb3b2c7cd93eafe804572d4c4a68f3e414550a76e463c277044bb907bd2ee2e", + "02b5f742bc0797e946d1116d7a7b307a5ab8ebd6dce5feeb0b0298c291cf9ef6cf", + "026c26c9269b0c2e80111041c697d94b3794e28c9ee16a23e227ece99a2080a44b", + "02c9770ef6fa5b37ae4fc9ba96cea5a01916f86534bf70fb825a9c8d0f1a5e7229", + "03aa7a0b46173bb065b18540531a322d867658c3d83f4f814463314e1bff49cf41", + "03bec2bc1aa51d7358e0f953a111d065e23199a412dcf1c2fca97dc8f31fc51e29", + "03dbcf1530095f02b2a6224dbbae374ff6c5530f23302520d9f0ec3212e3f86317", + "023420725706137fe7ee3c23075d89b85f1820f7b7705e6b07f70daa19e2c6220c", + "03f0670573266838a53b6ffdffa39ddc33434ddccf7586f5f6509d839d4afd6f2c", + "0219c926ccb4bb4951a1d135ad5026dee31cd9b8223ee4c856020fbc64f4e7bdee", + "03c0ab6f8eb36b632e2cd11e335047bd79509d24579203cee218ebec36a31424df", + "02b3c053a3062e080442934dd68e4af2d19ca7db4f20a540fa617a4720d80adf40", + "0334732e4dd68b76886a4946b45362e1215bfbf97022f7fb1c9c5dc3bd6620982c", + "03d503aca25df261584ae2f8301c5396e424c383c1579669fb8948067bb4bf2d92", + "03dc78d61786ba913ad9fb092affc2e5bb8c9116b46c9afaf447bc98234bb9dd53", + "03666dc73e06cacbfd5be9075c0b02f480bbf2704aa01fa0e7a8285d35691017af", + "033c2b09193fabc90899a3544689f7c9c87e63e09d4c885fcf5a741e570f7b6831", + "03ae62b23c656554382b575be8769cfe50d3aadf032defaa4e211fc7c4b360a34d", + "03ece0b9796b140486fb9e575b036ff60d83137d2655c521ba4a0f782636473a2b" + ] +} diff --git a/bindex-lib/src/tests/signet/bip352_tweaks_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.json b/bindex-lib/src/tests/signet/bip352_tweaks_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.json new file mode 100644 index 0000000..00790bf --- /dev/null +++ b/bindex-lib/src/tests/signet/bip352_tweaks_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.json @@ -0,0 +1,137 @@ +{ + "bip352_tweaks": [ + "02c9c9bb0f8fa49b5764f270422167efd670b8b04136197fa63ebe4373368c00c4", + "0366e880f4692ede6566623f5b281e42383eb5b95e320daff3553f96d57f2a3feb", + "030704f3420f149449c560579504638f939447027eaa6d4ff5da29a97bd27dfb17", + "03c2d2819be65672792877837979a7d96e36d5cadb3265c7673c240f88a9a4ddaf", + "02ce9b5b1964cf1aa4ed3d90976a61410d54247eaeba84198546597eed510372e7", + "03e4f93bb98c65e9883993ab79a043900b8f53a1b42b071bda8baf7f06c753c6c4", + "0316f0e50d31b9de603f49d6885b6f0dcdb8d3665142eb56829afa43e39fb7597d", + "03ddc2f478ffa0c68d36a127fd849be7b6e8a4c6e90f01a81b89e306aa8fd04f78", + "026d2b50668aa7a984f15770cbf36d45e6ffb005b85ef0231e99d6a0883ed81a51", + "032a7bdb54702ac4de644d6ff8e4dce56614962e25bbd844df24235ccc45c8f5d3", + "02c2447bd83405c73d575652c98a657c5f6b13ba41310f7b4cac2702c32e48be45", + "036f6ed72058da780dd656985fe221e14baa6f60af04c7bdcaa0444a30c2a47a0d", + "0258f8eb1fc01e2d9a568a84b42abea378ac66a60988304da52d75732106021ad8", + "02b3bbdd0935f99b08131f6737919a3644b1bd03cbbb7733a64e7d1a437d020337", + "0251a6e4369d95b1e8405d5916d51dee2eb1aa0ece7180e181957e8b21e952f216", + "026323d754a42b9a83ece5fce2c8bddae7b852fe2c5ec5d548a49576c22ac9b71c", + "023a65e36c86441044a1caa8d2f34960d5c9e14d674a4899698b8b21567a6e2d46", + "0271beefbf630b67b6d70b7f0456577a184b0df31b47ff03920cdc1f6c5594c3c1", + "02ee54e6405635a6ca58b59ae97e42dca7257f75e08a9facd2940348b8681aad1f", + "0310c2ee7d47daae8c7c9473d3cbaf316b5340fb11dcf887a0c57b92e85ede2530", + "02dd4e48ad3b9614844a5fa4ab25b616bdf0ca1e301914b001b219154ddb9adb4f", + "022996a98ee8e3d479f1abd0a9049c3a33bd7339ba20f6f2494c5a394e4a46748d", + "030eff7ad74348ae7efb0988f6380424ecc8054b6106d0e76d09e59e4acbb92b0b", + "03b7574fb604bb47a3e0327beeff1c375acb80a263aabb88deebff62c312915293", + "02f8e7d7bc4e0c23e10a57777be27ceea8cd33a3ab7446b616c4aaff1dd403a69d", + "021016db808e78aba8a691962c94580441e260ba8ae21bbff255f81d34b7985f08", + "022759558e4ba8028237822539f76356282170f969d2d876b1aef69c4ae32528f2", + "02433cb67b8072170ead3aad80882fa8786b62f6ee26bedf8ff8863f2cc16d967d", + "038000615515c9478b79d3c7122c60494b747306812639d57f1bdce9b133970c48", + "037093fde98aad30bd59413c92fdb1b751662ba71148fe41e06b8f32f1b4802e48", + "03fd2c80ceda3ca4917498db0a3f0f80e96933873673b4cbe8f9486295b5f1d4db", + "03cb187bbfaa0f32ff89539db03d58a3f295befce6081fc0dd858dc293b25d0a47", + "02222d381b3803cac0eb58f11dca602342ea836650a7d64640d4c4aac388c811ab", + "03e5457796bf604d9a7e21499506169b3232af52aa80e8c7aa01e512fd2d5db9c4", + "02084685528b2e03452eefb2225e8a177c739fb52ec331ba0e7e135146af283fe4", + "0202c6acd88b9f1695cc65a3ef870e0f1628279d4fce54baece651b530b05db9e1", + "03e7be9884e4ca3818b8db65b6f50d31a5fdb9a201817d879fb3e6718aa32f0d91", + "038138a86c5f194d77f9177d28979286bee590f69a8d446208fd7347d304fd278f", + "0256192ca85ae444b54b89dd3bf86141d0c3c5277ccd6f6a09ed539b7e27603084", + "03fb42e4e7cf46ad7526257b6fae07f0af543b83bbf90b6c4ff05b190bb5c034bf", + "028b9a21fdd6d6ce29d41afa87ccd153b0b26996dfde85d3cdbb7831aa7654395e", + "02e3489bd491018a4eba5be626bf4f2bd2734343fc3d985f844ac3e2bed2f1df02", + "027ed731c43a0caecbf8708e0dad0b273fb3851ee2008fa2cf0319b0d2f86ca624", + "02c117f84d69b6b09882dd4e3e5f1b45097a450caeeaa1fc3e6317b591a5481ee5", + "0331a1ad83bacd4f30619dab34bae33784b4a0296071e361b6bf6477f019f86abf", + "03a8d8c12b513fb7e65e119526ce36439688f8c96fb3b5afe73210a6ba2a386593", + "03972fd270e295591a2167aaf6eacc560cc856b5f5154c1878a44b624d4c8e6238", + "032c247b76f7b70f70d2923ba10a865e8a1044fc01f44c1d9f5c11664e27737523", + "02a0014937d01335b5d2b5cfd0fd6f9d0eedfec43dbd20da03b5cb6b86521dde43", + "023e84f37a4a6a95ada3e01b1fa927472522db22b651427b240f4d283a79980403", + "03bab083cf584dcd91891b939de6cdbe7bef4f0ec195001a3603c24b3a4751147a", + "0237e648dd9aee98c2f382b71c4394b678d78e650593b075ac7a2ff6adc0bcda99", + "0260f174ae6d7f60d7bd546a35e6f8d1b7eef26f85b58cd42ded3a7f04d6219e4b", + "02bb0a19ec30c25d0848c44b7a32b278fc8763905399182a9a3e1dd726ae68e9fb", + "03ec88e79fb4862d55cfac97321d19d6d9b1ea046919b96eb1a3e7b8d29465ed40", + "03f033a2c645ed20d3ecd71a7fbf3da56b5618a5e171c94061a4fa3d365d2fd663", + "035fdd2fbb3d9a22f5b9cea7d3e328d2fd2eb66c3d2ac5a9d24118db2355a129f5", + "036cdcb77a6d06a9cee0565dafe926c8b498c4bab7483615c4027e9c15f70e3bc0", + "03cdd4899fd3d66b4828773c17eb525c945c854b6b18eb113017196a09fe708470", + "0289b5e8948d23459c8f922922d056cef4fe2e5bb0a0a28ed7f3ceb76084644892", + "0235e7a9de22616072730eb42a02868eb536a2453a8dc2993ccb177777ba0eb5f2", + "0201c1c7326a046c478e381d247eeeb2d5e2c98a54fdbb31cd0feaba26af9d1c8d", + "0265498ad722424c660764452f3951de5e2787a505fcfbfd56cc154bbf7a4e3bd3", + "03e234a3ec81e65ea5dce6e4c4f24abc4129b5aecb03576f7e438c1ab53b3c3105", + "03fab2ac486726cce36bdfeac029cfecb78728f9c40ee3b62a66bb459533b99406", + "030f95f733365b4258301b363228a396db32b09a5e240450154306d24cdd7eee82", + "0398f913843fd319bc6514e48174a542eefeeed7d27ab7d89266ef1551ad55c5ab", + "03705b4f5518e09eca1ab5c0b7887b9054233b75e3d2b64d8e657d88fb76660fe4", + "025c3556997b7a14387d2365c3840c642063e066dc21be4b8317aed889e1e73921", + "03d502d6ae7428752e621c44fa47f6eb4ae40a3759a50f2e1519d64d0e90db3423", + "02881f8c5d3333b275083aeb4abe53c6d1a27828de7f55b13a6c749fe2bb3b54ea", + "022f4a2268d81b24aaaea54b7dc0bc15caa2b9bc449cd1943aee9df0e26ee17fa5", + "02eb8c6cf5efa49038d0e860b7222099d314c8b19f99003cdf5df43dfa80bf147d", + "034cc01ddfecc2da162186f3a05d36b137ce96b270a1bfd84a9f1147d0991fab1d", + "0353daeec86093fafb2c6c96c35e24d38677cd8e098a5eb9aadfdca97088cc49c3", + "034a279ab495321bb5e18b9c30fd3251bf2b9bf0161e6b019ea689b3853ecea319", + "030ce42b735439577e5ad1224c46125730f913862b47aa4443904e313431f01663", + "028a2a492bfbbc79feba2f8901edc009a85d8586bedb5fa1388e51d92302b648c1", + "03761483ed7ebc1a74c0a5fd141990fee076913d5272534f46f26c66cbcd81c23c", + "03858c3bf6cfcaea514729ed3a5f22aedcf09df3682271f9e4fafc8eec193c8e09", + "025ddaf0f80d24c052b27eb780c4ba826d8fc3cb26e432be9b0f1086247af8487f", + "0303eb410d05d5ef78f3a7d586f13a2d6e8170a24dc4429162642ccdbdaed33288", + "02d7ad98021f6cd989fa3877972cce6d7b87218a3bfb35aab7f07024eb97a5db3d", + "02f15aedd02bd340c2794b39cbcf670647ca17cbfe4afb258ffd36bcddbae3411a", + "03b8857c65024d4d1b8ad66bea0d2799b81ccec0e950bb2c9da0cb009e07e184d9", + "039941f4d7fb5f0df2c51e89d6e25b2e7f45740d6999ee93fae7714b687b09fd1c", + "033d588c745f0ffcfd32cc071d5a10c6b6b29280a2b5cf812eea8df17a7324a39c", + "0271a5b1f152953958da45f07dffe4822a223c54a1805d6e87d6e75d0b9bd970a1", + "03f2c6db54cb3253ba608fc56cde630790f30f1c5c323ee4516b51c11ab39adaa1", + "03c65e00a4fba30534370846006c2257bad216109f17dd1f3815ae4e0d4022159e", + "038c8d0fedb9181665dfe3fb12650f79f368e5dfe7a93c843bf0bbe5925b044195", + "02ee2f8ee415bdffeae56611ae3c7f726fb0dfaf1fc57d9853b6e88c6ab77ec75e", + "0246681b89eb8cf62381007275667095ea9a935a90a654196921f49426b8659c6a", + "0259cf283026e962be0cd2d13d7c0211309fe3aeccc3e61bb792da08ef3bf46fdb", + "0357db4f7881743ad33e2f5b861957fae024e872dc94a3a08cf148424b01102786", + "0263a32a727dec6f97cda1043473dd243a92e377bacc244ad09c9958373dce82bb", + "02a11406abb94316f1ee3fee837af6c6b97486e3b938f712ac87aec030e16c4907", + "02869df18b8720a62c0e1e62792622c142d065613379ab093cc240047e6d4b08a3", + "0325fc187462b2186d3905fc8d60892ce2ce0b9dc4a1bb055590a5f08ec7cffbd1", + "030d210c4ac195d760e1dbbfea93abda6376b78a3202aaa33541bfe41300191381", + "02555073a3269162a2d5249ebd1c4c86048e72be8966c74157fb573fcd7c5b7100", + "02e95bfb6b13d086da146621275588b5baacf477d299672fc876b9f52bb8fd651c", + "0318cd2021b62599653aaf1835efa935672b9d40cf2be4998e062f9db58b37e8c2", + "021a957fe1b7d92bd21b3e512140e281f10d6665f9b52c601124e9e5b656a0ca8c", + "0241db6680bde1daf76066d48921a7f96a58944d6cbafa732650cd3e4f5b67169f", + "02d91743e0096a27170433d467b07da9e31460d1a780c3a873a06c9b21113fa01c", + "03368cbca3f6ac55b918075ae9b099a800039c30c6586b5dd1164475a6e1335c3f", + "03d990de185a4d92d95d93f53d2edd267a9d0e9a1dcf26f39daeee417517c8b468", + "029f422caaa27b89a3503f294cc562ca2022e7a56e47c12dd712dea4cb6a9ce434", + "0243c2f5fabb2f780feae7b7b2541aea5992a8e0e16d35e610e66fc7ee3cca6a23", + "03a7afb1d1f17f2412bcd3695e76b33cbaa8691916bc6dd975c13586ace80deaed", + "03be0b834d17ac5544fc1aed69d05558c43c7683538289ed7afa3ff851ceba9b40", + "035effa2318e1903e7a6dc91b48c33f15923da1f6a76bd90e9099e6b7596e74b37", + "039041f0d5ff6c5cd622b82c5646f47365d086fc039113d3b2c88a1a8c5df9cb1f", + "020013dc06002d3e29329d77d499e21fa6f91acab357d37fd584c6e504c4072fcc", + "03f95fcb3f028f9a442b40a6e9fac648f6991dfdf74fbe960ff603e557bb70afff", + "03b2a6821fd7fd922d2d1b01a86943682a6dfc09e138ceb5487b96f3b8206be174", + "02c9db11e0f7fbed82494850251a5fc4c6a4b1d6c7e20f2b4e62587058231dd0bb", + "03734286dfa6ab9d49ab62f32e62d40efb62a20e21c1556ce769b2e9435b0b8622", + "0237bf777276886f535301404bd6e66f2c20bfb24f118da63dd3a3c8087fa1e5ca", + "034a76a1e0402993e08f17f93c5f3aa55234f6aca41d2a7466037be2b6787707b9", + "027f9aebed86b24ba9aa98ee1db7cb08088cbc51bd3d0783f5fdfba108224ee87b", + "027e0bac3567ed4fae71c5801f6b9dff875cce37eada972180318b32cc2043dd6d", + "03ce9091820e60cd67e9e83cb8fa68f082159f965bde3dae6c817ae4894e18d611", + "03fe6c26f0bb4556a1859f94258d0ee4567a7c9ac3b93578de34108e089b0b61c0", + "039c0ac051541b22a75e85b32d77734c5d87e42caa45b20aeaddd47914806e3202", + "02e2fbfb9ac5200da2a639fa124589761169c4db6274dec4b177b8f9bc057ca182", + "03b4a78783c0e78e1eeff3da6a5f5686f69fadd816fce0b2ccdde797842f9d4c51", + "03905bf5fb95ff41ef7eb16bf2c44f254031067f729ed8f324acad092f16982d48", + "034c1eab5dc472b0ad1427282e250755682b73a1d2d370549e493ccefb2ef460b0", + "036d2bc52b826a63691ec72a6c28699c97be64e2e6ea7a53f017e4099a1d22a08a", + "0305e2a46486e45e9b603388a25ed27d42ae899ebf2867537de337672e1db41254", + "028963170ea21fea0494210b48a93f046e71a40451cbe159e83e2d17de6a56866f" + ] +} diff --git a/bindex-lib/src/tests/signet/block_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.bin b/bindex-lib/src/tests/signet/block_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.bin new file mode 100644 index 0000000..b93d3f6 Binary files /dev/null and b/bindex-lib/src/tests/signet/block_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.bin differ diff --git a/bindex-lib/src/tests/signet/block_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.bin b/bindex-lib/src/tests/signet/block_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.bin new file mode 100644 index 0000000..cec8bed Binary files /dev/null and b/bindex-lib/src/tests/signet/block_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.bin differ diff --git a/bindex-lib/src/tests/signet/spent_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.bin b/bindex-lib/src/tests/signet/spent_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.bin new file mode 100644 index 0000000..75f891a Binary files /dev/null and b/bindex-lib/src/tests/signet/spent_00000012c5a8005cd56f2cb97334b038fc6dc442c1c1682ba9065e4402b3eaa0.bin differ diff --git a/bindex-lib/src/tests/signet/spent_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.bin b/bindex-lib/src/tests/signet/spent_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.bin new file mode 100644 index 0000000..86d2947 Binary files /dev/null and b/bindex-lib/src/tests/signet/spent_0000007d60f5ffc47975418ac8331c0ea52cf551730ef7ead7ff9082a536f13c.bin differ diff --git a/bindex.sh b/bindex.sh index 7698a63..dd7f084 100755 --- a/bindex.sh +++ b/bindex.sh @@ -4,6 +4,6 @@ set -eux export RUST_LOG=${RUST_LOG:-info} cargo +stable build --release --all --locked -ARGS="--db-path ./db" +ARGS="--db-path ./__db_sptweaks" ulimit -n 8192 target/release/bindex-cli $ARGS $*