Skip to content

Commit

Permalink
Use get_or_insert_with in common_cache()
Browse files Browse the repository at this point in the history
There was a question whether this is equally performant. There are
multiple good reasons why it should be:

1. `get_or_insert_with` is marked `#[inline]`
2. Any good optimizer will inline a function that is used exactly once
3. 1 and 2 conclude that the closure will get inlined
4. Computing self.tx can then be moved to the only branch where it is
   required.
5. Even if get_or_insert_with didn't get optimized, which is extremely
   unlikely, the `tx` field is at the beginning of the struct and it
   probably has pointer alignment (`Deref` suggests it's a pointer).
   Alignment larger than pointer is not used, so we can expect the
   fields to be ordered as-defined. (This is not guaranteed by Rust but
   there's not good reason to change the order in this case.) We can
   assume that offset to tx is zero in most cases which means no
   computation is actually needed so the expression before closure is
   no-op short of passing it into the closure as an argument.

At the time of writing `#[inline]` can be seen at
https://doc.rust-lang.org/src/core/option.rs.html#933
  • Loading branch information
Kixunil committed Aug 10, 2021
1 parent ca80a5a commit 497dbfb
Showing 1 changed file with 7 additions and 8 deletions.
15 changes: 7 additions & 8 deletions src/util/sighash.rs
Expand Up @@ -550,29 +550,28 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
}

fn common_cache(&mut self) -> &CommonCache {
if self.common_cache.is_none() {
let tx = &self.tx;
self.common_cache.get_or_insert_with(|| {
let mut enc_prevouts = sha256::Hash::engine();
let mut enc_sequences = sha256::Hash::engine();
for txin in self.tx.input.iter() {
for txin in tx.input.iter() {
txin.previous_output
.consensus_encode(&mut enc_prevouts)
.unwrap();
txin.sequence.consensus_encode(&mut enc_sequences).unwrap();
}
let cache = CommonCache {
CommonCache {
prevouts: sha256::Hash::from_engine(enc_prevouts),
sequences: sha256::Hash::from_engine(enc_sequences),
outputs: {
let mut enc = sha256::Hash::engine();
for txout in self.tx.output.iter() {
for txout in tx.output.iter() {
txout.consensus_encode(&mut enc).unwrap();
}
sha256::Hash::from_engine(enc)
},
};
self.common_cache = Some(cache);
}
self.common_cache.as_ref().unwrap() // safe to unwrap because we checked is_none()
}
})
}

fn segwit_cache(&mut self) -> &SegwitCache {
Expand Down

0 comments on commit 497dbfb

Please sign in to comment.