Skip to content

Conversation

maflcko
Copy link
Member

@maflcko maflcko commented Apr 17, 2018

This speeds up:

  • compactblocks (v2)
  • ATMP
  • validation and miner (via BlockWitnessMerkleRoot)
  • sigcache (see also unrelated Faster sigcache nonce #13204)
  • rpc and rest (nice, but irrelevant)

This presumably slows down rescan, which uses a CTransaction and its GetHash, but never uses the GetWitnessHash. The slow down is proportional to the number of witness transactions in the rescan window. I.e. early in the chain there should be no measurable slow down. Later in the chain, there should be a slow down, but acceptable given the speedups in the modules mentioned above.

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK fae63d51ab252579adbaceb6aaba935bae75de88. Code looks ok, but what's the motivation for this change? I imagine there are a lot of performance implications.

Also, why is unique_ptr<uint256> used for the witness hash when the plain hash is just uint256?

}
return SerializeHash(*this, SER_GETHASH, 0);
return std::unique_ptr<const uint256>{new uint256{SerializeHash(*this, SER_GETHASH, 0)}};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use MakeUnique<const uint256>(SerializeHash(*this, SER_GETHASH, 0)); here

CTransaction::CTransaction(CMutableTransaction &&tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash{}, m_witness_hash{nullptr} {}
CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you could remove some of the boilerplate and repetition here using member initialization in the header:

const std::unique_ptr<const uint256> m_witness_hash = ComputeWitnessHash();

It would be nice to do this for the other members, too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what would be the execution order in this case? ComputeWitnessHash calls SerializeHash(*this, ...) so other members must be initialized before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what would be the execution order in this case? ComputeWitnessHash calls SerializeHash(*this, ...) so other members must be initialized before.

Execution order always the matches order members are declared in the class, not the order initializations are written in the constructor (compilers will warn if the orders differ), so this wouldn't change behavior. You can see https://isocpp.org/wiki/faq/ctors#ctor-initializer-order for discussion about this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We couldn't do the same for the hash member, I guess, so will leave this as is for now.

Copy link
Contributor

@promag promag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK.

I guess the extra memory usage is neglectable.

// Compute a hash that includes both transaction and witness data
uint256 GetWitnessHash() const;
const uint256& GetHash() const { return hash; }
const uint256& GetWitnessHash() const { return m_witness_hash ? *m_witness_hash : hash; };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this expression be in ComputeWitnessHash?

@practicalswift
Copy link
Contributor

Concept ACK

@sdaftuar
Copy link
Member

@sipa raised design concerns with caching data like this in CTransaction previously (see #9700)

@TheBlueMatt
Copy link
Contributor

Honestly I think we need to revive #9700. Now that SegWit has some use, giving up on the huge performance gains of that (and this) for (IMO) minor design concerns is an absurd tradeoff.

@sipa
Copy link
Member

sipa commented Apr 20, 2018

Then at the very least introduce alternate versions of CTransaction/CBlock that don't precompute anything, for use in reindexing and rescanning and serving blocks from disk. Otherwise you'll waste your time computing wtxids/sighashes in those cases, where they're never used.

@TheBlueMatt
Copy link
Contributor

Indeed, though we may want to look into something wholesale smarter for rescan, its already impossibly slow even when considering the amount of I/O required.

@maflcko maflcko force-pushed the Mf1804-cacheWitnessHash branch from fae63d5 to fa77996 Compare April 21, 2018 13:37
TheBlueMatt added a commit to bitcoinfibre/bitcoinfibre that referenced this pull request May 4, 2018
MarcoFalke added 2 commits May 4, 2018 17:40
Silently converting to a CMutableTransaction will drop all caches
and should thus be done explicitly
@maflcko maflcko force-pushed the Mf1804-cacheWitnessHash branch from fa77996 to fac1223 Compare May 4, 2018 21:55
@maflcko
Copy link
Member Author

maflcko commented May 4, 2018

Split into two commits for easier review

@TheBlueMatt
Copy link
Contributor

utACK fac1223. We should probably take this as-is IMO and then we can clean things up when we look at fully splitting out hashes in #13098.

@jamesob
Copy link
Contributor

jamesob commented May 10, 2018

utACK fac1223

Numbers would be nice, but the code looks good.

@ryanofsky
Copy link
Contributor

Was a discussion about this in IRC meeting yesterday: https://botbot.me/freenode/bitcoin-core-dev/msg/99929243/

Beginning of discussion before it goes on to talk about related PRs like #13098

[19:10:54] <MarcoFalke> Background: The witness hash is used for all loose transactions, so caching it would speed up validation (e.g. ATMP and compact block relay). Also, the witness hash is equal to the "normal hash" for transactions without a witness, so there is overhead for rescan/reindex is currently minimal (since there are not many transactions with witness). The gains of caching the witness hash dwarf any overhead during rescan/reindex, imo. And of course, we
[19:10:55] <MarcoFalke> can just rework rescan in a future pr.
[19:11:32] <MarcoFalke> The code changes are trivial, so at least that shouldn't be an issue
[19:12:03] <jamesob> would be nice if that paragraph was in the PR description
[19:12:23] <sipa> Downside is that it makes the transactions larger, and hardcodes some validation sprcific logic into the transaction data structure (which for example also affects serving blocks from disks etc)
[19:12:46] <BlueMatt> upside is we rectify a significant performance regression
[19:12:48] <sipa> So my view is that we should separate the transactions-for-validation tyoe and simple mutable transactions
[19:13:01] <BlueMatt> and obviously all pre-segwit-activation blocks will not be served any slower
[19:13:03] <MarcoFalke> sipa: I think those can easily be fixed in future prs (I have one open for the
blocks serving from disks, and wumpus as well)
[19:13:19] <sipa> MarcoFalke: i'm aware, not objecting to amything
[19:13:21] <BlueMatt> personally, I find it really unacceptable that we have this huge performance regression and arent taking it as something to be fixed asap
[19:13:33] <MarcoFalke> sipa: I know, just posting for reference
[19:13:34] <sipa> just pointing out that we don't want to do this work everywhere
[19:13:48] <sipa> so concept ack, if we commit to separating those types
[19:14:01] <wumpus> agree with sipa
[19:14:05] <BlueMatt> yes, imo we should merge the per as-is now, and then when we look towards MarcoFalke's next pr splitting out the types (which is gonna be a lot more work) we will probably pull out both hashes then anyway
[19:14:16] <sipa> there are other reasons for separating those types as well, btw
[19:14:22] * BlueMatt would kinda recommending backporting the pr as-is, though

Continues https://botbot.me/freenode/bitcoin-core-dev/msg/99929408/

@maflcko
Copy link
Member Author

maflcko commented May 11, 2018

This speeds up:

  • compactblocks (v2)
  • ATMP
  • validation and miner (via BlockWitnessMerkleRoot)
  • sigcache (see also unrelated Faster sigcache nonce #13204)
  • rpc and rest (nice, but irrelevant)

This presumably slows down rescan, which uses a CTransaction and its GetHash, but never uses the GetWitnessHash. The slow down is proportional to the number of witness transactions in the rescan window. I.e. early in the chain there should be no measurable slow down. Later in the chain, there should be a slow down, but acceptable given the speedups in the modules mentioned above.

@maflcko
Copy link
Member Author

maflcko commented May 11, 2018

Note: You can run benchmarks such as:

./src/bench/bench_bitcoin --filter=MempoolEviction  # ATMP (unchecked) with 100% segwit transactions
./src/bench/bench_bitcoin --filter=DeserializeBlockTest  # Used by rescan, so this should be slower, but none of the txs have witness, so there is no difference in runtime

@jimpo
Copy link
Contributor

jimpo commented May 13, 2018

If performance is a concern in contexts where the precomputed value isn't needed, couldn't this just lazily compute and cache the witness hash? There'd probably have to be some concurrency handling, I suppose.

@sipa
Copy link
Member

sipa commented May 13, 2018

avoid "some concurrency handling" was the reason for making these fields const in the first place.

The alternative is either indirections (through atomic pointers) or mutexes all over the place.

The solution to not computing it in places where it isn't needed is not using a type that caches these values.

@promag
Copy link
Contributor

promag commented May 13, 2018

utACK fac1223.

@jimpo
Copy link
Contributor

jimpo commented May 17, 2018

utACK fac1223

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK fac1223. Only change since previous review is making m_witness_hash member const uint256 instead of std::unique_ptr<const uint256>, and adding the new cleanup commit: "Make CMutableTransaction constructor explicit …"

@sipa
Copy link
Member

sipa commented May 17, 2018

utACK fac1223

@danielsam
Copy link

utACK fac1223

@laanwj
Copy link
Member

laanwj commented May 23, 2018

utACK fac1223

@laanwj laanwj merged commit fac1223 into bitcoin:master May 23, 2018
laanwj added a commit that referenced this pull request May 23, 2018
fac1223 Cache witness hash in CTransaction (MarcoFalke)
faab55f Make CMutableTransaction constructor explicit (MarcoFalke)

Pull request description:

  This speeds up:
  * compactblocks (v2)
  * ATMP
  * validation and miner (via `BlockWitnessMerkleRoot`)
  * sigcache (see also unrelated #13204)
  * rpc and rest (nice, but irrelevant)

  This presumably slows down rescan, which uses a `CTransaction` and its `GetHash`, but never uses the `GetWitnessHash`. The slow down is proportional to the number of witness transactions in the rescan window. I.e. early in the chain there should be no measurable slow down. Later in the chain, there should be a slow down, but acceptable given the speedups in the modules mentioned above.

Tree-SHA512: 443e86acfcceb5af2163e68840c581d44159af3fd1fce266cab3504b29fcd74c50812b69a00d41582e7e1c5ea292f420ce5e892cdfab691da9c24ed1c44536c7
@maflcko maflcko deleted the Mf1804-cacheWitnessHash branch May 23, 2018 17:50
TheBlueMatt added a commit to bitcoinfibre/bitcoinfibre that referenced this pull request Jul 17, 2018
TheBlueMatt added a commit to bitcoinfibre/bitcoinfibre that referenced this pull request Sep 27, 2018
TheBlueMatt added a commit to bitcoinfibre/bitcoinfibre that referenced this pull request Dec 28, 2018
UdjinM6 pushed a commit to UdjinM6/dash that referenced this pull request Jun 18, 2021
fac1223 Cache witness hash in CTransaction (MarcoFalke)
faab55f Make CMutableTransaction constructor explicit (MarcoFalke)

Pull request description:

  This speeds up:
  * compactblocks (v2)
  * ATMP
  * validation and miner (via `BlockWitnessMerkleRoot`)
  * sigcache (see also unrelated bitcoin#13204)
  * rpc and rest (nice, but irrelevant)

  This presumably slows down rescan, which uses a `CTransaction` and its `GetHash`, but never uses the `GetWitnessHash`. The slow down is proportional to the number of witness transactions in the rescan window. I.e. early in the chain there should be no measurable slow down. Later in the chain, there should be a slow down, but acceptable given the speedups in the modules mentioned above.

Tree-SHA512: 443e86acfcceb5af2163e68840c581d44159af3fd1fce266cab3504b29fcd74c50812b69a00d41582e7e1c5ea292f420ce5e892cdfab691da9c24ed1c44536c7
UdjinM6 pushed a commit to UdjinM6/dash that referenced this pull request Jun 24, 2021
fac1223 Cache witness hash in CTransaction (MarcoFalke)
faab55f Make CMutableTransaction constructor explicit (MarcoFalke)

Pull request description:

  This speeds up:
  * compactblocks (v2)
  * ATMP
  * validation and miner (via `BlockWitnessMerkleRoot`)
  * sigcache (see also unrelated bitcoin#13204)
  * rpc and rest (nice, but irrelevant)

  This presumably slows down rescan, which uses a `CTransaction` and its `GetHash`, but never uses the `GetWitnessHash`. The slow down is proportional to the number of witness transactions in the rescan window. I.e. early in the chain there should be no measurable slow down. Later in the chain, there should be a slow down, but acceptable given the speedups in the modules mentioned above.

Tree-SHA512: 443e86acfcceb5af2163e68840c581d44159af3fd1fce266cab3504b29fcd74c50812b69a00d41582e7e1c5ea292f420ce5e892cdfab691da9c24ed1c44536c7
UdjinM6 pushed a commit to UdjinM6/dash that referenced this pull request Jun 26, 2021
fac1223 Cache witness hash in CTransaction (MarcoFalke)
faab55f Make CMutableTransaction constructor explicit (MarcoFalke)

Pull request description:

  This speeds up:
  * compactblocks (v2)
  * ATMP
  * validation and miner (via `BlockWitnessMerkleRoot`)
  * sigcache (see also unrelated bitcoin#13204)
  * rpc and rest (nice, but irrelevant)

  This presumably slows down rescan, which uses a `CTransaction` and its `GetHash`, but never uses the `GetWitnessHash`. The slow down is proportional to the number of witness transactions in the rescan window. I.e. early in the chain there should be no measurable slow down. Later in the chain, there should be a slow down, but acceptable given the speedups in the modules mentioned above.

Tree-SHA512: 443e86acfcceb5af2163e68840c581d44159af3fd1fce266cab3504b29fcd74c50812b69a00d41582e7e1c5ea292f420ce5e892cdfab691da9c24ed1c44536c7
UdjinM6 pushed a commit to UdjinM6/dash that referenced this pull request Jun 26, 2021
fac1223 Cache witness hash in CTransaction (MarcoFalke)
faab55f Make CMutableTransaction constructor explicit (MarcoFalke)

Pull request description:

  This speeds up:
  * compactblocks (v2)
  * ATMP
  * validation and miner (via `BlockWitnessMerkleRoot`)
  * sigcache (see also unrelated bitcoin#13204)
  * rpc and rest (nice, but irrelevant)

  This presumably slows down rescan, which uses a `CTransaction` and its `GetHash`, but never uses the `GetWitnessHash`. The slow down is proportional to the number of witness transactions in the rescan window. I.e. early in the chain there should be no measurable slow down. Later in the chain, there should be a slow down, but acceptable given the speedups in the modules mentioned above.

Tree-SHA512: 443e86acfcceb5af2163e68840c581d44159af3fd1fce266cab3504b29fcd74c50812b69a00d41582e7e1c5ea292f420ce5e892cdfab691da9c24ed1c44536c7
UdjinM6 pushed a commit to UdjinM6/dash that referenced this pull request Jun 28, 2021
fac1223 Cache witness hash in CTransaction (MarcoFalke)
faab55f Make CMutableTransaction constructor explicit (MarcoFalke)

Pull request description:

  This speeds up:
  * compactblocks (v2)
  * ATMP
  * validation and miner (via `BlockWitnessMerkleRoot`)
  * sigcache (see also unrelated bitcoin#13204)
  * rpc and rest (nice, but irrelevant)

  This presumably slows down rescan, which uses a `CTransaction` and its `GetHash`, but never uses the `GetWitnessHash`. The slow down is proportional to the number of witness transactions in the rescan window. I.e. early in the chain there should be no measurable slow down. Later in the chain, there should be a slow down, but acceptable given the speedups in the modules mentioned above.

Tree-SHA512: 443e86acfcceb5af2163e68840c581d44159af3fd1fce266cab3504b29fcd74c50812b69a00d41582e7e1c5ea292f420ce5e892cdfab691da9c24ed1c44536c7
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.