Skip to content

Conversation

@morcos
Copy link
Contributor

@morcos morcos commented Jan 16, 2018

In #6931 we introduced a possible consensus breaking change by misunderstanding how completely BIP 34 obviated the need for BIP 30. Unfixed, this could break consensus after block height about 1.9M. Explained in code comment.

h/t @sdaftuar

Copy link
Member

@instagibbs instagibbs Jan 16, 2018

Choose a reason for hiding this comment

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

Maybe put "block" in front of blocks being named by number. (and everywhere else)

I was reading it as the the height in coinbase aka the number 176,684 in the block's coinbase at height 490,897.

Copy link
Contributor

@ryanofsky ryanofsky Jan 16, 2018

Choose a reason for hiding this comment

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

Is the significance of 1,938,702 just that it is the third lowest height found encoded in the old coinbases? The sentence doesn't say where 1,938,702 comes from, and this is written like it should be obvious what the number means.

If it is just the third lowest height found in the search, I think it would be clearer to say something like "An exhaustive search of all blocks before the BIP34 height found that the lowest height values indicated in coinbase scriptSigs were: 209,921, 490,897, and 1,983,702."

Copy link
Contributor

@jnewbery jnewbery 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 9ab7fe0b3f50b2cc3514975b26eb7c63134bdd40.

I'm currently running my own analysis of pre-BIP34 blocks to make sure that it agrees with what you found. It would be good to have a gist showing those results with code so other people can easily validate for themselves.

In general, I'm not sure whether code comments are appropriate for such a long and nuanced description. It certainly breaks up the flow of the ConnectBlock(). However, more verbose is generally better than less, and I don't have a better suggestion of where to put this level of comment that would stay maintained with the code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than start your new comment explaining where the previous comment is incorrect, I think it makes sense to remove/reword the paragraph above.

I also think it would make the whole comment clearer if you explicitly introduced terminology at the top of the comment. Something like:

- block height: the height of the block in the blockchain
- coinbase height: the height indicated in the coinbase transaction's scriptSig under BIP34 rules.

All blocks with block height >= 227,931 must have coinbase height equal to block height. This is a consensus rule.

rather than sprinkling the rest of the comment with multiple terms for the same concept: a scriptSig with a valid-looking BIP34 height..., scriptSig indicating..., indicated block height, coinbase with indicated height.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it is useful to understand the basic logic that BIP 34 implies BIP 30 is met and doesn't need to be checked. But then understand why it's not quite that simple. It also matches the historical evolution of the code. So I left this comment as correction to the previous one.

Copy link
Contributor

Choose a reason for hiding this comment

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

typo: optimization

@gmaxwell
Copy link
Contributor

Concept ACK.

Copy link
Contributor

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

code-level utACK, modulo comment comments.

@maflcko
Copy link
Member

maflcko commented Jan 18, 2018

Concept ACK. Though, I have never checked if any of the heights or hashes make sense. Wouldn't it help review if #6931 or this pull actually included the code that was used to determine those magic numbers?

@jnewbery
Copy link
Contributor

My analysis matches yours exactly. The pre-BIP34 blocks with coinbase height > block height are (in ascending order):

block_height | coinbase_height
209920 | 209921
176684 | 490897
164384 | 1983702
169895 | 3708179 <---- I expect to be dead before this height
....

so you're right that the only heights that we should care about are 209921, 490897 and 1983702.

@jnewbery
Copy link
Contributor

If anyone wants to re-run the analysis, the gist with my code is here: https://gist.github.com/jnewbery/df0a98f3d2fea52e487001bf2b9ef1fd

(this is quite slow since it's hitting the RPC interface 3 times for each block. It'd be faster to deserialize block files directly, patch bitcoind to print this data itself, or use BlockSci or a similar block analysis tool)

@achow101
Copy link
Member

code utACK, haven't actually read through the whole comment.

I agree with the above analysis that block 1983702 is the lowest block height that we need to worry about. We could soft fork in something prior to that block to guarantee that the txids will be different, e.g. block height in the nLockTime field.

@morcos
Copy link
Contributor Author

morcos commented Jan 25, 2018

Comment updated to hopefully be clearer. Code unchanged.

For reference here is how I double checked the possible violations. I patched bitcoind with this snippet and then ran with -reindex-chainstate.

@@ -1724,6 +1724,16 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
                 }
             }
         }
