Skip to content

Conversation

jnewbery
Copy link
Contributor

@jnewbery jnewbery commented Feb 11, 2020

This change prevents coins from existing in a coins cache which are both FRESH and spent. FRESH coins should be removed from a cache when they are spent, and this PR also stops us from fetching spent coins from a parent cache and marking them FRESH.

@DrahtBot
Copy link
Contributor

DrahtBot commented Feb 11, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@jnewbery jnewbery force-pushed the 2020-01-prune-pruned branch from 5150e82 to 9288d74 Compare February 11, 2020 16:32
@jnewbery
Copy link
Contributor Author

Fixed a whitespace oops that our linters didn't like.

@fanquake fanquake changed the title [coins] Don't allow a coin to spent and FRESH. Improve commenting. coins: Don't allow a coin to be spent and FRESH. Improve commenting. Feb 12, 2020
@jonatack
Copy link
Member

Concept ACK, will review (this was discussed in part in the meeting log of https://bitcoincore.reviews/17487.html)

src/coins.h Outdated
//! If a FRESH coin is spent in this cache, then it can be deleted entirely
//! and doesn't ever need to be flushed to the parent. This is a performance
//! optimization. Note that a coin cannot be both FRESH and empty.
//! Marking a coin FRESH which is does exist in the parent view will
Copy link
Contributor

@amitiuttarwar amitiuttarwar Mar 18, 2020

Choose a reason for hiding this comment

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

grammar issue- "which is does exist"
maybe- "which actually does exist"

also, I find this sentence a bit confusing, mostly because of the phrasing of "will" vs "might". If a coin exists in the parent view & gets incorrectly marked as FRESH, is there a way it could still be deleted from the parent when the cache is flushed?

Copy link
Contributor

Choose a reason for hiding this comment

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

grammar issue- "which is does exist"
maybe- "which actually does exist"

Or simply "exists"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

src/coins.cpp Outdated
// re-added if it also appears in the newly connected blocks). It can
// also happen in the case of duplicate txids. In practice, BIP30 and
// BIP34 ensure that the only duplicate transactions before block
// 1,983,702 are the two pairs of coinbase txs at heights 91812/91842
Copy link
Member

Choose a reason for hiding this comment

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

Block 1,983,702 -- about 26 years from now? Is that a timestamp rolling over or something?
I thought BIP34 (block height in coinbase) will prevent this from ever happening since it was enforced:

Block number 227,835 (timestamp 2013-03-24 15:49:13 GMT) was the last version 1 block.

Copy link
Contributor

Choose a reason for hiding this comment

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

Take a look at the comments here:

// Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting

Copy link
Member

Choose a reason for hiding this comment

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

Oh THAT large comment in connectBlock() thanks ;-)

src/coins.h Outdated
//! Failing to mark a coin as DIRTY when it is potentially different from the
//! parent view will cause a consensus failure, since the coin's state won't get
//! written to the parent when the cache is flushed.
//! Note that all empty coins in the cache MUST be DIRTY.
Copy link
Member

Choose a reason for hiding this comment

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

What is an "empty" coin?

Copy link
Contributor

@fjahr fjahr Mar 18, 2020

Choose a reason for hiding this comment

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

I think this references emptyCoin (coins.h:132) which calls an empty constructor of Coin (coins.h:53).

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this references emptyCoin (coins.h:132) which calls an empty contractor of Coin (coins.h:53).

I think this is suppose to say coinEmpty (coins.cpp:132).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right that this is unclear. Empty here means that the coin has been spent (see Coin.Clear() above which nulls out a coin when it is spent). I've changed this to "Note that a spent coin MUST be DIRTY", which I think is much clearer.

@ghost
Copy link

ghost commented Mar 18, 2020

Reading about it in details now. Not sure if I can suggest anything in next few hours because this looks more complex than I thought.

Will join the Bitcoin Core PR Review Club Meeting on IRC today to understand more and research later in the week : https://bitcoincore.reviews/18113.html

Copy link
Contributor

@fjahr fjahr 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

Code looks good but I still need to think about reorgs a little more.

src/coins.cpp Outdated
@@ -75,8 +75,26 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
}
if (!possible_overwrite) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you could clean up and clarify this parameter here as well. First of all, it is sometimes called possible_overwrite and sometimes potential_overwrite in the code base, making it harder to grep etc. And I think part of the comment below could be moved here or there could be an additional comment here to explain what this does. I still found it confusing at first after reading comments in coins.h and validation.cpp.

Copy link
Contributor

@fjahr fjahr Mar 18, 2020

Choose a reason for hiding this comment

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

Or, I should rather say, the combination of the comments confused me more. From validation.cpp where AddCoin is called: "The potential_overwrite parameter to AddCoin is only allowed to be false if we know for sure that the coin did not already exist in the cache." When it is false we end up in this code branch and your comment starts with "If the coin exists in this cache..."

