Store TxOuts directly in UtxoSet rather than in Boxes
This gives a significant speedup during deserialization since we don't have to allocate for every output.
This commit is contained in:
parent
b5c25ff768
commit
1be45395da
|
@ -32,14 +32,14 @@ use util::uint::Uint128;
|
||||||
use util::thinvec::ThinVec;
|
use util::thinvec::ThinVec;
|
||||||
|
|
||||||
/// Vector of outputs; None indicates a nonexistent or already spent output
|
/// Vector of outputs; None indicates a nonexistent or already spent output
|
||||||
type UtxoNode = ThinVec<Option<Box<TxOut>>>;
|
type UtxoNode = ThinVec<Option<TxOut>>;
|
||||||
|
|
||||||
/// The UTXO set
|
/// The UTXO set
|
||||||
pub struct UtxoSet {
|
pub struct UtxoSet {
|
||||||
table: HashMap<Uint128, UtxoNode, DumbHasher>,
|
table: HashMap<Uint128, UtxoNode, DumbHasher>,
|
||||||
last_hash: Sha256dHash,
|
last_hash: Sha256dHash,
|
||||||
// A circular buffer of deleted utxos, grouped by block
|
// A circular buffer of deleted utxos, grouped by block
|
||||||
spent_txos: Vec<Vec<Box<TxOut>>>,
|
spent_txos: Vec<Vec<TxOut>>,
|
||||||
// The last index into the above buffer that was assigned to
|
// The last index into the above buffer that was assigned to
|
||||||
spent_idx: u64,
|
spent_idx: u64,
|
||||||
n_utxos: u64
|
n_utxos: u64
|
||||||
|
@ -70,7 +70,7 @@ impl UtxoSet {
|
||||||
let mut new_node = ThinVec::with_capacity(tx.output.len() as u32);
|
let mut new_node = ThinVec::with_capacity(tx.output.len() as u32);
|
||||||
for (vout, txo) in tx.output.iter().enumerate() {
|
for (vout, txo) in tx.output.iter().enumerate() {
|
||||||
// Unsafe since we are not uninitializing the old data in the vector
|
// Unsafe since we are not uninitializing the old data in the vector
|
||||||
unsafe { new_node.init(vout as uint, Some(box txo.clone())); }
|
unsafe { new_node.init(vout as uint, Some(txo.clone())); }
|
||||||
}
|
}
|
||||||
// TODO: insert/lookup should return a Result which we pass along
|
// TODO: insert/lookup should return a Result which we pass along
|
||||||
if self.table.insert(txid.as_uint128(), new_node) {
|
if self.table.insert(txid.as_uint128(), new_node) {
|
||||||
|
@ -81,7 +81,7 @@ impl UtxoSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove a UTXO from the set and return it
|
/// Remove a UTXO from the set and return it
|
||||||
fn take_utxo(&mut self, txid: Sha256dHash, vout: u32) -> Option<Box<TxOut>> {
|
fn take_utxo(&mut self, txid: Sha256dHash, vout: u32) -> Option<TxOut> {
|
||||||
// This whole function has awkward scoping thx to lexical borrow scoping :(
|
// This whole function has awkward scoping thx to lexical borrow scoping :(
|
||||||
let (ret, should_delete) = {
|
let (ret, should_delete) = {
|
||||||
// Locate the UTXO, failing if not found
|
// Locate the UTXO, failing if not found
|
||||||
|
@ -111,7 +111,7 @@ impl UtxoSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to a UTXO in the set
|
/// Get a reference to a UTXO in the set
|
||||||
pub fn get_utxo<'a>(&'a mut self, txid: Sha256dHash, vout: u32) -> Option<&'a Box<TxOut>> {
|
pub fn get_utxo<'a>(&'a mut self, txid: Sha256dHash, vout: u32) -> Option<&'a TxOut> {
|
||||||
// Locate the UTXO, failing if not found
|
// Locate the UTXO, failing if not found
|
||||||
let node = match self.table.find_mut(&txid.as_uint128()) {
|
let node = match self.table.find_mut(&txid.as_uint128()) {
|
||||||
Some(node) => node,
|
Some(node) => node,
|
||||||
|
@ -289,7 +289,7 @@ mod tests {
|
||||||
let hash = tx.bitcoin_hash();
|
let hash = tx.bitcoin_hash();
|
||||||
for (n, out) in tx.output.iter().enumerate() {
|
for (n, out) in tx.output.iter().enumerate() {
|
||||||
let n = n as u32;
|
let n = n as u32;
|
||||||
assert_eq!(empty_set.get_utxo(hash, n), Some(&box out.clone()));
|
assert_eq!(empty_set.get_utxo(hash, n), Some(&out.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ mod tests {
|
||||||
let hash = tx.bitcoin_hash();
|
let hash = tx.bitcoin_hash();
|
||||||
for (n, out) in tx.output.iter().enumerate() {
|
for (n, out) in tx.output.iter().enumerate() {
|
||||||
let n = n as u32;
|
let n = n as u32;
|
||||||
assert_eq!(empty_set.get_utxo(hash, n), Some(&box out.clone()));
|
assert_eq!(empty_set.get_utxo(hash, n), Some(&out.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +323,7 @@ mod tests {
|
||||||
assert_eq!(read_set.take_utxo(hash, 100 + n), None);
|
assert_eq!(read_set.take_utxo(hash, 100 + n), None);
|
||||||
// Check take of real UTXO
|
// Check take of real UTXO
|
||||||
let ret = read_set.take_utxo(hash, n);
|
let ret = read_set.take_utxo(hash, n);
|
||||||
assert_eq!(ret, Some(box out.clone()));
|
assert_eq!(ret, Some(out.clone()));
|
||||||
// Try double-take
|
// Try double-take
|
||||||
assert_eq!(read_set.take_utxo(hash, n), None);
|
assert_eq!(read_set.take_utxo(hash, n), None);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue