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:
Andrew Poelstra 2014-07-23 11:27:03 -07:00
parent b5c25ff768
commit 1be45395da
1 changed files with 8 additions and 8 deletions

View File

@ -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);
} }