src/coins.h Outdated
//! Failing to mark a coin as DIRTY when it is potentially different from the
//! parent view will cause a consensus failure, since the coin's state won't get
//! written to the parent when the cache is flushed.
//! Note that all empty coins in the cache MUST be DIRTY.
Copy link
Contributor

@fjahr fjahr Mar 18, 2020

Choose a reason for hiding this comment

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

I think this references emptyCoin (coins.h:132) which calls an empty constructor of Coin (coins.h:53).

src/coins.cpp Outdated
entry.flags |= CCoinsCacheEntry::FRESH;
}
// The parent cache does not have an entry, while the child does.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: empty line could be removed

@meshcollider
Copy link
Contributor

Code review ACK 9288d74

Agree the terminology between FRESH and DIRTY is a bit confusing as people brought up in the PR review meeting this morning.

@fjahr
Copy link
Contributor

fjahr commented Mar 18, 2020

Code review ACK 9288d74

Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

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

ACK 9288d74 modulo terminology and timing

  • I think "FRESH" and "DIRTY" generally imply mutually exclusive states to people, and non-intuitive meanings/behavior could cause issues in the future. Happy to re-review/re-ACK any proposed further improvements.

  • As this touches consensus, perhaps best to merge after the impending 0.20 branch-off to give the changes some time.

@jkczyz
Copy link
Contributor

jkczyz commented Mar 18, 2020

Agree the terminology between FRESH and DIRTY is a bit confusing as people brought up in the PR review meeting this morning.

Given that there are four valid states but eight possible combinations (see @amitiuttarwar's summarization), one option is to refactor the code to use an enum with four variants named appropriately. This removes the possibility of getting into an invalid states. However, I'm not sure how practical this refactor would be or how difficult it would be to come up with meaningful names.

@fjahr
Copy link
Contributor

fjahr commented Mar 19, 2020

Given that there are four valid states but eight possible combinations (see @amitiuttarwar's summarization), one option is to refactor the code to use an enum with four variants named appropriately. This removes the possibility of getting into an invalid states. However, I'm not sure how practical this refactor would be or how difficult it would be to come up with meaningful names.

interesting idea but then I think renaming the flags to NEWCOIN and MUSTFLUSH as suggest by @jnewbery is a more practical change.

@andrewtoth
Copy link
Contributor

Concept ACK

Reiterating my comments from the PR review club, I think this PR might benefit from being split up. It's attempting two separate things, one of which is a consensus change. I think review on that important change might be more focused if this was split into a name and comment update, and then just the logic change.

@jnewbery jnewbery force-pushed the 2020-01-prune-pruned branch from 9288d74 to 2ba4885 Compare March 23, 2020 15:35
@jnewbery jnewbery changed the title coins: Don't allow a coin to be spent and FRESH. Improve commenting. [WIP] Don't allow a coin to be spent and FRESH. Mar 23, 2020
@jnewbery
Copy link
Contributor Author

jnewbery commented Mar 23, 2020

I've moved all the comment changes to #18113 #18410, which this PR now builds off. Please review #18113 first.

@jnewbery jnewbery changed the title [WIP] Don't allow a coin to be spent and FRESH. [WIP] Consensus: Don't allow a coin to be spent and FRESH. Mar 23, 2020
@jnewbery jnewbery force-pushed the 2020-01-prune-pruned branch from 2ba4885 to 0786c60 Compare March 24, 2020 15:04
@DrahtBot DrahtBot mentioned this pull request Apr 14, 2020
18 tasks
@DrahtBot
Copy link
Contributor

🐙 This pull request conflicts with the target branch and needs rebase.

When fetching a coin from a parent cache, don't add it to the child
cache if it's already spent, since there's no benefit to adding it.

This adds some invariant properties to the coins cache:
- a spent coin cannot be FRESH
- a spent coin must be DIRTY
@jnewbery jnewbery force-pushed the 2020-01-prune-pruned branch from 0786c60 to c9849da Compare April 22, 2020 22:07
@jnewbery
Copy link
Contributor Author

jnewbery commented Apr 22, 2020

This PR originally included changes to comments and the change to not fetch spend coins from the cache. The comments changes have been merged in #18113 #18410. Most of the review comments here are about those comments changes, so I'm closing this and using #18746 to PR the code changes.

@jnewbery jnewbery closed this Apr 22, 2020
@jnewbery jnewbery deleted the 2020-01-prune-pruned branch April 22, 2020 22:30
@maflcko
Copy link
Member

maflcko commented May 24, 2020

I think there is a typo in the last two comments 18113 should be 18410. #18410

@jnewbery
Copy link
Contributor Author

Thanks Marco. I fixed those comments.

@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
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.