+        if (block.vtx[0]->vin[0].scriptSig.size() >= 4 && block.vtx[0]->vin[0].scriptSig[0] == 3) {
+            std::vector<unsigned char> vch;
+            for (int i=1;i<4;i++)
+                vch.push_back( block.vtx[0]->vin[0].scriptSig[i]);
+            CScriptNum height(vch,false);
+            int height_indicated = height.getint();
+            if (height_indicated > pindex->nHeight) {
+                fprintf(stdout,"Potential future duplicate: block %d has indicated height %d\n",pindex->nHeight,height_indicated);
+            }
+        }
     }
 
     // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.

@jnewbery
Copy link
Contributor

Tested ACK 3f3b991

@laanwj
Copy link
Member

laanwj commented Feb 8, 2018

Looks sensible to me. Although I think we should definitely make this a chain parameter, or at least define a constant, instead of hardcoding this magic number:

Optional TODO: Have BIP30 checking activate at a per chain block height.

I don't think we're in enough of a hurry here to skip that.

@morcos
Copy link
Contributor Author

morcos commented Feb 15, 2018

@laanwj I'm happy to define it as a constant locally, but it seems like adding it as a chain parameter just adds unnecessary cruft to the code. This is such an obscure (and irrelevant for decades) element of the consensus that it seems better to keep it entirely contained to one spot in the code base, so it doesn't occupy mental energy in other places. That said, will defer to your judgement...

EDIT: Or if we think testnet3 will get longer than 1.9 million blocks, then I suppose that's an argument for per chain so we don't do unnecessary calculations on testnet3.

@laanwj
Copy link
Member

laanwj commented Feb 15, 2018

Nono I'm OK with that, but if we actively argue against making it a chain parameter we should remove the TODO as well, otherwise it's inviting someone else to make that change. My only point is that there is no hurry to merge this, so no reason to leave unfinished TODOs in the code.

@morcos
Copy link
Contributor Author

morcos commented Feb 15, 2018

updated to a constant and removed optional TODO, I believe its better to keep this mess contained to one section of the code

@laanwj
Copy link
Member

laanwj commented Feb 15, 2018

utACK 5b8b387

@jnewbery
Copy link
Contributor

utACK 5b8b387

Difference is that there is now a constexpr int BIP34_IMPLIES_BIP30_LIMIT and the comment has been updated.

Travis failed because of a timeout. I'll kick it.

@sdaftuar
Copy link
Member

sdaftuar commented Mar 7, 2018

ACK

@laanwj laanwj merged commit 5b8b387 into bitcoin:master Mar 7, 2018
laanwj added a commit that referenced this pull request Mar 7, 2018
5b8b387 Fix overly eager BIP30 bypass (Alex Morcos)

Pull request description:

  In #6931 we introduced a possible consensus breaking change by misunderstanding how completely BIP 34 obviated the need for BIP 30.  Unfixed, this could break consensus after block height about 1.9M.  Explained in code comment.

  h/t @sdaftuar

Tree-SHA512: 8f798c3f203432fd4ae1c1c08bd6967b4a5ec2064ed5f6a7dcf3bff34ea830952838dd4ff70d70b5080cf4644f601e5526b60456c08f43789e4aae05621d9d6b
furszy added a commit to PIVX-Project/PIVX that referenced this pull request Aug 2, 2020
c894e8f [Core] Remove BIP30 check (random-zebra)

