mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-24 16:54:47 -07:00
bitbase: rayon done
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use std::{collections::BTreeMap, path::Path, str::FromStr};
|
use std::{collections::BTreeMap, path::Path, str::FromStr, thread};
|
||||||
|
|
||||||
use biter::{
|
use biter::{
|
||||||
bitcoin::{hashes::Hash, Txid},
|
bitcoin::{hashes::Hash, TxIn, TxOut, Txid},
|
||||||
bitcoincore_rpc::{Auth, Client},
|
bitcoincore_rpc::{Auth, Client},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,9 +22,16 @@ const DAILY_BLOCK_TARGET: usize = 144;
|
|||||||
const MONTHLY_BLOCK_TARGET: usize = DAILY_BLOCK_TARGET * 30;
|
const MONTHLY_BLOCK_TARGET: usize = DAILY_BLOCK_TARGET * 30;
|
||||||
const U16MAX: usize = u16::MAX as usize;
|
const U16MAX: usize = u16::MAX as usize;
|
||||||
|
|
||||||
|
enum TxInOrAddresstxoutindex<'a> {
|
||||||
|
TxIn(&'a TxIn),
|
||||||
|
Addresstxoutindex(Addresstxoutindex),
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> color_eyre::Result<()> {
|
fn main() -> color_eyre::Result<()> {
|
||||||
let i = std::time::Instant::now();
|
let i = std::time::Instant::now();
|
||||||
|
|
||||||
|
let check_collisions = true;
|
||||||
|
|
||||||
let data_dir = Path::new("../../../../bitcoin");
|
let data_dir = Path::new("../../../../bitcoin");
|
||||||
let cookie = Path::new(data_dir).join(".cookie");
|
let cookie = Path::new(data_dir).join(".cookie");
|
||||||
let rpc = Client::new("http://localhost:8332", Auth::CookieFile(cookie)).unwrap();
|
let rpc = Client::new("http://localhost:8332", Auth::CookieFile(cookie)).unwrap();
|
||||||
@@ -86,14 +93,16 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if parts.blockhash_prefix_to_height.needs(height) {
|
if parts.blockhash_prefix_to_height.needs(height) {
|
||||||
if let Some(prev_height_slice) =
|
if check_collisions {
|
||||||
wtx.fetch_update(parts.blockhash_prefix_to_height.data(), blockhash.prefix(), |_| {
|
if let Some(prev_height_slice) =
|
||||||
Some(Slice::from(height))
|
wtx.get(parts.blockhash_prefix_to_height.data(), blockhash.prefix())?
|
||||||
})?
|
{
|
||||||
{
|
dbg!(blockhash, Height::from(prev_height_slice));
|
||||||
dbg!(blockhash, Height::from(prev_height_slice));
|
return Err(eyre!("Collision, expect prefix to need be set yet"));
|
||||||
return Err(eyre!("Collision, expect prefix to need be set yet"));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wtx.insert(parts.blockhash_prefix_to_height.data(), blockhash.prefix(),Slice::from(height));
|
||||||
}
|
}
|
||||||
|
|
||||||
if parts.height_to_blockhash.needs(height) {
|
if parts.height_to_blockhash.needs(height) {
|
||||||
@@ -111,107 +120,316 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
let txlen = block.txdata.len();
|
let txlen = block.txdata.len();
|
||||||
let last_txi = txlen - 1;
|
let last_txi = txlen - 1;
|
||||||
|
|
||||||
let mut txi_to_txid_and_prev_txindex_slice_opt = block
|
let (txid_to_index_join_handle, txin_or_addresstxoutindex_vec_handle, txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle) = thread::scope(|scope| {
|
||||||
.txdata
|
let txid_to_index_handle = scope.spawn(|| -> color_eyre::Result<_> {
|
||||||
.par_iter()
|
block
|
||||||
.enumerate()
|
.txdata
|
||||||
.map(|(txi, tx)| -> color_eyre::Result<(usize, (Txid, Option<Slice>))> {
|
.par_iter()
|
||||||
let txid = tx.compute_txid();
|
.enumerate()
|
||||||
|
.map(|(index, tx)| -> color_eyre::Result<_> {
|
||||||
|
let txid = tx.compute_txid();
|
||||||
|
|
||||||
let prev_txindex_slice_opt = wtx.get(parts.txid_prefix_to_txindex.data(), txid.prefix())?;
|
// Could be removed as should only trigger for two txid (duplicates)
|
||||||
|
let prev_txindex_slice_opt = wtx.get(parts.txid_prefix_to_txindex.data(), txid.prefix())?;
|
||||||
|
|
||||||
Ok((txi, (txid, prev_txindex_slice_opt)))
|
Ok((txid, (index, prev_txindex_slice_opt)))
|
||||||
})
|
})
|
||||||
.try_fold(
|
.try_fold(
|
||||||
|| -> BTreeMap<usize, (Txid, Option<Slice>)> { BTreeMap::default() },
|
BTreeMap::new,
|
||||||
|mut map, tuple| -> color_eyre::Result<BTreeMap<usize, (Txid, Option<Slice>)>> {
|
|mut map, tuple| {
|
||||||
let (txi, tuple) = tuple?;
|
let (key, value) = tuple?;
|
||||||
map.insert(txi, tuple);
|
map.insert(key, value);
|
||||||
Ok(map)
|
Ok(map)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.try_reduce(BTreeMap::default, |mut map, mut map2| {
|
.try_reduce(BTreeMap::new, |mut map, mut map2| {
|
||||||
if map.len() > map2.len() {
|
if map.len() > map2.len() {
|
||||||
map.append(&mut map2);
|
map.append(&mut map2);
|
||||||
Ok(map)
|
Ok(map)
|
||||||
} else {
|
} else {
|
||||||
map2.append(&mut map);
|
map2.append(&mut map);
|
||||||
Ok(map2)
|
Ok(map2)
|
||||||
|
}
|
||||||
|
})});
|
||||||
|
|
||||||
|
let txin_or_addresstxoutindex_vec_handle = scope.spawn(|| -> color_eyre::Result<Vec<TxInOrAddresstxoutindex>> {
|
||||||
|
block
|
||||||
|
.txdata
|
||||||
|
.par_iter()
|
||||||
|
.filter(|tx| !tx.is_coinbase())
|
||||||
|
.flat_map(|tx| &tx.input)
|
||||||
|
.map(|txin| -> color_eyre::Result<_> {
|
||||||
|
let outpoint = txin.previous_output;
|
||||||
|
let txid_prefix = outpoint.txid.prefix();
|
||||||
|
let vout = outpoint.vout as u16;
|
||||||
|
|
||||||
|
let txindex = if let Some(txindex) = wtx
|
||||||
|
.get(parts.txid_prefix_to_txindex.data(), txid_prefix)?
|
||||||
|
.map(Txindex::from)
|
||||||
|
{
|
||||||
|
txindex
|
||||||
|
} else {
|
||||||
|
return Ok(TxInOrAddresstxoutindex::TxIn(txin));
|
||||||
|
};
|
||||||
|
|
||||||
|
let txoutindex = Txoutindex::from((txindex, vout));
|
||||||
|
|
||||||
|
let addressindex = Addressindex::from(
|
||||||
|
wtx.get(parts.txoutindex_to_addressindex.data(), Slice::from(txoutindex))?
|
||||||
|
.context("Expect addressindex to not be none")
|
||||||
|
.inspect_err(|_| {
|
||||||
|
let height = Height::from(
|
||||||
|
wtx.get(parts.txindex_to_height.data(), Slice::from(txindex))
|
||||||
|
.expect("txindex_to_height get not fail")
|
||||||
|
.expect("Expect height for txindex"),
|
||||||
|
);
|
||||||
|
dbg!(outpoint.txid, txindex, vout, txoutindex, height);
|
||||||
|
})?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(TxInOrAddresstxoutindex::Addresstxoutindex(Addresstxoutindex::from((
|
||||||
|
addressindex,
|
||||||
|
txoutindex,
|
||||||
|
))))
|
||||||
|
})
|
||||||
|
.try_fold(
|
||||||
|
Vec::new,
|
||||||
|
|mut vec, addresstxoutindex| {
|
||||||
|
// There is no need to check for bad_tx as there are only 2 instances known
|
||||||
|
// Which you can find below and which are coinbase tx and thus which are already filtered
|
||||||
|
if parts.addresstxoutindexes_out.needs(height) {
|
||||||
|
vec.push(addresstxoutindex?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(vec)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.try_reduce(Vec::new, |mut v, mut v2| {
|
||||||
|
if v.len() > v2.len() {
|
||||||
|
v.append(&mut v2);
|
||||||
|
Ok(v)
|
||||||
|
} else {
|
||||||
|
v2.append(&mut v);
|
||||||
|
Ok(v2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle = scope.spawn(|| -> color_eyre::Result<BTreeMap<Txoutindex,
|
||||||
|
(&TxOut, Addresstype, color_eyre::Result<Addressbytes>, Option<Slice>)>> {
|
||||||
|
block
|
||||||
|
.txdata
|
||||||
|
.par_iter()
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(|(index, tx)| {
|
||||||
|
tx.output
|
||||||
|
.par_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(move |(vout, txout)| (index, vout, txout))
|
||||||
|
})
|
||||||
|
.map(
|
||||||
|
|(index, vout, txout)| {
|
||||||
|
if vout > U16MAX {
|
||||||
|
return Err(eyre!("vout bigger than u16::MAX"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let vout = vout as u16;
|
||||||
|
let txindex = txindex + index;
|
||||||
|
let txoutindex = Txoutindex::from((txindex, vout));
|
||||||
|
|
||||||
|
let script = &txout.script_pubkey;
|
||||||
|
|
||||||
|
let addresstype = Addresstype::from(script);
|
||||||
|
|
||||||
|
let addressbytes_res = Addressbytes::try_from((script, addresstype)).inspect_err(|_| {
|
||||||
|
// dbg!(&txout, height, txi, &tx.compute_txid());
|
||||||
|
});
|
||||||
|
|
||||||
|
let addressindex_slice_opt = addressbytes_res.as_ref().ok().and_then(|addressbytes| {
|
||||||
|
wtx.get(
|
||||||
|
parts.addressbytes_prefix_to_addressindex.data(),
|
||||||
|
Slice::from(addressbytes),
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s)
|
||||||
|
});
|
||||||
|
|
||||||
|
let is_new_address = addressindex_slice_opt.is_none();
|
||||||
|
|
||||||
|
if check_collisions && is_new_address {
|
||||||
|
if let Ok(addressbytes) = &addressbytes_res {
|
||||||
|
if let Some(prev) = wtx.get(
|
||||||
|
parts.addressbytes_prefix_to_addressindex.data(),
|
||||||
|
Slice::from(addressbytes),
|
||||||
|
)? {
|
||||||
|
dbg!(prev);
|
||||||
|
return Err(eyre!("addressbytes_prefix_to_addressindex collision, expect none"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
txoutindex,
|
||||||
|
(txout, addresstype, addressbytes_res, addressindex_slice_opt),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.try_fold(
|
||||||
|
BTreeMap::new,
|
||||||
|
|mut map, tuple| -> color_eyre::Result<_> {
|
||||||
|
let (key, value) = tuple?;
|
||||||
|
map.insert(key, value);
|
||||||
|
Ok(map)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.try_reduce(BTreeMap::new, |mut map, mut map2| {
|
||||||
|
if map.len() > map2.len() {
|
||||||
|
map.append(&mut map2);
|
||||||
|
Ok(map)
|
||||||
|
} else {
|
||||||
|
map2.append(&mut map);
|
||||||
|
Ok(map2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
(txid_to_index_handle.join(), txin_or_addresstxoutindex_vec_handle.join(), txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle.join())
|
||||||
|
});
|
||||||
|
|
||||||
|
let txid_to_index = txid_to_index_join_handle.ok().context("Expect txid_to_index_join_handle to join")??;
|
||||||
|
|
||||||
|
let txin_or_addresstxoutindex_vec = txin_or_addresstxoutindex_vec_handle.ok().context("Export txin_or_addresstxoutindex_vec_handle to join")??;
|
||||||
|
|
||||||
|
let txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt = txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle.ok().context("Expect txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle to join")??;
|
||||||
|
|
||||||
|
let mut new_txoutindex_to_addressindex: BTreeMap<Txoutindex, Addressindex> = BTreeMap::new();
|
||||||
|
|
||||||
|
txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt
|
||||||
|
.into_iter()
|
||||||
|
.try_for_each(|(txoutindex, (txout, addresstype, addressbytes_res, addressindex_slice_opt))| -> color_eyre::Result<()> {
|
||||||
|
let amount = Amount::from(txout.value);
|
||||||
|
|
||||||
|
let mut addressindex_local = addressindex;
|
||||||
|
|
||||||
|
if amount.is_zero() {
|
||||||
|
if parts.zero_txoutindexes.needs(height) {
|
||||||
|
wtx.insert(
|
||||||
|
parts.zero_txoutindexes.data(),
|
||||||
|
Slice::from(txoutindex),
|
||||||
|
Slice::default(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if parts.txoutindex_to_amount.needs(height) {
|
||||||
|
wtx.insert(
|
||||||
|
parts.txoutindex_to_amount.data(),
|
||||||
|
Slice::from(txoutindex),
|
||||||
|
Slice::from(amount),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(addressindex_slice) = addressindex_slice_opt {
|
||||||
|
addressindex_local = addressindex_slice.into()
|
||||||
|
} else {
|
||||||
|
new_txoutindex_to_addressindex.insert(txoutindex, addressindex_local);
|
||||||
|
|
||||||
|
if parts.addressindex_to_addresstype.needs(height) {
|
||||||
|
wtx.insert(
|
||||||
|
parts.addressindex_to_addresstype.data(),
|
||||||
|
Slice::from(addressindex_local),
|
||||||
|
Slice::from(addresstype),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(addressbytes) = addressbytes_res {
|
||||||
|
if parts.addressbytes_prefix_to_addressindex.needs(height) {
|
||||||
|
wtx.insert(
|
||||||
|
parts.addressbytes_prefix_to_addressindex.data(),
|
||||||
|
Slice::from(addressbytes.prefix()),
|
||||||
|
Slice::from(addressindex_local),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if parts.addressindex_to_addressbytes.needs(height) {
|
||||||
|
wtx.insert(
|
||||||
|
parts.addressindex_to_addressbytes.data(),
|
||||||
|
Slice::from(addressindex_local),
|
||||||
|
Slice::from(&addressbytes),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
addressindex.increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
if parts.txoutindex_to_addressindex.needs(height) {
|
||||||
|
wtx.insert(
|
||||||
|
parts.txoutindex_to_addressindex.data(),
|
||||||
|
Slice::from(txoutindex),
|
||||||
|
Slice::from(addressindex_local),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let addresstxoutindex = Addresstxoutindex::from((addressindex_local, txoutindex));
|
||||||
|
|
||||||
|
if parts.addresstxoutindexes_in.needs(height) {
|
||||||
|
wtx.insert(
|
||||||
|
parts.addresstxoutindexes_in.data(),
|
||||||
|
Slice::from(addresstxoutindex),
|
||||||
|
Slice::default(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// let addresstxoutindexes_out = block
|
if parts.addresstxoutindexes_out.needs(height) {
|
||||||
// .txdata
|
txin_or_addresstxoutindex_vec
|
||||||
// .par_iter()
|
|
||||||
// .filter(|tx| !tx.is_coinbase())
|
|
||||||
// .flat_map(|tx| &tx.input)
|
|
||||||
// .try_fold(
|
|
||||||
// || -> Vec<Addresstxoutindex> { vec![] },
|
|
||||||
// |mut vec, txin| -> color_eyre::Result<Vec<Addresstxoutindex>> {
|
|
||||||
// let outpoint = txin.previous_output;
|
|
||||||
// let txid_prefix = outpoint.txid.prefix();
|
|
||||||
// let vout = outpoint.vout as u16;
|
|
||||||
|
|
||||||
// let txindex = Txindex::from(
|
|
||||||
// wtx.get(parts.txid_prefix_to_txindex.data(), txid_prefix)?
|
|
||||||
// .context("Expect txid to be saved")?,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// let txoutindex = Txoutindex::from((txindex, vout));
|
|
||||||
|
|
||||||
// let addressindex = Addressindex::from(
|
|
||||||
// wtx.get(parts.txoutindex_to_addressindex.data(), Slice::from(txoutindex))?
|
|
||||||
// .context("Expect addressindex to not be none")
|
|
||||||
// .inspect_err(|_| {
|
|
||||||
// let height = Height::from(
|
|
||||||
// wtx.get(parts.txindex_to_height.data(), Slice::from(txindex))
|
|
||||||
// .expect("txindex_to_height get not fail")
|
|
||||||
// .expect("Expect height for txindex"),
|
|
||||||
// );
|
|
||||||
// dbg!(outpoint.txid, txindex, vout, txoutindex, height);
|
|
||||||
// })?,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if parts.addresstxoutindexes_out.needs(height) {
|
|
||||||
// vec.push(Addresstxoutindex::from((addressindex, txoutindex)));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Ok(vec)
|
|
||||||
// },
|
|
||||||
// )
|
|
||||||
// .try_reduce(Vec::new, |mut v, mut v2| {
|
|
||||||
// if v.len() > v2.len() {
|
|
||||||
// v.append(&mut v2);
|
|
||||||
// Ok(v)
|
|
||||||
// } else {
|
|
||||||
// v2.append(&mut v);
|
|
||||||
// Ok(v2)
|
|
||||||
// }
|
|
||||||
// })?;
|
|
||||||
|
|
||||||
// addresstxoutindexes_out.into_iter().for_each(|addresstxoutindex| {
|
|
||||||
// wtx.insert(
|
|
||||||
// parts.addresstxoutindexes_out.data(),
|
|
||||||
// Slice::from(addresstxoutindex),
|
|
||||||
// Slice::default(),
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
|
|
||||||
block
|
|
||||||
.txdata
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.map(|txin_or_addresstxoutindex| -> color_eyre::Result<Addresstxoutindex> {
|
||||||
.try_for_each(|(txi, tx)| -> color_eyre::Result<()> {
|
match txin_or_addresstxoutindex {
|
||||||
let is_coinbase = tx.is_coinbase();
|
TxInOrAddresstxoutindex::Addresstxoutindex(addresstxoutindex) => Ok(addresstxoutindex),
|
||||||
|
TxInOrAddresstxoutindex::TxIn(txin) => {
|
||||||
|
let outpoint = txin.previous_output;
|
||||||
|
let txid = outpoint.txid;
|
||||||
|
let vout = outpoint.vout as u16;
|
||||||
|
let index = txid_to_index
|
||||||
|
.get(&txid)
|
||||||
|
.context("txid should be in same block")?.0;
|
||||||
|
let txindex = txindex + index;
|
||||||
|
let txoutindex = Txoutindex::from((txindex, vout));
|
||||||
|
let addressindex = new_txoutindex_to_addressindex
|
||||||
|
.remove(&txoutindex)
|
||||||
|
.context("should have found addressindex from same block").inspect_err(|_| {
|
||||||
|
dbg!(txin, txoutindex);
|
||||||
|
})?;
|
||||||
|
|
||||||
if txi == 0 && parts.height_to_first_txindex.needs(height) {
|
Ok(Addresstxoutindex::from((addressindex, txoutindex)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.try_for_each(|addresstxoutindex| -> color_eyre::Result<()> {
|
||||||
|
wtx.insert(
|
||||||
|
parts.addresstxoutindexes_out.data(),
|
||||||
|
Slice::from(addresstxoutindex?),
|
||||||
|
Slice::default(),
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
txid_to_index.into_iter().try_for_each(
|
||||||
|
|(txid, (index, prev_txindex_slice_opt))| -> color_eyre::Result<()> {
|
||||||
|
let txindex = txindex + index;
|
||||||
|
|
||||||
|
if index == 0 && parts.height_to_first_txindex.needs(height) {
|
||||||
wtx.insert(
|
wtx.insert(
|
||||||
parts.height_to_first_txindex.data(),
|
parts.height_to_first_txindex.data(),
|
||||||
Slice::from(height),
|
Slice::from(height),
|
||||||
Slice::from(txindex),
|
Slice::from(txindex),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if txi == last_txi && parts.height_to_last_txindex.needs(height) {
|
if index == last_txi && parts.height_to_last_txindex.needs(height) {
|
||||||
wtx.insert(
|
wtx.insert(
|
||||||
parts.height_to_last_txindex.data(),
|
parts.height_to_last_txindex.data(),
|
||||||
Slice::from(height),
|
Slice::from(height),
|
||||||
@@ -219,15 +437,6 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bad_tx = false;
|
|
||||||
|
|
||||||
let (txid, prev_txindex_slice_opt) = txi_to_txid_and_prev_txindex_slice_opt
|
|
||||||
.remove(&txi)
|
|
||||||
.context("Par compute of tx should have worked")
|
|
||||||
.inspect_err(|_| {
|
|
||||||
dbg!(&txi_to_txid_and_prev_txindex_slice_opt, &txi, tx.compute_txid());
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if parts.txindex_to_txid.needs(height) {
|
if parts.txindex_to_txid.needs(height) {
|
||||||
wtx.insert(parts.txindex_to_txid.data(), Slice::from(txindex), txid);
|
wtx.insert(parts.txindex_to_txid.data(), Slice::from(txindex), txid);
|
||||||
}
|
}
|
||||||
@@ -239,18 +448,20 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(prev_txindex_slice) => {
|
Some(prev_txindex_slice) => {
|
||||||
|
// Ok if `get` is not par as should happen only twice
|
||||||
let prev_txid = Txid::from_slice(
|
let prev_txid = Txid::from_slice(
|
||||||
&wtx.get(parts.txindex_to_txid.data(), &prev_txindex_slice)?
|
&wtx.get(parts.txindex_to_txid.data(), &prev_txindex_slice)?
|
||||||
.expect("To have txid for txindex"),
|
.expect("To have txid for txindex"),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// If another Txid needs to be added to the list
|
||||||
|
// We need to check that it's also a coinbase tx otherwise par_iter inputs needs to be updated
|
||||||
let only_known_dup_txids = [
|
let only_known_dup_txids = [
|
||||||
Txid::from_str("d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599")?,
|
Txid::from_str("d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599")?,
|
||||||
Txid::from_str("e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468")?,
|
Txid::from_str("e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468")?,
|
||||||
];
|
];
|
||||||
|
|
||||||
let is_dup = only_known_dup_txids.contains(&prev_txid);
|
let is_dup = only_known_dup_txids.contains(&prev_txid);
|
||||||
bad_tx = is_dup;
|
|
||||||
|
|
||||||
if !is_dup {
|
if !is_dup {
|
||||||
let prev_height = Height::from(
|
let prev_height = Height::from(
|
||||||
@@ -272,174 +483,9 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.input
|
|
||||||
.par_iter()
|
|
||||||
// .into_par_iter()
|
|
||||||
.try_fold(
|
|
||||||
|| -> Vec<Addresstxoutindex> { vec![] },
|
|
||||||
|mut vec, txin| -> color_eyre::Result<Vec<Addresstxoutindex>> {
|
|
||||||
if is_coinbase {
|
|
||||||
return Ok(vec);
|
|
||||||
}
|
|
||||||
|
|
||||||
let outpoint = txin.previous_output;
|
|
||||||
let txid_prefix = outpoint.txid.prefix();
|
|
||||||
let vout = outpoint.vout as u16;
|
|
||||||
|
|
||||||
let txindex = Txindex::from(
|
|
||||||
wtx.get(parts.txid_prefix_to_txindex.data(), txid_prefix)?
|
|
||||||
.context("Expect txid to be saved")?,
|
|
||||||
);
|
|
||||||
|
|
||||||
let txoutindex = Txoutindex::from((txindex, vout));
|
|
||||||
|
|
||||||
let addressindex = Addressindex::from(
|
|
||||||
wtx.get(parts.txoutindex_to_addressindex.data(), Slice::from(txoutindex))?
|
|
||||||
.context("Expect addressindex to not be none")
|
|
||||||
.inspect_err(|_| {
|
|
||||||
let height = Height::from(
|
|
||||||
wtx.get(parts.txindex_to_height.data(), Slice::from(txindex))
|
|
||||||
.expect("txindex_to_height get not fail")
|
|
||||||
.expect("Expect height for txindex"),
|
|
||||||
);
|
|
||||||
dbg!(txid, outpoint.txid, txindex, vout, txoutindex, height);
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
|
|
||||||
if bad_tx {
|
|
||||||
dbg!(tx.compute_txid(), outpoint);
|
|
||||||
panic!("bad tx in input")
|
|
||||||
}
|
|
||||||
if !bad_tx && parts.addresstxoutindexes_out.needs(height) {
|
|
||||||
vec.push(Addresstxoutindex::from((addressindex, txoutindex)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(vec)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.try_reduce(Vec::new, |mut v, mut v2| {
|
|
||||||
if v.len() > v2.len() {
|
|
||||||
v.append(&mut v2);
|
|
||||||
Ok(v)
|
|
||||||
} else {
|
|
||||||
v2.append(&mut v);
|
|
||||||
Ok(v2)
|
|
||||||
}
|
|
||||||
})?
|
|
||||||
.into_iter()
|
|
||||||
.for_each(|addresstxoutindex| {
|
|
||||||
wtx.insert(
|
|
||||||
parts.addresstxoutindexes_out.data(),
|
|
||||||
Slice::from(addresstxoutindex),
|
|
||||||
Slice::default(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
tx.output
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.try_for_each(|(vout, txout)| -> color_eyre::Result<()> {
|
|
||||||
if vout > U16MAX {
|
|
||||||
return Err(eyre!("vout bigger than u16::MAX"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let vout = vout as u16;
|
|
||||||
let txoutindex = Txoutindex::from((txindex, vout));
|
|
||||||
let amount = Amount::from(txout.value);
|
|
||||||
|
|
||||||
if amount.is_zero() {
|
|
||||||
if parts.zero_txoutindexes.needs(height) {
|
|
||||||
wtx.insert(
|
|
||||||
parts.zero_txoutindexes.data(),
|
|
||||||
Slice::from(txoutindex),
|
|
||||||
Slice::default(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if parts.txoutindex_to_amount.needs(height) {
|
|
||||||
wtx.insert(
|
|
||||||
parts.txoutindex_to_amount.data(),
|
|
||||||
Slice::from(txoutindex),
|
|
||||||
Slice::from(amount),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let script = &txout.script_pubkey;
|
|
||||||
|
|
||||||
let mut addressindex_local = addressindex;
|
|
||||||
|
|
||||||
let addresstype = Addresstype::from(script);
|
|
||||||
|
|
||||||
let addressbytes = Addressbytes::try_from((script, addresstype)).inspect_err(|_| {
|
|
||||||
// dbg!(&txout, height, txi, &tx.compute_txid());
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(addressindex_slice) = addressbytes.as_ref().ok().and_then(|addressbytes| {
|
|
||||||
wtx.get(
|
|
||||||
parts.addressbytes_prefix_to_addressindex.data(),
|
|
||||||
Slice::from(addressbytes),
|
|
||||||
)
|
|
||||||
.ok()
|
|
||||||
.and_then(|s| s)
|
|
||||||
}) {
|
|
||||||
addressindex_local = addressindex_slice.into()
|
|
||||||
} else {
|
|
||||||
if parts.addressindex_to_addresstype.needs(height) {
|
|
||||||
wtx.insert(
|
|
||||||
parts.addressindex_to_addresstype.data(),
|
|
||||||
Slice::from(addressindex_local),
|
|
||||||
Slice::from(addresstype),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(addressbytes) = addressbytes {
|
|
||||||
if parts.addressbytes_prefix_to_addressindex.needs(height) {
|
|
||||||
if let Some(prev) = wtx.fetch_update(
|
|
||||||
parts.addressbytes_prefix_to_addressindex.data(),
|
|
||||||
Slice::from(&addressbytes),
|
|
||||||
|_| Some(Slice::from(addressindex_local)),
|
|
||||||
)? {
|
|
||||||
dbg!(prev);
|
|
||||||
return Err(eyre!("Expect none"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if parts.addressindex_to_addressbytes.needs(height) {
|
|
||||||
wtx.insert(
|
|
||||||
parts.addressindex_to_addressbytes.data(),
|
|
||||||
Slice::from(addressindex_local),
|
|
||||||
Slice::from(&addressbytes),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addressindex.increment();
|
|
||||||
}
|
|
||||||
|
|
||||||
if parts.txoutindex_to_addressindex.needs(height) {
|
|
||||||
wtx.insert(
|
|
||||||
parts.txoutindex_to_addressindex.data(),
|
|
||||||
Slice::from(txoutindex),
|
|
||||||
Slice::from(addressindex_local),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let addresstxoutindex = Addresstxoutindex::from((addressindex_local, txoutindex));
|
|
||||||
|
|
||||||
if !bad_tx && parts.addresstxoutindexes_in.needs(height) {
|
|
||||||
wtx.insert(
|
|
||||||
parts.addresstxoutindexes_in.data(),
|
|
||||||
Slice::from(addresstxoutindex),
|
|
||||||
Slice::default(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
txindex.increment();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
if parts.height_to_last_addressindex.needs(height) {
|
if parts.height_to_last_addressindex.needs(height) {
|
||||||
wtx.insert(
|
wtx.insert(
|
||||||
@@ -457,10 +503,12 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
wtx_opt.replace(wtx);
|
wtx_opt.replace(wtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txindex += txlen;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let wtx = wtx_opt.take().context("option should have WriteTransaction")?;
|
let wtx = wtx_opt.take().context("option should have wtx")?;
|
||||||
export(&keyspace, wtx, &parts, height)?;
|
export(&keyspace, wtx, &parts, height)?;
|
||||||
|
|
||||||
dbg!(i.elapsed());
|
dbg!(i.elapsed());
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use fjall::Slice;
|
|||||||
|
|
||||||
use super::Addresstype;
|
use super::Addresstype;
|
||||||
|
|
||||||
#[derive(Debug, Deref, DerefMut)]
|
#[derive(Debug, Deref, DerefMut, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Addressbytes(Slice);
|
pub struct Addressbytes(Slice);
|
||||||
|
|
||||||
impl TryFrom<(&ScriptBuf, Addresstype)> for Addressbytes {
|
impl TryFrom<(&ScriptBuf, Addresstype)> for Addressbytes {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::ops::{Add, AddAssign};
|
||||||
|
|
||||||
use derive_deref::{Deref, DerefMut};
|
use derive_deref::{Deref, DerefMut};
|
||||||
use fjall::Slice;
|
use fjall::Slice;
|
||||||
|
|
||||||
@@ -9,10 +11,6 @@ pub struct Txindex(u32);
|
|||||||
impl Txindex {
|
impl Txindex {
|
||||||
pub const BYTES: usize = size_of::<Self>();
|
pub const BYTES: usize = size_of::<Self>();
|
||||||
|
|
||||||
pub fn increment(&mut self) {
|
|
||||||
self.0 += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn incremented(self) -> Self {
|
pub fn incremented(self) -> Self {
|
||||||
Self(*self + 1)
|
Self(*self + 1)
|
||||||
}
|
}
|
||||||
@@ -45,3 +43,16 @@ impl From<Txindex> for Slice {
|
|||||||
value.to_be_bytes().into()
|
value.to_be_bytes().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Add<usize> for Txindex {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: usize) -> Self::Output {
|
||||||
|
Self(self.0 + rhs as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<usize> for Txindex {
|
||||||
|
fn add_assign(&mut self, rhs: usize) {
|
||||||
|
self.0 += rhs as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user