mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
indexer: moved to addri->txindex and addri->outpoint indexing from addri->txoutindex
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -683,6 +683,7 @@ dependencies = [
|
||||
name = "brk_grouper"
|
||||
version = "0.0.111"
|
||||
dependencies = [
|
||||
"brk_error",
|
||||
"brk_structs",
|
||||
"brk_traversable",
|
||||
"vecdb",
|
||||
|
||||
@@ -10,6 +10,7 @@ rust-version.workspace = true
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
brk_error = { workspace = true }
|
||||
brk_structs = { workspace = true }
|
||||
brk_traversable = { workspace = true }
|
||||
vecdb = { workspace = true }
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_structs::OutputType;
|
||||
use brk_traversable::{Traversable, TreeNode};
|
||||
use vecdb::AnyCollectableVec;
|
||||
|
||||
use super::{Filter, Filtered};
|
||||
|
||||
pub const P2PK65: &str = "p2pk65";
|
||||
pub const P2PK33: &str = "p2pk33";
|
||||
pub const P2PKH: &str = "p2pkh";
|
||||
pub const P2SH: &str = "p2sh";
|
||||
pub const P2WPKH: &str = "p2wpkh";
|
||||
pub const P2WSH: &str = "p2wsh";
|
||||
pub const P2TR: &str = "p2tr";
|
||||
pub const P2A: &str = "p2a";
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct ByAddressType<T> {
|
||||
pub p2pk65: T,
|
||||
@@ -19,6 +29,22 @@ pub struct ByAddressType<T> {
|
||||
}
|
||||
|
||||
impl<T> ByAddressType<T> {
|
||||
pub fn new<F>(f: F) -> Result<Self>
|
||||
where
|
||||
F: Fn(&'static str) -> Result<T>,
|
||||
{
|
||||
Ok(Self {
|
||||
p2pk65: f(P2PK65)?,
|
||||
p2pk33: f(P2PK33)?,
|
||||
p2pkh: f(P2PKH)?,
|
||||
p2sh: f(P2SH)?,
|
||||
p2wpkh: f(P2WPKH)?,
|
||||
p2wsh: f(P2WSH)?,
|
||||
p2tr: f(P2TR)?,
|
||||
p2a: f(P2A)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_unwrap(&self, address_type: OutputType) -> &T {
|
||||
self.get(address_type).unwrap()
|
||||
}
|
||||
@@ -200,14 +226,14 @@ impl<T: Traversable> Traversable for ByAddressType<T> {
|
||||
fn to_tree_node(&self) -> TreeNode {
|
||||
TreeNode::Branch(
|
||||
[
|
||||
("p2pk65", &self.p2pk65),
|
||||
("p2pk33", &self.p2pk33),
|
||||
("p2pkh", &self.p2pkh),
|
||||
("p2sh", &self.p2sh),
|
||||
("p2wpkh", &self.p2wpkh),
|
||||
("p2wsh", &self.p2wsh),
|
||||
("p2tr", &self.p2tr),
|
||||
("p2a", &self.p2a),
|
||||
(P2PK65, &self.p2pk65),
|
||||
(P2PK33, &self.p2pk33),
|
||||
(P2PKH, &self.p2pkh),
|
||||
(P2SH, &self.p2sh),
|
||||
(P2WPKH, &self.p2wpkh),
|
||||
(P2WSH, &self.p2wsh),
|
||||
(P2TR, &self.p2tr),
|
||||
(P2A, &self.p2a),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|(name, field)| (name.to_string(), field.to_tree_node()))
|
||||
|
||||
@@ -50,6 +50,6 @@ fn main() -> Result<()> {
|
||||
indexer.index(&parser, rpc, &exit, true)?;
|
||||
dbg!(i.elapsed());
|
||||
|
||||
sleep(Duration::from_secs(5 * 60));
|
||||
sleep(Duration::from_secs(60));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use bitcoincore_rpc::Client;
|
||||
use brk_error::{Error, Result};
|
||||
use brk_structs::{
|
||||
BlockHash, CheckedSub, EmptyOutputIndex, Height, TxInIndex, OpReturnIndex, TxOutIndex,
|
||||
OutputType, P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex, P2PK65AddressIndex,
|
||||
P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex,
|
||||
TxIndex, TypeIndex, UnknownOutputIndex,
|
||||
BlockHash, CheckedSub, EmptyOutputIndex, Height, OpReturnIndex, OutputType, P2AAddressIndex,
|
||||
P2MSOutputIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex,
|
||||
P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, TxInIndex, TxIndex, TxOutIndex,
|
||||
TypeIndex, UnknownOutputIndex,
|
||||
};
|
||||
use vecdb::{
|
||||
AnyIterableVec, AnyStoredIterableVec, GenericStoredVec, StoredIndex, StoredRaw, VecIterator,
|
||||
@@ -234,7 +234,7 @@ impl TryFrom<(&mut Vecs, &Stores, &Client)> for Indexes {
|
||||
|
||||
let txinindex = starting_index(
|
||||
&vecs.height_to_first_txinindex,
|
||||
&vecs.txinindex_to_txoutindex,
|
||||
&vecs.txinindex_to_outpoint,
|
||||
height,
|
||||
)
|
||||
.ok_or(Error::Str(""))?;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
use std::{collections::BTreeMap, path::Path, str::FromStr, time::Instant};
|
||||
use std::{collections::BTreeMap, path::Path, str::FromStr, thread, time::Instant};
|
||||
|
||||
use bitcoin::{Transaction, TxIn, TxOut};
|
||||
use brk_error::{Error, Result};
|
||||
use brk_store::AnyStore;
|
||||
use brk_structs::{
|
||||
AddressBytes, AddressBytesHash, BlockHashPrefix, Height, OutputType, Sats, StoredBool,
|
||||
Timestamp, TxInIndex, TxIndex, TxOutIndex, Txid, TxidPrefix, TypeIndex,
|
||||
TypeIndexWithOutputindex, Unit, Version, Vin, Vout,
|
||||
AddressBytes, AddressBytesHash, BlockHashPrefix, Height, OutPoint, OutputType, Sats,
|
||||
StoredBool, Timestamp, TxInIndex, TxIndex, TxOutIndex, Txid, TxidPrefix, TypeIndex,
|
||||
TypeIndexAndOutPoint, TypeIndexAndTxIndex, Unit, Version, Vin, Vout,
|
||||
};
|
||||
use log::{error, info};
|
||||
use rayon::prelude::*;
|
||||
@@ -39,11 +39,18 @@ impl Indexer {
|
||||
|
||||
let path = outputs_dir.join("indexed");
|
||||
|
||||
let vecs = Vecs::forced_import(&path, VERSION)?;
|
||||
info!("Imported vecs");
|
||||
let (vecs, stores) = thread::scope(|s| -> Result<_> {
|
||||
let vecs = s.spawn(|| -> Result<_> {
|
||||
let vecs = Vecs::forced_import(&path, VERSION)?;
|
||||
info!("Imported vecs");
|
||||
Ok(vecs)
|
||||
});
|
||||
|
||||
let stores = Stores::forced_import(&path, VERSION)?;
|
||||
info!("Imported stores");
|
||||
let stores = Stores::forced_import(&path, VERSION)?;
|
||||
info!("Imported stores");
|
||||
|
||||
Ok((vecs.join().unwrap()?, stores))
|
||||
})?;
|
||||
|
||||
Ok(Self { vecs, stores })
|
||||
}
|
||||
@@ -103,6 +110,8 @@ impl Indexer {
|
||||
};
|
||||
|
||||
let mut txindex_to_first_txoutindex_reader_opt = None;
|
||||
let mut txoutindex_to_outputtype_reader_opt = None;
|
||||
let mut txoutindex_to_typeindex_reader_opt = None;
|
||||
let mut p2pk65addressindex_to_p2pk65bytes_reader_opt = None;
|
||||
let mut p2pk33addressindex_to_p2pk33bytes_reader_opt = None;
|
||||
let mut p2pkhaddressindex_to_p2pkhbytes_reader_opt = None;
|
||||
@@ -115,6 +124,8 @@ impl Indexer {
|
||||
let reset_readers =
|
||||
|vecs: &mut Vecs,
|
||||
txindex_to_first_txoutindex_reader_opt: &mut Option<Reader<'static>>,
|
||||
txoutindex_to_outputtype_reader_opt: &mut Option<Reader<'static>>,
|
||||
txoutindex_to_typeindex_reader_opt: &mut Option<Reader<'static>>,
|
||||
p2pk65addressindex_to_p2pk65bytes_reader_opt: &mut Option<Reader<'static>>,
|
||||
p2pk33addressindex_to_p2pk33bytes_reader_opt: &mut Option<Reader<'static>>,
|
||||
p2pkhaddressindex_to_p2pkhbytes_reader_opt: &mut Option<Reader<'static>>,
|
||||
@@ -125,6 +136,10 @@ impl Indexer {
|
||||
p2aaddressindex_to_p2abytes_reader_opt: &mut Option<Reader<'static>>| {
|
||||
txindex_to_first_txoutindex_reader_opt
|
||||
.replace(vecs.txindex_to_first_txoutindex.create_static_reader());
|
||||
txoutindex_to_outputtype_reader_opt
|
||||
.replace(vecs.txoutindex_to_outputtype.create_static_reader());
|
||||
txoutindex_to_typeindex_reader_opt
|
||||
.replace(vecs.txoutindex_to_value.create_static_reader());
|
||||
p2pk65addressindex_to_p2pk65bytes_reader_opt.replace(
|
||||
vecs.p2pk65addressindex_to_p2pk65bytes
|
||||
.create_static_reader(),
|
||||
@@ -152,6 +167,8 @@ impl Indexer {
|
||||
reset_readers(
|
||||
vecs,
|
||||
&mut txindex_to_first_txoutindex_reader_opt,
|
||||
&mut txoutindex_to_outputtype_reader_opt,
|
||||
&mut txoutindex_to_typeindex_reader_opt,
|
||||
&mut p2pk65addressindex_to_p2pk65bytes_reader_opt,
|
||||
&mut p2pk33addressindex_to_p2pk33bytes_reader_opt,
|
||||
&mut p2pkhaddressindex_to_p2pkhbytes_reader_opt,
|
||||
@@ -172,6 +189,8 @@ impl Indexer {
|
||||
idxs.height = height;
|
||||
|
||||
let txindex_to_first_txoutindex_reader = txindex_to_first_txoutindex_reader_opt.as_ref().unwrap();
|
||||
let txoutindex_to_outputtype_reader = txoutindex_to_outputtype_reader_opt.as_ref().unwrap();
|
||||
let txoutindex_to_typeindex_reader = txoutindex_to_typeindex_reader_opt.as_ref().unwrap();
|
||||
let p2pk65addressindex_to_p2pk65bytes_reader = p2pk65addressindex_to_p2pk65bytes_reader_opt.as_ref().unwrap();
|
||||
let p2pk33addressindex_to_p2pk33bytes_reader = p2pk33addressindex_to_p2pk33bytes_reader_opt.as_ref().unwrap();
|
||||
let p2pkhaddressindex_to_p2pkhbytes_reader = p2pkhaddressindex_to_p2pkhbytes_reader_opt.as_ref().unwrap();
|
||||
@@ -246,7 +265,7 @@ impl Indexer {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let input_source_vec = inputs
|
||||
let txinindex_to_txindata = inputs
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.map(|(block_txinindex, (block_txindex, vin, txin, tx))| -> Result<(TxInIndex, InputSource)> {
|
||||
@@ -283,11 +302,30 @@ impl Indexer {
|
||||
})?.into_owned()
|
||||
+ vout;
|
||||
|
||||
Ok((txinindex, InputSource::PreviousBlock((
|
||||
let outpoint = OutPoint::new(prev_txindex, vout);
|
||||
|
||||
let outputtype = vecs.txoutindex_to_outputtype.get_or_read(txoutindex, txoutindex_to_outputtype_reader)?
|
||||
.ok_or(Error::Str("Expect outputtype to not be none"))?.into_owned();
|
||||
|
||||
let mut tuple = (
|
||||
vin,
|
||||
txindex,
|
||||
txoutindex,
|
||||
))))
|
||||
outpoint,
|
||||
None
|
||||
);
|
||||
|
||||
// Rare but happens
|
||||
// https://mempool.space/tx/8ebe1df6ebf008f7ec42ccd022478c9afaec3ca0444322243b745aa2e317c272#flow=&vin=89
|
||||
if outputtype.is_not_address() {
|
||||
return Ok((txinindex, InputSource::PreviousBlock(tuple)));
|
||||
}
|
||||
|
||||
let typeindex = vecs.txoutindex_to_typeindex.get_or_read(txoutindex, txoutindex_to_typeindex_reader)?
|
||||
.ok_or(Error::Str("Expect typeindex to not be none"))?.into_owned();
|
||||
|
||||
tuple.3 = Some((outputtype, typeindex));
|
||||
|
||||
Ok((txinindex, InputSource::PreviousBlock(tuple)))
|
||||
})
|
||||
.try_fold(BTreeMap::new, |mut map, tuple| -> Result<_> {
|
||||
let (key, value) = tuple?;
|
||||
@@ -315,7 +353,7 @@ impl Indexer {
|
||||
.map(move |(vout, txout)| (TxIndex::from(index), Vout::from(vout), txout, tx))
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let txoutindex_to_txout_outputtype_addressbytes_res_addressindex_opt = outputs.into_par_iter()
|
||||
let txoutindex_to_txoutdata = outputs.into_par_iter()
|
||||
.enumerate()
|
||||
.map(
|
||||
#[allow(clippy::type_complexity)]
|
||||
@@ -349,7 +387,7 @@ impl Indexer {
|
||||
.get(&AddressBytesHash::from((addressbytes, outputtype)))
|
||||
.unwrap()
|
||||
.map(|v| *v)
|
||||
// Checking if not in the future
|
||||
// Checking if not in the future (in case we started before the last processed block)
|
||||
.and_then(|typeindex_local| {
|
||||
(typeindex_local < idxs.to_typeindex(outputtype)).then_some(typeindex_local)
|
||||
})
|
||||
@@ -449,141 +487,142 @@ impl Indexer {
|
||||
}
|
||||
})?;
|
||||
|
||||
let outputs_len = txoutindex_to_txout_outputtype_addressbytes_res_addressindex_opt.len();
|
||||
let inputs_len = input_source_vec.len();
|
||||
let outputs_len = txoutindex_to_txoutdata.len();
|
||||
let inputs_len = txinindex_to_txindata.len();
|
||||
let tx_len = block.txdata.len();
|
||||
|
||||
let mut new_txindexvout_to_txoutindex: BTreeMap<
|
||||
(TxIndex, Vout),
|
||||
TxOutIndex,
|
||||
> = BTreeMap::new();
|
||||
|
||||
let mut already_added_addressbyteshash: BTreeMap<AddressBytesHash, TypeIndex> = BTreeMap::new();
|
||||
|
||||
txoutindex_to_txout_outputtype_addressbytes_res_addressindex_opt
|
||||
.into_iter()
|
||||
.try_for_each(
|
||||
|(
|
||||
txoutindex,
|
||||
(txout, txindex, vout, outputtype, addressbytes_res, typeindex_opt, _tx),
|
||||
)|
|
||||
-> Result<()> {
|
||||
let sats = Sats::from(txout.value);
|
||||
let mut outpoint_to_outputtype_and_addressindex: BTreeMap<OutPoint, (OutputType, TypeIndex)> =
|
||||
txoutindex_to_txoutdata
|
||||
.into_iter()
|
||||
.flat_map(|(
|
||||
txoutindex,
|
||||
(txout, txindex, vout, outputtype, addressbytes_res, typeindex_opt, _tx),
|
||||
)| {
|
||||
let result: Result<Option<(OutPoint, (OutputType, TypeIndex))>> = (|| {
|
||||
let sats = Sats::from(txout.value);
|
||||
|
||||
if vout.is_zero() {
|
||||
vecs.txindex_to_first_txoutindex.push_if_needed(txindex, txoutindex)?;
|
||||
}
|
||||
if vout.is_zero() {
|
||||
vecs.txindex_to_first_txoutindex.push_if_needed(txindex, txoutindex)?;
|
||||
}
|
||||
|
||||
vecs.txoutindex_to_value.push_if_needed(txoutindex, sats)?;
|
||||
vecs.txoutindex_to_value.push_if_needed(txoutindex, sats)?;
|
||||
|
||||
vecs.txoutindex_to_outputtype
|
||||
.push_if_needed(txoutindex, outputtype)?;
|
||||
vecs.txoutindex_to_outputtype
|
||||
.push_if_needed(txoutindex, outputtype)?;
|
||||
|
||||
let mut addressbyteshash = None;
|
||||
let mut addressbyteshash = None;
|
||||
|
||||
let typeindex;
|
||||
let typeindex;
|
||||
|
||||
if let Some(typeindex_local) = typeindex_opt.or_else(|| {
|
||||
addressbytes_res.as_ref().ok().and_then(|addressbytes| {
|
||||
// Check if address was first seen before in this iterator
|
||||
// Example: https://mempool.space/address/046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0c
|
||||
addressbyteshash.replace(AddressBytesHash::from((addressbytes, outputtype)));
|
||||
already_added_addressbyteshash
|
||||
.get(addressbyteshash.as_ref().unwrap())
|
||||
.cloned()
|
||||
})
|
||||
}) {
|
||||
typeindex = typeindex_local;
|
||||
} else {
|
||||
typeindex = match outputtype {
|
||||
OutputType::P2PK65 => {
|
||||
idxs.p2pk65addressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2PK33 => {
|
||||
idxs.p2pk33addressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2PKH => {
|
||||
idxs.p2pkhaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2MS => {
|
||||
vecs.p2msoutputindex_to_txindex.push_if_needed(idxs.p2msoutputindex, txindex)?;
|
||||
idxs.p2msoutputindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2SH => {
|
||||
idxs.p2shaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::OpReturn => {
|
||||
vecs.opreturnindex_to_txindex.push_if_needed(idxs.opreturnindex, txindex)?;
|
||||
idxs.opreturnindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2WPKH => {
|
||||
idxs.p2wpkhaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2WSH => {
|
||||
idxs.p2wshaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2TR => {
|
||||
idxs.p2traddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2A => {
|
||||
idxs.p2aaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::Empty => {
|
||||
vecs.emptyoutputindex_to_txindex
|
||||
.push_if_needed(idxs.emptyoutputindex, txindex)?;
|
||||
idxs.emptyoutputindex.copy_then_increment()
|
||||
},
|
||||
OutputType::Unknown => {
|
||||
vecs.unknownoutputindex_to_txindex.push_if_needed(idxs.unknownoutputindex, txindex)?;
|
||||
idxs.unknownoutputindex.copy_then_increment()
|
||||
},
|
||||
_ => unreachable!()
|
||||
};
|
||||
if let Some(typeindex_local) = typeindex_opt.or_else(|| {
|
||||
addressbytes_res.as_ref().ok().and_then(|addressbytes| {
|
||||
// Check if address was first seen before in this iterator
|
||||
// Example: https://mempool.space/address/046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0c
|
||||
addressbyteshash.replace(AddressBytesHash::from((addressbytes, outputtype)));
|
||||
already_added_addressbyteshash
|
||||
.get(addressbyteshash.as_ref().unwrap())
|
||||
.cloned()
|
||||
})
|
||||
}) {
|
||||
typeindex = typeindex_local;
|
||||
} else {
|
||||
typeindex = match outputtype {
|
||||
OutputType::P2PK65 => {
|
||||
idxs.p2pk65addressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2PK33 => {
|
||||
idxs.p2pk33addressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2PKH => {
|
||||
idxs.p2pkhaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2MS => {
|
||||
vecs.p2msoutputindex_to_txindex.push_if_needed(idxs.p2msoutputindex, txindex)?;
|
||||
idxs.p2msoutputindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2SH => {
|
||||
idxs.p2shaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::OpReturn => {
|
||||
vecs.opreturnindex_to_txindex.push_if_needed(idxs.opreturnindex, txindex)?;
|
||||
idxs.opreturnindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2WPKH => {
|
||||
idxs.p2wpkhaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2WSH => {
|
||||
idxs.p2wshaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2TR => {
|
||||
idxs.p2traddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2A => {
|
||||
idxs.p2aaddressindex.copy_then_increment()
|
||||
},
|
||||
OutputType::Empty => {
|
||||
vecs.emptyoutputindex_to_txindex
|
||||
.push_if_needed(idxs.emptyoutputindex, txindex)?;
|
||||
idxs.emptyoutputindex.copy_then_increment()
|
||||
},
|
||||
OutputType::Unknown => {
|
||||
vecs.unknownoutputindex_to_txindex.push_if_needed(idxs.unknownoutputindex, txindex)?;
|
||||
idxs.unknownoutputindex.copy_then_increment()
|
||||
},
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
if let Ok(addressbytes) = addressbytes_res {
|
||||
let addressbyteshash = addressbyteshash.unwrap();
|
||||
if let Ok(addressbytes) = addressbytes_res {
|
||||
let addressbyteshash = addressbyteshash.unwrap();
|
||||
|
||||
already_added_addressbyteshash
|
||||
.insert(addressbyteshash, typeindex);
|
||||
already_added_addressbyteshash
|
||||
.insert(addressbyteshash, typeindex);
|
||||
|
||||
stores.addressbyteshash_to_typeindex.insert_if_needed(
|
||||
addressbyteshash,
|
||||
typeindex,
|
||||
height,
|
||||
);
|
||||
stores.addressbyteshash_to_typeindex.insert_if_needed(
|
||||
addressbyteshash,
|
||||
typeindex,
|
||||
height,
|
||||
);
|
||||
|
||||
vecs.push_bytes_if_needed(typeindex, addressbytes)?;
|
||||
vecs.push_bytes_if_needed(typeindex, addressbytes)?;
|
||||
}
|
||||
}
|
||||
|
||||
vecs.txoutindex_to_typeindex
|
||||
.push_if_needed(txoutindex, typeindex)?;
|
||||
|
||||
if outputtype.is_unspendable() {
|
||||
return Ok(None)
|
||||
} else if outputtype.is_address() {
|
||||
stores.addresstype_to_typeindex_and_txindex.get_mut(outputtype).unwrap().insert_if_needed(TypeIndexAndTxIndex::from((typeindex, txindex)), Unit, height);
|
||||
}
|
||||
|
||||
Ok(Some((OutPoint::new(txindex, vout), (outputtype, typeindex))))
|
||||
})();
|
||||
|
||||
match result {
|
||||
Ok(Some(item)) => Some(Ok(item)),
|
||||
Ok(None) => None,
|
||||
Err(e) => Some(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
vecs.txoutindex_to_typeindex
|
||||
.push_if_needed(txoutindex, typeindex)?;
|
||||
|
||||
new_txindexvout_to_txoutindex
|
||||
.insert((txindex, vout), txoutindex);
|
||||
|
||||
if outputtype.is_address() {
|
||||
stores.addresstype_to_typeindex_with_txoutindex.get_mut(outputtype).unwrap().insert_if_needed(TypeIndexWithOutputindex::from((typeindex, txoutindex)), Unit, height);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
})
|
||||
.collect::<Result<BTreeMap<_, _>>>()?;
|
||||
|
||||
drop(already_added_addressbyteshash);
|
||||
|
||||
input_source_vec
|
||||
txinindex_to_txindata
|
||||
.into_iter()
|
||||
.map(
|
||||
#[allow(clippy::type_complexity)]
|
||||
|(txinindex, input_source)| -> Result<(
|
||||
TxInIndex, Vin, TxIndex, TxOutIndex
|
||||
TxInIndex, Vin, TxIndex, OutPoint, Option<(OutputType, TypeIndex)>
|
||||
)> {
|
||||
match input_source {
|
||||
InputSource::PreviousBlock((vin, txindex, txoutindex)) => Ok((txinindex, vin, txindex, txoutindex)),
|
||||
InputSource::PreviousBlock((vin, txindex, outpoint, outputtype_typeindex_opt)) => Ok((txinindex, vin, txindex, outpoint, outputtype_typeindex_opt)),
|
||||
InputSource::SameBlock((tx, txindex, txin, vin)) => {
|
||||
if tx.is_coinbase() {
|
||||
return Ok((txinindex, vin, txindex, TxOutIndex::COINBASE));
|
||||
return Ok((txinindex, vin, txindex, OutPoint::COINBASE, None));
|
||||
}
|
||||
|
||||
let outpoint = txin.previous_output;
|
||||
@@ -599,44 +638,68 @@ impl Indexer {
|
||||
.2;
|
||||
let prev_txindex = idxs.txindex + block_txindex;
|
||||
|
||||
let prev_txoutindex = new_txindexvout_to_txoutindex
|
||||
.remove(&(prev_txindex, vout))
|
||||
let outpoint = OutPoint::new(prev_txindex, vout);
|
||||
|
||||
let mut tuple = (txinindex, vin, txindex, outpoint, None);
|
||||
|
||||
let outputtype_typeindex = outpoint_to_outputtype_and_addressindex
|
||||
.remove(&outpoint)
|
||||
.ok_or(Error::Str("should have found addressindex from same block"))
|
||||
.inspect_err(|_| {
|
||||
dbg!(&new_txindexvout_to_txoutindex, txin, prev_txindex, vout, txid);
|
||||
dbg!(&outpoint_to_outputtype_and_addressindex, txin, prev_txindex, vout, txid);
|
||||
})?;
|
||||
|
||||
Ok((txinindex, vin, txindex, prev_txoutindex))
|
||||
if outputtype_typeindex.0.is_not_address() {
|
||||
return Ok(tuple)
|
||||
}
|
||||
|
||||
tuple.4 = Some(outputtype_typeindex);
|
||||
|
||||
Ok(tuple)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.try_for_each(|res| -> Result<()> {
|
||||
let (txinindex, vin, txindex, txoutindex) = res?;
|
||||
let (txinindex, vin, txindex, outpoint, outputtype_typeindex_opt) = res?;
|
||||
|
||||
if vin.is_zero() {
|
||||
vecs.txindex_to_first_txinindex.push_if_needed(txindex, txinindex)?;
|
||||
}
|
||||
|
||||
vecs.txinindex_to_txoutindex.push_if_needed(txinindex, txoutindex)?;
|
||||
vecs.txinindex_to_outpoint.push_if_needed(txinindex, outpoint)?;
|
||||
|
||||
let Some((outputtype, typeindex)) = outputtype_typeindex_opt else {
|
||||
return Ok(())
|
||||
};
|
||||
|
||||
stores.addresstype_to_typeindex_and_txindex.get_mut(outputtype).unwrap().insert_if_needed(TypeIndexAndTxIndex::from((typeindex, txindex)), Unit, height);
|
||||
|
||||
stores.addresstype_to_typeindex_and_unspentoutpoint.get_mut(outputtype).unwrap().remove_if_needed(TypeIndexAndOutPoint::from((typeindex, outpoint)), height);
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
drop(new_txindexvout_to_txoutindex);
|
||||
|
||||
let mut txindex_to_tx_and_txid: BTreeMap<TxIndex, (&Transaction, Txid)> = BTreeMap::default();
|
||||
outpoint_to_outputtype_and_addressindex
|
||||
.into_iter()
|
||||
.filter(|(_, (outputtype,_))| outputtype.is_address())
|
||||
.for_each(|(outpoint, (outputtype, typeindex))| {
|
||||
stores.addresstype_to_typeindex_and_unspentoutpoint
|
||||
.get_mut(outputtype)
|
||||
.unwrap()
|
||||
.insert_if_needed(TypeIndexAndOutPoint::from((typeindex, outpoint)), Unit, height);
|
||||
});
|
||||
|
||||
let mut txindex_to_txid_iter = vecs
|
||||
.txindex_to_txid.into_iter();
|
||||
|
||||
txid_prefix_to_txid_and_block_txindex_and_prev_txindex
|
||||
let txindex_to_tx_and_txid = txid_prefix_to_txid_and_block_txindex_and_prev_txindex
|
||||
.into_iter()
|
||||
.try_for_each(
|
||||
|(txid_prefix, (tx, txid, index, prev_txindex_opt))| -> Result<()> {
|
||||
.map(
|
||||
|(txid_prefix, (tx, txid, index, prev_txindex_opt))| -> Result<(TxIndex, (&Transaction, Txid))> {
|
||||
let txindex = idxs.txindex + index;
|
||||
|
||||
txindex_to_tx_and_txid.insert(txindex, (tx, txid));
|
||||
let tuple = (txindex, (tx, txid));
|
||||
|
||||
match prev_txindex_opt {
|
||||
None => {
|
||||
@@ -647,11 +710,11 @@ impl Indexer {
|
||||
Some(prev_txindex) => {
|
||||
// In case if we start at an already parsed height
|
||||
if txindex == prev_txindex {
|
||||
return Ok(());
|
||||
return Ok(tuple);
|
||||
}
|
||||
|
||||
if !check_collisions {
|
||||
return Ok(());
|
||||
return Ok(tuple);
|
||||
}
|
||||
|
||||
let len = vecs.txindex_to_txid.len();
|
||||
@@ -689,9 +752,9 @@ impl Indexer {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(tuple)
|
||||
},
|
||||
)?;
|
||||
).collect::<Result<BTreeMap<_, _>>>()?;
|
||||
|
||||
drop(txindex_to_txid_iter);
|
||||
|
||||
@@ -713,6 +776,8 @@ impl Indexer {
|
||||
|
||||
if should_export(height, false) {
|
||||
txindex_to_first_txoutindex_reader_opt.take();
|
||||
txoutindex_to_outputtype_reader_opt.take();
|
||||
txoutindex_to_typeindex_reader_opt.take();
|
||||
p2pk65addressindex_to_p2pk65bytes_reader_opt.take();
|
||||
p2pk33addressindex_to_p2pk33bytes_reader_opt.take();
|
||||
p2pkhaddressindex_to_p2pkhbytes_reader_opt.take();
|
||||
@@ -727,6 +792,8 @@ impl Indexer {
|
||||
reset_readers(
|
||||
vecs,
|
||||
&mut txindex_to_first_txoutindex_reader_opt,
|
||||
&mut txoutindex_to_outputtype_reader_opt,
|
||||
&mut txoutindex_to_typeindex_reader_opt,
|
||||
&mut p2pk65addressindex_to_p2pk65bytes_reader_opt,
|
||||
&mut p2pk33addressindex_to_p2pk33bytes_reader_opt,
|
||||
&mut p2pkhaddressindex_to_p2pkhbytes_reader_opt,
|
||||
@@ -770,6 +837,6 @@ impl Indexer {
|
||||
|
||||
#[derive(Debug)]
|
||||
enum InputSource<'a> {
|
||||
PreviousBlock((Vin, TxIndex, TxOutIndex)),
|
||||
PreviousBlock((Vin, TxIndex, OutPoint, Option<(OutputType, TypeIndex)>)),
|
||||
SameBlock((&'a Transaction, TxIndex, &'a TxIn, Vin)),
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::{borrow::Cow, fs, path::Path, thread};
|
||||
use std::{borrow::Cow, fs, path::Path};
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_grouper::ByAddressType;
|
||||
use brk_store::{AnyStore, Store};
|
||||
use brk_structs::{
|
||||
AddressBytes, AddressBytesHash, BlockHashPrefix, Height, OutputType, StoredString, TxIndex,
|
||||
TxOutIndex, TxidPrefix, TypeIndex, TypeIndexWithOutputindex, Unit, Version,
|
||||
TxOutIndex, TxidPrefix, TypeIndex, TypeIndexAndOutPoint, TypeIndexAndTxIndex, Unit, Version,
|
||||
};
|
||||
use fjall::{PersistMode, TransactionalKeyspace};
|
||||
use rayon::prelude::*;
|
||||
@@ -23,141 +23,90 @@ pub struct Stores {
|
||||
pub blockhashprefix_to_height: Store<BlockHashPrefix, Height>,
|
||||
pub height_to_coinbase_tag: Store<Height, StoredString>,
|
||||
pub txidprefix_to_txindex: Store<TxidPrefix, TxIndex>,
|
||||
// Do address_type_to_typeindex_with_txindex_to_vin_and_vout_instead ?
|
||||
// and should vin be txoutindex or txinindex?
|
||||
pub addresstype_to_typeindex_with_txoutindex:
|
||||
ByAddressType<Store<TypeIndexWithOutputindex, Unit>>,
|
||||
pub addresstype_to_typeindex_and_txindex: ByAddressType<Store<TypeIndexAndTxIndex, Unit>>,
|
||||
pub addresstype_to_typeindex_and_unspentoutpoint:
|
||||
ByAddressType<Store<TypeIndexAndOutPoint, Unit>>,
|
||||
}
|
||||
|
||||
impl Stores {
|
||||
pub fn forced_import(parent: &Path, version: Version) -> Result<Self> {
|
||||
let path = parent.join("stores");
|
||||
let pathbuf = parent.join("stores");
|
||||
let path = pathbuf.as_path();
|
||||
|
||||
fs::create_dir_all(&path)?;
|
||||
fs::create_dir_all(&pathbuf)?;
|
||||
|
||||
let keyspace = match brk_store::open_keyspace(&path) {
|
||||
let keyspace = match brk_store::open_keyspace(path) {
|
||||
Ok(keyspace) => keyspace,
|
||||
Err(_) => {
|
||||
fs::remove_dir_all(&path)?;
|
||||
return Self::forced_import(&path, version);
|
||||
fs::remove_dir_all(path)?;
|
||||
return Self::forced_import(path, version);
|
||||
}
|
||||
};
|
||||
|
||||
thread::scope(|scope| {
|
||||
let addressbyteshash_to_typeindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
&keyspace,
|
||||
&path,
|
||||
"addressbyteshash_to_typeindex",
|
||||
version,
|
||||
None,
|
||||
)
|
||||
});
|
||||
let blockhashprefix_to_height = scope.spawn(|| {
|
||||
Store::import(&keyspace, &path, "blockhashprefix_to_height", version, None)
|
||||
});
|
||||
let txidprefix_to_txindex = scope
|
||||
.spawn(|| Store::import(&keyspace, &path, "txidprefix_to_txindex", version, None));
|
||||
let p2aaddressindex_with_txoutindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
&keyspace,
|
||||
&path,
|
||||
"p2aaddressindex_with_txoutindex",
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
});
|
||||
let p2pk33addressindex_with_txoutindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
&keyspace,
|
||||
&path,
|
||||
"p2pk33addressindex_with_txoutindex",
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
});
|
||||
let p2pk65addressindex_with_txoutindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
&keyspace,
|
||||
&path,
|
||||
"p2pk65addressindex_with_txoutindex",
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
});
|
||||
let p2pkhaddressindex_with_txoutindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
&keyspace,
|
||||
&path,
|
||||
"p2pkhaddressindex_with_txoutindex",
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
});
|
||||
let p2shaddressindex_with_txoutindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
&keyspace,
|
||||
&path,
|
||||
"p2shaddressindex_with_txoutindex",
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
});
|
||||
let p2traddressindex_with_txoutindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
&keyspace,
|
||||
&path,
|
||||
"p2traddressindex_with_txoutindex",
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
});
|
||||
let p2wpkhaddressindex_with_txoutindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
&keyspace,
|
||||
&path,
|
||||
"p2wpkhaddressindex_with_txoutindex",
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
});
|
||||
let p2wshaddressindex_with_txoutindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
&keyspace,
|
||||
&path,
|
||||
"p2wshaddressindex_with_txoutindex",
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
});
|
||||
let keyspace_ref = &keyspace;
|
||||
|
||||
let height_to_coinbase_tag =
|
||||
Store::import(&keyspace, &path, "height_to_coinbase_tag", version, None)?;
|
||||
let create_addressindex_and_txindex_store = |cohort| {
|
||||
Store::import(
|
||||
keyspace_ref,
|
||||
path,
|
||||
&format!("{}addressindex_and_txindex", cohort),
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
keyspace: keyspace.clone(),
|
||||
let create_addressindex_and_unspentoutpoint_store = |cohort| {
|
||||
Store::import(
|
||||
keyspace_ref,
|
||||
path,
|
||||
&format!("{}addressindex_and_unspentoutpoint", cohort),
|
||||
version,
|
||||
Some(false),
|
||||
)
|
||||
};
|
||||
|
||||
height_to_coinbase_tag,
|
||||
addressbyteshash_to_typeindex: addressbyteshash_to_typeindex.join().unwrap()?,
|
||||
blockhashprefix_to_height: blockhashprefix_to_height.join().unwrap()?,
|
||||
txidprefix_to_txindex: txidprefix_to_txindex.join().unwrap()?,
|
||||
addresstype_to_typeindex_with_txoutindex: ByAddressType {
|
||||
p2pk65: p2pk65addressindex_with_txoutindex.join().unwrap()?,
|
||||
p2pk33: p2pk33addressindex_with_txoutindex.join().unwrap()?,
|
||||
p2pkh: p2pkhaddressindex_with_txoutindex.join().unwrap()?,
|
||||
p2sh: p2shaddressindex_with_txoutindex.join().unwrap()?,
|
||||
p2wpkh: p2wpkhaddressindex_with_txoutindex.join().unwrap()?,
|
||||
p2wsh: p2wshaddressindex_with_txoutindex.join().unwrap()?,
|
||||
p2tr: p2traddressindex_with_txoutindex.join().unwrap()?,
|
||||
p2a: p2aaddressindex_with_txoutindex.join().unwrap()?,
|
||||
},
|
||||
})
|
||||
Ok(Self {
|
||||
keyspace: keyspace.clone(),
|
||||
|
||||
height_to_coinbase_tag: Store::import(
|
||||
keyspace_ref,
|
||||
path,
|
||||
"height_to_coinbase_tag",
|
||||
version,
|
||||
None,
|
||||
)?,
|
||||
addressbyteshash_to_typeindex: Store::import(
|
||||
keyspace_ref,
|
||||
path,
|
||||
"addressbyteshash_to_typeindex",
|
||||
version,
|
||||
None,
|
||||
)?,
|
||||
blockhashprefix_to_height: Store::import(
|
||||
keyspace_ref,
|
||||
path,
|
||||
"blockhashprefix_to_height",
|
||||
version,
|
||||
None,
|
||||
)?,
|
||||
txidprefix_to_txindex: Store::import(
|
||||
keyspace_ref,
|
||||
path,
|
||||
"txidprefix_to_txindex",
|
||||
version,
|
||||
None,
|
||||
)?,
|
||||
addresstype_to_typeindex_and_txindex: ByAddressType::new(
|
||||
create_addressindex_and_txindex_store,
|
||||
)?,
|
||||
addresstype_to_typeindex_and_unspentoutpoint: ByAddressType::new(
|
||||
create_addressindex_and_unspentoutpoint_store,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn starting_height(&self) -> Height {
|
||||
self.as_slice()
|
||||
.into_iter()
|
||||
self.iter_any_store()
|
||||
.map(|store| {
|
||||
// let height =
|
||||
store.height().map(Height::incremented).unwrap_or_default()
|
||||
@@ -168,8 +117,8 @@ impl Stores {
|
||||
}
|
||||
|
||||
pub fn commit(&mut self, height: Height) -> Result<()> {
|
||||
self.as_mut_slice()
|
||||
.into_par_iter()
|
||||
self.iter_mut_any_store()
|
||||
.par_bridge()
|
||||
.try_for_each(|store| store.commit(height))?;
|
||||
|
||||
self.keyspace
|
||||
@@ -177,38 +126,44 @@ impl Stores {
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn as_slice(&self) -> [&(dyn AnyStore + Send + Sync); 12] {
|
||||
fn iter_any_store(&self) -> impl Iterator<Item = &dyn AnyStore> {
|
||||
[
|
||||
&self.addressbyteshash_to_typeindex,
|
||||
&self.addresstype_to_typeindex_with_txoutindex.p2a,
|
||||
&self.addresstype_to_typeindex_with_txoutindex.p2pk33,
|
||||
&self.addresstype_to_typeindex_with_txoutindex.p2pk65,
|
||||
&self.addresstype_to_typeindex_with_txoutindex.p2pkh,
|
||||
&self.addresstype_to_typeindex_with_txoutindex.p2sh,
|
||||
&self.addresstype_to_typeindex_with_txoutindex.p2tr,
|
||||
&self.addresstype_to_typeindex_with_txoutindex.p2wpkh,
|
||||
&self.addresstype_to_typeindex_with_txoutindex.p2wsh,
|
||||
&self.addressbyteshash_to_typeindex as &dyn AnyStore,
|
||||
&self.blockhashprefix_to_height,
|
||||
&self.height_to_coinbase_tag,
|
||||
&self.txidprefix_to_txindex,
|
||||
]
|
||||
.into_iter()
|
||||
.chain(
|
||||
self.addresstype_to_typeindex_and_txindex
|
||||
.iter()
|
||||
.map(|s| s as &dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_typeindex_and_unspentoutpoint
|
||||
.iter()
|
||||
.map(|s| s as &dyn AnyStore),
|
||||
)
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> [&mut (dyn AnyStore + Send + Sync); 12] {
|
||||
fn iter_mut_any_store(&mut self) -> impl Iterator<Item = &mut dyn AnyStore> {
|
||||
[
|
||||
&mut self.addressbyteshash_to_typeindex,
|
||||
&mut self.addresstype_to_typeindex_with_txoutindex.p2a,
|
||||
&mut self.addresstype_to_typeindex_with_txoutindex.p2pk33,
|
||||
&mut self.addresstype_to_typeindex_with_txoutindex.p2pk65,
|
||||
&mut self.addresstype_to_typeindex_with_txoutindex.p2pkh,
|
||||
&mut self.addresstype_to_typeindex_with_txoutindex.p2sh,
|
||||
&mut self.addresstype_to_typeindex_with_txoutindex.p2tr,
|
||||
&mut self.addresstype_to_typeindex_with_txoutindex.p2wpkh,
|
||||
&mut self.addresstype_to_typeindex_with_txoutindex.p2wsh,
|
||||
&mut self.addressbyteshash_to_typeindex as &mut dyn AnyStore,
|
||||
&mut self.blockhashprefix_to_height,
|
||||
&mut self.height_to_coinbase_tag,
|
||||
&mut self.txidprefix_to_txindex,
|
||||
]
|
||||
.into_iter()
|
||||
.chain(
|
||||
self.addresstype_to_typeindex_and_txindex
|
||||
.iter_mut()
|
||||
.map(|s| s as &mut dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_typeindex_and_unspentoutpoint
|
||||
.iter_mut()
|
||||
.map(|s| s as &mut dyn AnyStore),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn rollback_if_needed(
|
||||
@@ -221,37 +176,19 @@ impl Stores {
|
||||
&& self.txidprefix_to_txindex.is_empty()?
|
||||
&& self.height_to_coinbase_tag.is_empty()?
|
||||
&& self
|
||||
.addresstype_to_typeindex_with_txoutindex
|
||||
.p2a
|
||||
.is_empty()?
|
||||
.addresstype_to_typeindex_and_txindex
|
||||
.iter()
|
||||
.map(|s| s.is_empty())
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.into_iter()
|
||||
.all(|empty| empty)
|
||||
&& self
|
||||
.addresstype_to_typeindex_with_txoutindex
|
||||
.p2pk33
|
||||
.is_empty()?
|
||||
&& self
|
||||
.addresstype_to_typeindex_with_txoutindex
|
||||
.p2pk65
|
||||
.is_empty()?
|
||||
&& self
|
||||
.addresstype_to_typeindex_with_txoutindex
|
||||
.p2pkh
|
||||
.is_empty()?
|
||||
&& self
|
||||
.addresstype_to_typeindex_with_txoutindex
|
||||
.p2sh
|
||||
.is_empty()?
|
||||
&& self
|
||||
.addresstype_to_typeindex_with_txoutindex
|
||||
.p2tr
|
||||
.is_empty()?
|
||||
&& self
|
||||
.addresstype_to_typeindex_with_txoutindex
|
||||
.p2wpkh
|
||||
.is_empty()?
|
||||
&& self
|
||||
.addresstype_to_typeindex_with_txoutindex
|
||||
.p2wsh
|
||||
.is_empty()?
|
||||
.addresstype_to_typeindex_and_unspentoutpoint
|
||||
.iter()
|
||||
.map(|s| s.is_empty())
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.into_iter()
|
||||
.all(|empty| empty)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
@@ -456,39 +393,28 @@ impl Stores {
|
||||
}
|
||||
|
||||
if starting_indexes.txoutindex != TxOutIndex::ZERO {
|
||||
let mut txoutindex_to_typeindex_iter = vecs.txoutindex_to_typeindex.into_iter();
|
||||
vecs.txoutindex_to_outputtype
|
||||
.iter_at(starting_indexes.txoutindex)
|
||||
.filter(|(_, outputtype)| outputtype.is_address())
|
||||
.for_each(|(txoutindex, outputtype)| {
|
||||
let outputtype = outputtype.into_owned();
|
||||
todo!();
|
||||
// let mut txoutindex_to_typeindex_iter = vecs.txoutindex_to_typeindex.into_iter();
|
||||
// vecs.txoutindex_to_outputtype
|
||||
// .iter_at(starting_indexes.txoutindex)
|
||||
// .filter(|(_, outputtype)| outputtype.is_address())
|
||||
// .for_each(|(txoutindex, outputtype)| {
|
||||
// let outputtype = outputtype.into_owned();
|
||||
|
||||
let typeindex = txoutindex_to_typeindex_iter.unwrap_get_inner(txoutindex);
|
||||
// let typeindex = txoutindex_to_typeindex_iter.unwrap_get_inner(txoutindex);
|
||||
|
||||
self.addresstype_to_typeindex_with_txoutindex
|
||||
.get_mut(outputtype)
|
||||
.unwrap()
|
||||
.remove(TypeIndexWithOutputindex::from((typeindex, txoutindex)));
|
||||
});
|
||||
// self.addresstype_to_typeindex_and_unspentoutpoint
|
||||
// .get_mut(outputtype)
|
||||
// .unwrap()
|
||||
// .remove(TypeIndexAndTxIndex::from((typeindex, txoutindex)));
|
||||
// });
|
||||
} else {
|
||||
self.addresstype_to_typeindex_with_txoutindex.p2a.reset()?;
|
||||
self.addresstype_to_typeindex_with_txoutindex
|
||||
.p2pk33
|
||||
.reset()?;
|
||||
self.addresstype_to_typeindex_with_txoutindex
|
||||
.p2pk65
|
||||
.reset()?;
|
||||
self.addresstype_to_typeindex_with_txoutindex
|
||||
.p2pkh
|
||||
.reset()?;
|
||||
self.addresstype_to_typeindex_with_txoutindex.p2sh.reset()?;
|
||||
self.addresstype_to_typeindex_with_txoutindex.p2tr.reset()?;
|
||||
self.addresstype_to_typeindex_with_txoutindex
|
||||
.p2wpkh
|
||||
.reset()?;
|
||||
self.addresstype_to_typeindex_with_txoutindex
|
||||
.p2wsh
|
||||
.reset()?;
|
||||
self.addresstype_to_typeindex_and_txindex
|
||||
.iter_mut()
|
||||
.try_for_each(|s| s.reset())?;
|
||||
self.addresstype_to_typeindex_and_unspentoutpoint
|
||||
.iter_mut()
|
||||
.try_for_each(|s| s.reset())?;
|
||||
}
|
||||
|
||||
self.commit(starting_indexes.height.decremented().unwrap_or_default())?;
|
||||
|
||||
@@ -2,12 +2,12 @@ use std::path::Path;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_structs::{
|
||||
AddressBytes, BlockHash, EmptyOutputIndex, Height, OpReturnIndex, OutputType, P2AAddressIndex,
|
||||
P2ABytes, P2MSOutputIndex, P2PK33AddressIndex, P2PK33Bytes, P2PK65AddressIndex, P2PK65Bytes,
|
||||
P2PKHAddressIndex, P2PKHBytes, P2SHAddressIndex, P2SHBytes, P2TRAddressIndex, P2TRBytes,
|
||||
P2WPKHAddressIndex, P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes, RawLockTime, Sats, StoredBool,
|
||||
StoredF64, StoredU32, StoredU64, Timestamp, TxInIndex, TxIndex, TxOutIndex, TxVersion, Txid,
|
||||
TypeIndex, UnknownOutputIndex, Version, Weight,
|
||||
AddressBytes, BlockHash, EmptyOutputIndex, Height, OpReturnIndex, OutPoint, OutputType,
|
||||
P2AAddressIndex, P2ABytes, P2MSOutputIndex, P2PK33AddressIndex, P2PK33Bytes,
|
||||
P2PK65AddressIndex, P2PK65Bytes, P2PKHAddressIndex, P2PKHBytes, P2SHAddressIndex, P2SHBytes,
|
||||
P2TRAddressIndex, P2TRBytes, P2WPKHAddressIndex, P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes,
|
||||
RawLockTime, Sats, StoredBool, StoredF64, StoredU32, StoredU64, Timestamp, TxInIndex, TxIndex,
|
||||
TxOutIndex, TxVersion, Txid, TypeIndex, UnknownOutputIndex, Version, Weight,
|
||||
};
|
||||
use brk_traversable::Traversable;
|
||||
use rayon::prelude::*;
|
||||
@@ -40,8 +40,7 @@ pub struct Vecs {
|
||||
pub height_to_timestamp: CompressedVec<Height, Timestamp>,
|
||||
pub height_to_total_size: CompressedVec<Height, StoredU64>,
|
||||
pub height_to_weight: CompressedVec<Height, Weight>,
|
||||
/// If txoutindex == TxOutIndex::MAX then it's coinbase
|
||||
pub txinindex_to_txoutindex: RawVec<TxInIndex, TxOutIndex>,
|
||||
pub txinindex_to_outpoint: RawVec<TxInIndex, OutPoint>,
|
||||
pub opreturnindex_to_txindex: CompressedVec<OpReturnIndex, TxIndex>,
|
||||
pub txoutindex_to_outputtype: RawVec<TxOutIndex, OutputType>,
|
||||
pub txoutindex_to_typeindex: RawVec<TxOutIndex, TypeIndex>,
|
||||
@@ -152,7 +151,7 @@ impl Vecs {
|
||||
height_to_timestamp: CompressedVec::forced_import(&db, "timestamp", version)?,
|
||||
height_to_total_size: CompressedVec::forced_import(&db, "total_size", version)?,
|
||||
height_to_weight: CompressedVec::forced_import(&db, "weight", version)?,
|
||||
txinindex_to_txoutindex: RawVec::forced_import(&db, "txoutindex", version)?,
|
||||
txinindex_to_outpoint: RawVec::forced_import(&db, "outpoint", version)?,
|
||||
opreturnindex_to_txindex: CompressedVec::forced_import(&db, "txindex", version)?,
|
||||
txoutindex_to_outputtype: RawVec::forced_import(&db, "outputtype", version)?,
|
||||
txoutindex_to_typeindex: RawVec::forced_import(&db, "typeindex", version)?,
|
||||
@@ -266,7 +265,7 @@ impl Vecs {
|
||||
.truncate_if_needed_with_stamp(height, stamp)?;
|
||||
self.height_to_weight
|
||||
.truncate_if_needed_with_stamp(height, stamp)?;
|
||||
self.txinindex_to_txoutindex
|
||||
self.txinindex_to_outpoint
|
||||
.truncate_if_needed_with_stamp(txinindex, stamp)?;
|
||||
self.opreturnindex_to_txindex
|
||||
.truncate_if_needed_with_stamp(opreturnindex, stamp)?;
|
||||
@@ -347,7 +346,7 @@ impl Vecs {
|
||||
}
|
||||
|
||||
pub fn flush(&mut self, height: Height) -> Result<()> {
|
||||
self.iter_mut()
|
||||
self.iter_mut_any_stored_vec()
|
||||
.par_bridge()
|
||||
.try_for_each(|vec| vec.stamped_flush(Stamp::from(height)))?;
|
||||
self.db.flush()?;
|
||||
@@ -355,7 +354,7 @@ impl Vecs {
|
||||
}
|
||||
|
||||
pub fn starting_height(&mut self) -> Height {
|
||||
self.iter_mut()
|
||||
self.iter_mut_any_stored_vec()
|
||||
.map(|vec| {
|
||||
let h = Height::from(vec.stamp());
|
||||
if h > Height::ZERO { h.incremented() } else { h }
|
||||
@@ -419,7 +418,7 @@ impl Vecs {
|
||||
// .into_iter()
|
||||
// }
|
||||
|
||||
fn iter_mut(&mut self) -> impl Iterator<Item = &mut dyn AnyStoredVec> {
|
||||
fn iter_mut_any_stored_vec(&mut self) -> impl Iterator<Item = &mut dyn AnyStoredVec> {
|
||||
[
|
||||
&mut self.emptyoutputindex_to_txindex as &mut dyn AnyStoredVec,
|
||||
&mut self.height_to_blockhash,
|
||||
@@ -442,7 +441,7 @@ impl Vecs {
|
||||
&mut self.height_to_timestamp,
|
||||
&mut self.height_to_total_size,
|
||||
&mut self.height_to_weight,
|
||||
&mut self.txinindex_to_txoutindex,
|
||||
&mut self.txinindex_to_outpoint,
|
||||
&mut self.opreturnindex_to_txindex,
|
||||
&mut self.txoutindex_to_outputtype,
|
||||
&mut self.txoutindex_to_typeindex,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use brk_error::Result;
|
||||
use brk_structs::{Height, Version};
|
||||
|
||||
pub trait AnyStore {
|
||||
pub trait AnyStore: Send + Sync {
|
||||
fn commit(&mut self, height: Height) -> Result<()>;
|
||||
fn persist(&self) -> Result<()>;
|
||||
fn reset(&mut self) -> Result<()>;
|
||||
|
||||
@@ -46,11 +46,11 @@ pub fn open_keyspace(path: &Path) -> fjall::Result<TransactionalKeyspace> {
|
||||
.open_transactional()
|
||||
}
|
||||
|
||||
impl<'a, K, V> Store<K, V>
|
||||
impl<K, V> Store<K, V>
|
||||
where
|
||||
K: Debug + Clone + From<ByteView> + Ord + 'a,
|
||||
K: Debug + Clone + From<ByteView> + Ord,
|
||||
V: Debug + Clone + From<ByteView>,
|
||||
ByteView: From<K> + From<&'a K> + From<V>,
|
||||
ByteView: From<K> + From<V>,
|
||||
{
|
||||
pub fn import(
|
||||
keyspace: &TransactionalKeyspace,
|
||||
@@ -87,7 +87,10 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get(&'_ self, key: &'a K) -> Result<Option<Cow<'_, V>>> {
|
||||
pub fn get<'a>(&'a self, key: &'a K) -> Result<Option<Cow<'a, V>>>
|
||||
where
|
||||
ByteView: From<&'a K>,
|
||||
{
|
||||
if let Some(v) = self.puts.get(key) {
|
||||
Ok(Some(Cow::Borrowed(v)))
|
||||
} else if let Some(slice) = self
|
||||
@@ -159,18 +162,24 @@ where
|
||||
// return Ok(());
|
||||
// }
|
||||
|
||||
if !self.puts.is_empty() {
|
||||
unreachable!("Shouldn't reach this");
|
||||
}
|
||||
// if !self.puts.is_empty() {
|
||||
// unreachable!("Shouldn't reach this");
|
||||
// }
|
||||
|
||||
if !self.dels.insert(key.clone()) {
|
||||
dbg!(key, &self.meta.path());
|
||||
if (self.puts.is_empty() || self.puts.remove(&key).is_none()) && !self.dels.insert(key) {
|
||||
dbg!(&self.meta.path());
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
// Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_if_needed(&mut self, key: K, height: Height) {
|
||||
if self.needs(height) {
|
||||
self.remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn retain_or_del<F>(&mut self, retain: F)
|
||||
// where
|
||||
// F: Fn(&K, &mut V) -> bool,
|
||||
@@ -245,13 +254,22 @@ where
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn has(&self, height: Height) -> bool {
|
||||
self.meta.has(height)
|
||||
}
|
||||
|
||||
fn needs(&self, height: Height) -> bool {
|
||||
self.meta.needs(height)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> AnyStore for Store<K, V>
|
||||
impl<K, V> AnyStore for Store<K, V>
|
||||
where
|
||||
K: Debug + Clone + From<ByteView> + Ord + 'a,
|
||||
K: Debug + Clone + From<ByteView> + Ord,
|
||||
V: Debug + Clone + From<ByteView>,
|
||||
ByteView: From<K> + From<&'a K> + From<V>,
|
||||
ByteView: From<K> + From<V>,
|
||||
Self: Send + Sync,
|
||||
{
|
||||
fn commit(&mut self, height: Height) -> Result<()> {
|
||||
if self.puts.is_empty() && self.dels.is_empty() {
|
||||
@@ -298,10 +316,11 @@ where
|
||||
}
|
||||
|
||||
fn has(&self, height: Height) -> bool {
|
||||
self.meta.has(height)
|
||||
self.has(height)
|
||||
}
|
||||
|
||||
fn needs(&self, height: Height) -> bool {
|
||||
self.meta.needs(height)
|
||||
self.needs(height)
|
||||
}
|
||||
|
||||
fn version(&self) -> Version {
|
||||
|
||||
@@ -43,6 +43,7 @@ mod metrics;
|
||||
mod monthindex;
|
||||
mod ohlc;
|
||||
mod opreturnindex;
|
||||
mod outpoint;
|
||||
mod outputtype;
|
||||
mod p2aaddressindex;
|
||||
mod p2abytes;
|
||||
@@ -91,7 +92,8 @@ mod txoutindex;
|
||||
mod txstatus;
|
||||
mod txversion;
|
||||
mod typeindex;
|
||||
mod typeindex_with_txoutindex;
|
||||
mod typeindexandoutpoint;
|
||||
mod typeindexandtxindex;
|
||||
mod unit;
|
||||
mod unknownoutputindex;
|
||||
mod vin;
|
||||
@@ -139,6 +141,7 @@ pub use metrics::*;
|
||||
pub use monthindex::*;
|
||||
pub use ohlc::*;
|
||||
pub use opreturnindex::*;
|
||||
pub use outpoint::*;
|
||||
pub use outputtype::*;
|
||||
pub use p2aaddressindex::*;
|
||||
pub use p2abytes::*;
|
||||
@@ -187,7 +190,8 @@ pub use txoutindex::*;
|
||||
pub use txstatus::*;
|
||||
pub use txversion::*;
|
||||
pub use typeindex::*;
|
||||
pub use typeindex_with_txoutindex::*;
|
||||
pub use typeindexandoutpoint::*;
|
||||
pub use typeindexandtxindex::*;
|
||||
pub use unit::*;
|
||||
pub use unknownoutputindex::*;
|
||||
pub use vin::*;
|
||||
@@ -196,6 +200,19 @@ pub use weekindex::*;
|
||||
pub use weight::*;
|
||||
pub use yearindex::*;
|
||||
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn copy_first_2bytes(slice: &[u8]) -> Result<[u8; 2]> {
|
||||
let mut buf: [u8; 2] = [0; 2];
|
||||
let buf_len = buf.len();
|
||||
if slice.len() < buf_len {
|
||||
return Err(Error::Str("Buffer is too small to convert to 8 bytes"));
|
||||
}
|
||||
slice.iter().take(buf_len).enumerate().for_each(|(i, r)| {
|
||||
buf[i] = *r;
|
||||
});
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn copy_first_4bytes(slice: &[u8]) -> Result<[u8; 4]> {
|
||||
let mut buf: [u8; 4] = [0; 4];
|
||||
|
||||
79
crates/brk_structs/src/outpoint.rs
Normal file
79
crates/brk_structs/src/outpoint.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use allocative::Allocative;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{TxIndex, Vout};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
Allocative,
|
||||
JsonSchema,
|
||||
)]
|
||||
pub struct OutPoint {
|
||||
txindex: TxIndex,
|
||||
vout: Vout,
|
||||
_padding: u16,
|
||||
}
|
||||
|
||||
impl OutPoint {
|
||||
pub const COINBASE: Self = Self {
|
||||
txindex: TxIndex::COINBASE,
|
||||
vout: Vout::MAX,
|
||||
_padding: 0,
|
||||
};
|
||||
|
||||
pub fn new(txindex: TxIndex, vout: Vout) -> Self {
|
||||
Self {
|
||||
txindex,
|
||||
vout,
|
||||
_padding: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn txindex(&self) -> TxIndex {
|
||||
self.txindex
|
||||
}
|
||||
|
||||
pub fn vout(&self) -> Vout {
|
||||
self.vout
|
||||
}
|
||||
|
||||
pub fn is_coinbase(self) -> bool {
|
||||
self == Self::COINBASE
|
||||
}
|
||||
|
||||
pub fn to_be_bytes(&self) -> [u8; 6] {
|
||||
let txindex = self.txindex.to_be_bytes();
|
||||
let vout = self.vout.to_be_bytes();
|
||||
[
|
||||
txindex[0], txindex[1], txindex[2], txindex[3], vout[0], vout[1],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for OutPoint {
|
||||
fn from(value: &[u8]) -> Self {
|
||||
let txindex = TxIndex::from(&value[4..8]);
|
||||
let vout = Vout::from(&value[8..10]);
|
||||
Self::new(txindex, vout)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for OutPoint {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "txindex: {}, vout: {}", self.txindex, self.vout)
|
||||
}
|
||||
}
|
||||
@@ -36,492 +36,736 @@ pub enum OutputType {
|
||||
P2WSH,
|
||||
P2TR,
|
||||
P2A,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy10,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy11,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy12,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy13,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy14,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy15,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy16,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy17,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy18,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy19,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy20,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy21,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy22,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy23,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy24,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy25,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy26,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy27,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy28,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy29,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy30,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy31,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy32,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy33,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy34,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy35,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy36,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy37,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy38,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy39,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy40,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy41,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy42,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy43,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy44,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy45,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy46,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy47,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy48,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy49,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy50,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy51,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy52,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy53,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy54,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy55,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy56,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy57,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy58,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy59,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy60,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy61,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy62,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy63,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy64,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy65,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy66,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy67,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy68,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy69,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy70,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy71,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy72,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy73,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy74,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy75,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy76,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy77,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy78,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy79,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy80,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy81,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy82,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy83,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy84,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy85,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy86,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy87,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy88,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy89,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy90,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy91,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy92,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy93,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy94,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy95,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy96,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy97,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy98,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy99,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy100,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy101,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy102,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy103,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy104,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy105,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy106,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy107,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy108,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy109,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy110,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy111,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy112,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy113,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy114,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy115,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy116,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy117,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy118,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy119,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy120,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy121,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy122,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy123,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy124,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy125,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy126,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy127,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy128,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy129,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy130,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy131,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy132,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy133,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy134,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy135,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy136,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy137,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy138,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy139,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy140,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy141,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy142,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy143,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy144,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy145,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy146,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy147,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy148,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy149,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy150,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy151,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy152,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy153,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy154,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy155,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy156,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy157,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy158,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy159,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy160,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy161,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy162,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy163,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy164,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy165,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy166,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy167,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy168,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy169,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy170,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy171,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy172,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy173,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy174,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy175,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy176,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy177,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy178,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy179,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy180,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy181,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy182,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy183,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy184,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy185,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy186,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy187,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy188,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy189,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy190,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy191,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy192,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy193,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy194,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy195,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy196,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy197,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy198,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy199,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy200,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy201,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy202,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy203,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy204,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy205,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy206,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy207,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy208,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy209,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy210,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy211,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy212,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy213,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy214,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy215,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy216,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy217,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy218,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy219,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy220,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy221,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy222,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy223,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy224,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy225,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy226,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy227,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy228,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy229,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy230,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy231,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy232,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy233,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy234,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy235,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy236,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy237,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy238,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy239,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy240,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy241,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy242,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy243,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy244,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy245,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy246,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy247,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy248,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy249,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy250,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy251,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy252,
|
||||
#[doc(hidden)]
|
||||
#[schemars(skip)]
|
||||
Dummy253,
|
||||
Empty = 254,
|
||||
|
||||
@@ -36,6 +36,7 @@ pub struct TxIndex(u32);
|
||||
|
||||
impl TxIndex {
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const COINBASE: Self = Self(u32::MAX);
|
||||
|
||||
pub fn new(txindex: u32) -> Self {
|
||||
Self(txindex)
|
||||
@@ -44,6 +45,10 @@ impl TxIndex {
|
||||
pub fn incremented(self) -> Self {
|
||||
Self(*self + 1)
|
||||
}
|
||||
|
||||
pub fn to_be_bytes(&self) -> [u8; 4] {
|
||||
self.0.to_be_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<TxIndex> for TxIndex {
|
||||
@@ -78,6 +83,12 @@ impl From<u32> for TxIndex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxIndex> for u32 {
|
||||
fn from(value: TxIndex) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for TxIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value as u32)
|
||||
@@ -117,6 +128,12 @@ impl From<TxIndex> for StoredU32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for TxIndex {
|
||||
fn from(value: &[u8]) -> Self {
|
||||
Self(u32::from_be_bytes(copy_first_4bytes(value).unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl PrintableIndex for TxIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"txindex"
|
||||
|
||||
@@ -105,7 +105,7 @@ impl PrintableIndex for TxInIndex {
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["in", "txinindex"]
|
||||
&["txi", "txin", "txinindex"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ impl PrintableIndex for TxOutIndex {
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["out", "txoutindex"]
|
||||
&["txo", "txout", "txoutindex"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
use byteview::ByteView;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::{TxOutIndex, TypeIndex};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Serialize)]
|
||||
pub struct TypeIndexWithOutputindex {
|
||||
typeindex: TypeIndex,
|
||||
txoutindex: TxOutIndex,
|
||||
}
|
||||
|
||||
impl From<(TypeIndex, TxOutIndex)> for TypeIndexWithOutputindex {
|
||||
fn from(value: (TypeIndex, TxOutIndex)) -> Self {
|
||||
Self {
|
||||
typeindex: value.0,
|
||||
txoutindex: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for TypeIndexWithOutputindex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
let typeindex = TypeIndex::from(&value[0..4]);
|
||||
let txoutindex = TxOutIndex::from(&value[4..12]);
|
||||
Self {
|
||||
typeindex,
|
||||
txoutindex,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TypeIndexWithOutputindex> for ByteView {
|
||||
fn from(value: TypeIndexWithOutputindex) -> Self {
|
||||
ByteView::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&TypeIndexWithOutputindex> for ByteView {
|
||||
fn from(value: &TypeIndexWithOutputindex) -> Self {
|
||||
ByteView::from(
|
||||
[
|
||||
u32::from(value.typeindex).to_be_bytes().as_slice(),
|
||||
u64::from(value.txoutindex).to_be_bytes().as_slice(),
|
||||
]
|
||||
.concat(),
|
||||
)
|
||||
}
|
||||
}
|
||||
45
crates/brk_structs/src/typeindexandoutpoint.rs
Normal file
45
crates/brk_structs/src/typeindexandoutpoint.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use byteview::ByteView;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::{OutPoint, TypeIndex};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Serialize)]
|
||||
pub struct TypeIndexAndOutPoint {
|
||||
typeindex: TypeIndex,
|
||||
outpoint: OutPoint,
|
||||
}
|
||||
|
||||
impl From<(TypeIndex, OutPoint)> for TypeIndexAndOutPoint {
|
||||
fn from(value: (TypeIndex, OutPoint)) -> Self {
|
||||
Self {
|
||||
typeindex: value.0,
|
||||
outpoint: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for TypeIndexAndOutPoint {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self {
|
||||
typeindex: TypeIndex::from(&value[0..4]),
|
||||
outpoint: OutPoint::from(&value[4..]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TypeIndexAndOutPoint> for ByteView {
|
||||
fn from(value: TypeIndexAndOutPoint) -> Self {
|
||||
ByteView::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&TypeIndexAndOutPoint> for ByteView {
|
||||
fn from(value: &TypeIndexAndOutPoint) -> Self {
|
||||
ByteView::from(
|
||||
[
|
||||
u32::from(value.typeindex).to_be_bytes().as_slice(),
|
||||
value.outpoint.to_be_bytes().as_slice(),
|
||||
]
|
||||
.concat(),
|
||||
)
|
||||
}
|
||||
}
|
||||
44
crates/brk_structs/src/typeindexandtxindex.rs
Normal file
44
crates/brk_structs/src/typeindexandtxindex.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use byteview::ByteView;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::{TxIndex, TypeIndex};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Serialize)]
|
||||
pub struct TypeIndexAndTxIndex {
|
||||
typeindex: TypeIndex,
|
||||
txindex: TxIndex,
|
||||
}
|
||||
|
||||
impl From<(TypeIndex, TxIndex)> for TypeIndexAndTxIndex {
|
||||
fn from(value: (TypeIndex, TxIndex)) -> Self {
|
||||
Self {
|
||||
typeindex: value.0,
|
||||
txindex: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for TypeIndexAndTxIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
let typeindex = TypeIndex::from(&value[0..4]);
|
||||
let txindex = TxIndex::from(&value[4..8]);
|
||||
Self { typeindex, txindex }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TypeIndexAndTxIndex> for ByteView {
|
||||
fn from(value: TypeIndexAndTxIndex) -> Self {
|
||||
ByteView::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&TypeIndexAndTxIndex> for ByteView {
|
||||
fn from(value: &TypeIndexAndTxIndex) -> Self {
|
||||
ByteView::from(
|
||||
[
|
||||
u32::from(value.typeindex).to_be_bytes().as_slice(),
|
||||
u32::from(value.txindex).to_be_bytes().as_slice(),
|
||||
]
|
||||
.concat(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use derive_deref::Deref;
|
||||
|
||||
#[derive(Debug, Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Vin(u32);
|
||||
pub struct Vin(u16);
|
||||
|
||||
impl Vin {
|
||||
pub const ZERO: Self = Vin(0);
|
||||
@@ -12,15 +12,23 @@ impl Vin {
|
||||
}
|
||||
}
|
||||
|
||||
const U16_MAX_AS_U32: u32 = u16::MAX as u32;
|
||||
impl From<u32> for Vin {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
if value > U16_MAX_AS_U32 {
|
||||
panic!()
|
||||
}
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
const U16_MAX_AS_USIZE: usize = u16::MAX as usize;
|
||||
impl From<usize> for Vin {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
if value > U16_MAX_AS_USIZE {
|
||||
panic!()
|
||||
}
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,62 @@
|
||||
use allocative::Allocative;
|
||||
use derive_deref::Deref;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::copy_first_2bytes;
|
||||
|
||||
/// Index of the output being spent in the previous transaction
|
||||
#[derive(Debug, Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, JsonSchema)]
|
||||
pub struct Vout(u32);
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
Allocative,
|
||||
JsonSchema,
|
||||
)]
|
||||
pub struct Vout(u16);
|
||||
|
||||
impl Vout {
|
||||
const ZERO: Self = Vout(0);
|
||||
pub const ZERO: Self = Vout(0);
|
||||
pub const MAX: Self = Vout(u16::MAX);
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
*self == Self::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Vout {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
pub fn to_be_bytes(&self) -> [u8; 2] {
|
||||
self.0.to_be_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
const U16_MAX_AS_U32: u32 = u16::MAX as u32;
|
||||
impl From<u32> for Vout {
|
||||
fn from(value: u32) -> Self {
|
||||
if value > U16_MAX_AS_U32 {
|
||||
panic!()
|
||||
}
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
const U16_MAX_AS_USIZE: usize = u16::MAX as usize;
|
||||
impl From<usize> for Vout {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
if value > U16_MAX_AS_USIZE {
|
||||
panic!()
|
||||
}
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,3 +65,15 @@ impl From<Vout> for u64 {
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for Vout {
|
||||
fn from(value: &[u8]) -> Self {
|
||||
Self(u16::from_be_bytes(copy_first_2bytes(value).unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Vout {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="description" content="Bitcoin transparency, amplified" />
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
|
||||
Reference in New Issue
Block a user