Pull request description:

  A bit of history
  ----

  Two transactions can have the same txid if their parents are identical, since the txids of the parents are included in a transaction.
  Coinbases have no parents, so it used to be possible for two of them to be identical.
  Further,  by building on duplicate coinbases, duplicate normal transactions were possible as well (http://r6.ca/blog/20120206T005236Z.html).

  In order to remove the possibility of having duplicate transaction ids, Bitcoin introduced, with BIP30, the following consensus rule:
  - Blocks are not allowed to contain a transaction whose identifier matches that of an earlier, not-fully-spent transaction in the same chain. [[1](https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki)]

  This rule was enforced by verifying (in `ConnectBlock`) that none of the transactions in the block was overwriting an already existent non-pruned CCoins entry.

  BIP34 was later added in Bitcoin to enforce better transaction uniqueness, with the update of block version to 2, which introduced the following consensus rule:
  - the first serialized element in the scriptSig of coinbase transactions must be the height of the chain. [[2](https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki)]

  After the complete activation of BIP34, there seemed to be no longer need for the check in `ConnectBlock`, added for BIP30, as duplicated coinbases were rendered impossible with BIP34 (bitcoin#6931).

  This assumption was later revisited, when several blocks were found on Bitcoin's main chain (before BIP34 activation), having coinbase scripts with an height higher than the current chain height (and higher than the BIP34 activation height).
  Thus, coinbases for blocks at these "future" heights would have given the opportunity for BIP30 to be violated even with BIP34 enforced (bitcoin#12204).

  Motivation for this PR
  ----

  PIVX has BIP30 and BIP34 consensus rules already implemented since the chain start.
  The first block after the genesis (height=1) has version 3.
  The "block.nVersion=2 rule" is enforced in `ContextualCheckBlock`
  https://github.com/PIVX-Project/PIVX/blob/af3dd41f86684a5e4a18cfb85d471a199cc980da/src/main.cpp#L3605-L3612

  However the code still has the (somewhat expensive) BIP30 check in `ConnectBlock`, which wasn't needed at all, given the full enforcement of BIP34 since the start of the chain.

  This PR removes it.

  *Side Note*: Even without BIP34, with Proof-of-Stake, coinbase transactions have empty scriptPubKey (thus unspendable outputs), therefore there would have been no need for BIP30 checks in any case (at least after PoS activation height).

ACKs for top commit:
  furszy:
    Great find! ACK c894e8f.
  Fuzzbawls:
    ACK c894e8f

Tree-SHA512: bc0dec1ef68c05db35ee0a132d0817c851667ce47ba5ec7eae31d29f1a44266f987db4462dc16d2320684bf76a6088c3fdbe77e08a9312ab6a1b7a58b6632661
Stamek pushed a commit to Stamek/squorum that referenced this pull request Aug 22, 2020
  A bit of history
  ----

  Two transactions can have the same txid if their parents are identical, since the txids of the parents are included in a transaction.
  Coinbases have no parents, so it used to be possible for two of them to be identical.
  Further,  by building on duplicate coinbases, duplicate normal transactions were possible as well (http://r6.ca/blog/20120206T005236Z.html).

  In order to remove the possibility of having duplicate transaction ids, Bitcoin introduced, with BIP30, the following consensus rule:
  - Blocks are not allowed to contain a transaction whose identifier matches that of an earlier, not-fully-spent transaction in the same chain. [[1](https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki)]

  This rule was enforced by verifying (in `ConnectBlock`) that none of the transactions in the block was overwriting an already existent non-pruned CCoins entry.

  BIP34 was later added in Bitcoin to enforce better transaction uniqueness, with the update of block version to 2, which introduced the following consensus rule:
  - the first serialized element in the scriptSig of coinbase transactions must be the height of the chain. [[2](https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki)]

  After the complete activation of BIP34, there seemed to be no longer need for the check in `ConnectBlock`, added for BIP30, as duplicated coinbases were rendered impossible with BIP34 (bitcoin/bitcoin#6931).

  This assumption was later revisited, when several blocks were found on Bitcoin's main chain (before BIP34 activation), having coinbase scripts with an height higher than the current chain height (and higher than the BIP34 activation height).
  Thus, coinbases for blocks at these "future" heights would have given the opportunity for BIP30 to be violated even with BIP34 enforced (bitcoin/bitcoin#12204).

  Squorum has BIP30 and BIP34 consensus rules already implemented since the chain start.
  The first block after the genesis (height=1) has version 4.

  However the code still has the (somewhat expensive) BIP30 check in `ConnectBlock`, which wasn't needed at all, given the full enforcement of BIP34 since the start of the chain.

  This commit removes it.

  *Side Note*: Even without BIP34, with Proof-of-Stake, coinbase transactions have empty scriptPubKey (thus unspendable outputs), therefore there would have been no need for BIP30 checks in any case (at least after PoS activation height).
jasonbcox pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Oct 31, 2020
Summary:
5b8b387 Fix overly eager BIP30 bypass (Alex Morcos)

Pull request description:

  In #6931 we introduced a possible consensus breaking change by misunderstanding how completely BIP 34 obviated the need for BIP 30.  Unfixed, this could break consensus after block height about 1.9M.  Explained in code comment.

  h/t @sdaftuar

---

Backport of Core [[bitcoin/bitcoin#12204 | PR12204]]

Test Plan:
  ninja all check check-functional

Reviewers: #bitcoin_abc, PiRK

Reviewed By: PiRK

Differential Revision: https://reviews.bitcoinabc.org/D8209
@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.