#15481 Restrict timestamp when mining a diff-adjustment block to prev-600 (mining)
- This PR was proposed in preparation for Matt Corallo’s Great Consensus Cleanup softfork proposal. (Mailing list post), (proposed BIP).
- The proposal was discussed at the recent Bitcoin Core devtech meetup.
- This PR is connected with the timewarp fix part of the BIP: By further restricting nTime fields on difficulty adjustment blocks, we propose fixing the long-standing “timewarp” inflation vulnerability in Bitcoin’s difficulty adjustment without risking existing mining hardware becoming unusable. This limits the worst-case difficulty adjustment target in case of attack from the current exponential growth, to once every roughly 600 seconds.
- The expected time period of 2016 blocks (one retargetting period) isn’t exactly two weeks. See this thread from Pieter Wuille on why exactly that is.
- The PR doesn’t enforce that consensus change. Rather, it changes the mining behaviour of a Bitcoin Core node to be compliant with the proposed changes.
- There are two changes:
- One to
getblocktemplate(the RPC that a miner calls in order to get a template block to work on). This PR changes the returned
mintimefield returned by
getblocktemplate, such that if the next block is a difficulty adjustment block, it is constrained by the prev-600 rule.
- One to
UpdateTime(), which is called when creating a new block (either for mining on the node for regtest, or for
- One to
- At the time of writing, this PR is ‘Chasing Concept ACK’. That means that we want contributors to review the concept before reviewing the implementation.
- What could a miner do by abusing the timestamp field in a difficulty adjustment block prior to the Great Consensus Cleanup change?
- After the Great Consensus Cleanup change, what can a miner do by abusing the block timestamp?
- Why not just enforce that difficulty adjustment blocks to have a timestamp after the previous block, rather than after prev-600?
- Which function would need to be changed to enforce this timestamp restriction as a consensus rule?
curtimereturn value of
getblocktemplateis now constrained by the prev-600 rule. Why?
13:00 < jnewbery> hi 13:00 < kanzure> hi 13:00 < pinheadmz> hi 13:00 < sosthene> hi 13:00 < ccdle12> hi 13:00 < jonatack> hi ! 13:00 < rockstardev> hi... @jnewbery I'll follow up with details after PR review 13:01 < amiti> hi 13:01 < ariard> hi 13:01 < jnewbery> Before we start, can you raise your hand o/ if you managed to clone/build the PR and read the notes/questions? 13:02 < nehan> hi 13:02 < pinheadmz> read everything, did not test locally 13:02 < ccdle12> same as above 13:03 < jnewbery> ok, let's give everyone a couple of minutes to catch up. Notes are at https://bitcoin-core-review-club.github.io/15481.html 13:03 < ariard> read notes/BIP and skim over commits 13:03 < jnewbery> I'd encourage everyone to spend at least a few minutes preparing before the meeting by reading the notes. It'll really increase the benefit you get from the meeting if you come with questions prepared. 13:03 < ariard> https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-August/016316.html 13:03 < ariard> Getting around to fixing the timewarp attack 13:04 < jonatack> * yup built, tested, read 13:04 < PaulTroon> I looked over Jon's shoulder :-) 13:04 < jnewbery> ok, so let's hit some of those questions 13:05 < jnewbery> pinheadmz: What could a miner do by abusing the timestamp field in a difficulty adjustment block prior to the Great Consensus Cleanup change? 13:05 < pinheadmz> force a downward difficultly adjustment 13:06 < ariard> and so increase the block production rate? 13:06 < jnewbery> exactly right 13:06 < pinheadmz> making mining easier 13:06 < jnewbery> either push difficulty down or keep it low 13:06 < jnewbery> the idea is that the retarget algorithm only looks at 2015 out of 2016 blocks, so the retargeting periods don't overlap 13:07 < jnewbery> the timewarp exploits this by pushing the difficulty adjustment block way into the future, and then the next block back into the present 13:07 < jnewbery> that makes it appear to the retarget algorithm that it took a long time for the prior retarget period, so difficulty stays low or is adjusted down 13:08 < sosthene> Is it the same vulnerability that was exploited against Verge was attacked last year? 13:08 < pinheadmz> can we clarify which blocks by # ? Like, block 2015 (the ACTUAL last block for retarget algo) is the one thats post-dated 2 hours into the future? 13:09 < jnewbery> sosthene: I think similar. As far as I'm aware verge had some system that used multiple POW algorithms 13:09 < lightlike> jnewbery: "way in the future": is it possible, i read somewhere that you cannot go more than 2 hours into the future with the current rules? 13:09 < pinheadmz> lightlike: correct, 2 hours 13:09 < jnewbery> lightlike: correct, so you couldn't use this attack at the tip, but you could redo a blockchain from genesis that does this because you have 10 years to play with 13:09 < rockstardev> @lightlike: https://bitcoin.stackexchange.com/a/20490/13744 13:10 < jnewbery> (in fact there are stome checkpoints, so you could only do it from block 295,000 if you wanted your blockchain to be accepted by Bitcoin Core) 13:10 < pinheadmz> and that 2 hours is measured against netwoek-adjusted wall-clock time? not MTP 13:10 < nehan> jnewbery: in matt's bip, it's called "timewarp inflation vulnerability". How does inflation come into it? 13:10 < jnewbery> pinheadmz: yes, your local time 13:10 < ariard> you could redo a blockchain but with less work, so you can't override current chain right? 13:11 < kanzure> inflation because subsidy goes out quicker than scheduled 13:11 < jnewbery> nehan: because if you can increase the rate of block production, you can increase the rate of new coin emission 13:11 < nehan> ok, so it refers to schedule and not # of coins 13:11 < jnewbery> nehan: exactly 13:11 < jnewbery> it doesn't affect the 21m cap 13:12 < pinheadmz> since retarget algo is based on median, how much effect can post-dating block #2015 by 2 hours really have? 13:12 < jnewbery> ariard: yes, you'd still need to do more work than the current blockchain if you wanted others to reorg to your chain 13:12 < nehan> i'd appreciate more explanation about the bug, like what pinheadmz asked for (which blocks) 13:12 < pinheadmz> or does the attack have to involve more than just the last block 13:13 < jnewbery> so if I wanted to create a blockchain with many blocks, I'd do the following: 13:13 < jnewbery> create block 1 with a timestamp 1 second after the genesis block 13:13 < jnewbery> create block 2 with timestamp one second after that 13:13 < jnewbery> ... 13:14 < jnewbery> create block 2015 with timestamp genesis+2015 13:14 < jnewbery> create block 2016 with timestamp 2 weeks in the future 13:14 < jnewbery> sorry, timestamp genesis+2 weeks 13:14 < jnewbery> create block 2017 with timestmp genesis+2017 13:14 < jnewbery> ... 13:15 < nehan> jnewbery: is that within the 2 hour time bound? 13:15 < jnewbery> nehan: correction, not 2 weeks in the future from clock time, 2 weeks in the future from genesis 13:15 < nehan> it seems like two weeks + genesis - 2016s + geneses > 2 hours 13:15 < jnewbery> so the retarget algorithm compares the timestamp of block 2016 with block 1 and thinks "hmmm, it took 2 weeks to mine these blocks, keep difficulty at 1" 13:16 < jnewbery> but because 2017 is back to genesis+2017 seconds, the time hasn't advanced two weeks 13:16 < ariard> the hard limit of 2 hours is based on which clock ? Median-Time-Past of X blocks ? 13:16 < jnewbery> nehan: the 2 hours check is against clock time on the node 13:16 < nehan> hasn't it for block 2016 though? why would nodes accept 2016's with such a far off timestamp? 13:16 < jnewbery> the two hour rule is really weird 13:16 < nehan> or is it averaged over blocks? 13:17 < jnewbery> it's the only 'consensus' rule that isn't based on blockchain data but on local data 13:17 < ariard> okay if you're a malicious miner just tune your clock time like you want? 13:17 < jnewbery> it's almost better to not think of it as a consensus rule 13:17 < jnewbery> ariard: sure, but other people wouldn't accept your block 13:18 < jnewbery> because they're all comparing to their (presumably correct) clocks 13:18 < ccdle12> so what is the significance of updating previous block nTime to -600 seconds? (why -600 as an arbitrary number) 13:19 < ariard> the 600 seconds is to avoid messing with miner software using timestamp field for pow 13:19 < jnewbery> so in summary: it allows someone to create arbitrarily long blockchains without the difficulty increasing. The Median Time Passed of the blockchain creeps forward slowly, but one block out of every 2016 is sent forward in time to artificially keep the difficulty down 13:19 < pinheadmz> jnewbery: in your example, why not just create blocks 1-2016 at ten minute intervals? the diff will still stay unchanged? 13:20 < fl> ariard: using the node's local clock, it increases the attack surface from inaccurate time attestations in blocks to requiring the persistent manipulation of timeserver/nodes' local time 13:20 < jnewbery> ariard: exactly right. Some miners apparently use the timestamp field as extra nonce and roll it forward up to 10 minutes 13:20 < rockstardev> that's a good one... interesting to learn that miners do that with timestamp 13:20 < jnewbery> pinheadmz: because at blocks every 10 minutes the timestamp will advance to current time after ~580000 blocks 13:20 < fl> there's a bit of a dearth of nonce space IIRC 13:21 < jnewbery> the attack is to make a longer blockchain, but without increasing the difficulty 13:21 * pinheadmz thumbs up 13:21 < jnewbery> so more coinbase subsidy is realeased 13:21 < lightlike> jnewbery: why would other nodes accept the longer blockchain? I thought the one with the most cumulated work is accepted, not with the largest block count. 13:22 < fl> jnewbery wouldn't a timewarped fork chain require an eclipse attack to prevent nodes from learning about a non attacking chain? or is the desire just to make controlled supply more metered? 13:22 < jnewbery> lightlike: correct, so the full attack would be: I control 51% of the mining power, so I can create a chain with more work than anyone else. I do that, but also use timeward to make that most-work chain really long 13:23 < pinheadmz> does this attack have to start from genesis? 13:23 < fl> pinheadmz no 13:23 < lightlike> jnewbery: ok, thanks, I think I got it now :-) 13:23 < jnewbery> it means that a 51% attack can now increase the rate at which new coins are minted 13:23 < fl> timewarping can start at any block 13:23 < jnewbery> fl: yes, exactly correct 13:24 < fl> jnewbery to which comment? 13:24 < jnewbery> fl: correct that a timewarp can start at any block 13:24 < fl> ty 13:24 < jnewbery> I used genesis as an example because I thought it might simplify the concept, but you could start anywhere 13:24 < hugohn> q: why is the 600sec limit in miner.cpp? don't miners run their own sw? 13:25 < jnewbery> obviously if you start a more recent block, it'll be more work 13:25 < jnewbery> I created a 500,000 long mainnet blockchain by starting at genesis with an S7 a few years ago. At the time I believe it was the longest mainnet Bitcoin blockchain (but not most work, obviously) 13:26 < pinheadmz> jnewbery: thats awesome! ha 13:26 < nehan> jnewbery: i still don't understand why, in your example, other nodes would accept block 2016 (its timestamp is far in the future) but i am happy to take it offline 13:26 < ariard> fl: yes on increasing the attack surface to require the persistent manipulation of timeserver but I wonder if eclipse attacks can destroy this assumption and instead relying on public data wouldn't be better... 13:27 < fl> What would be the effect of sending a timewarped-spoofed chain to a node, would chainstate get erased? 13:27 < jnewbery> block 2016 is in the future from the prior block, but it's in the past when your node is validating 13:27 < wallet42> jnewbery: awesome! wen polo? 13:27 < nehan> jnewbery: aha, because you're starting at genesis, which was a long time ago. got it, thanks! 13:27 < jnewbery> yes, my use of the word future was probably confusing 13:28 < jnewbery> hugohn: I believe most miners use the Bitcoin Core software to get block templates, which they then do work on 13:28 < jnewbery> the `getblocktemplate` RPC will give a block template with the timestamp filled in 13:29 < jnewbery> Here's the code: https://github.com/bitcoin/bitcoin/blob/0221420d1a0550cd849e0f3a5ada3738d5931bdd/src/rpc/mining.cpp#L292 13:29 < jnewbery> You can see that it also returns `curtime` and `mintime` 13:29 < jnewbery> this PR means the value returned for those fields may change. Why? 13:30 < ariard> fl: headers-sync first would happen first and your spoffed chain not queried as new chainstate ? 13:31 < jnewbery> ariard fl: assuming your peer is on the most work tip, and your spoofed chain is below block 295,000, it wouldn't accept the headers because of the checkpoint 13:31 < fl> ah yeah 13:32 < fl> forgot 13:32 < jnewbery> you could create a timewarped chain after block 295,000 but even back at that height, it's quite a lot of work 13:33 < ariard> jnewbery: yes and after 295,000 headers are the counter-measures against resource consumption to track spoofed-chain? 13:33 < jnewbery> anyone want to take a shot at why `curtime` and `mintime` might be changed? 13:33 < fl> i.e. unless timewarped chain had more chainwork after 295e3 nodes wouldn't switch tips, correct? 13:33 < jnewbery> fl: right, we wouldn't reorg unless the new chain contained more work 13:34 < jonatack> to cap the mintime at not less than nTime - 600 ? 13:34 < hugohn> so this is not a consensus change right? as the 600-limit is only in miner.cpp 13:34 < fl> jnewbery but a timewarp spoof chain target node would have some some resource consumption based on header-sync assesment I think 13:35 < jnewbery> ok, so mintime might change because of the code change here: https://github.com/bitcoin/bitcoin/pull/15481/files#diff-9651347c8e00bed3ddc7631de569406dR656 13:35 < pinheadmz> Is there any way timewarp can benefit one single attacker? Seems like it lowers difficulty for EVERYONE, doesn't give one party a specific advantage 13:35 < jnewbery> if the last block of the retarget period was more than 10 minute in the future, then `mintime` would be that timestamp-600 13:36 < fl> pinheadmz it would benefit miners with low block propogation latency 13:36 < jnewbery> hugohn: correct, not a consensus change. This is just miner behaviour change 13:36 < jnewbery> pinheadmz: potentially you could combine it with selfish mining if you're not sharing your chain 13:37 < jnewbery> but really, the dangerous attack is from a miner (or group of miners) that control 51% 13:37 < jnewbery> why might `curtime` change? 13:37 < ariard> fl: starting from checkpoints that's only 2,3 GB of headers with current height of 581487 13:38 < jonatack> to close the vuln without potentially breaking miner machines 13:38 < wallet42> 23 MB 13:38 < jnewbery> fl: I believe we won't download the full block if it's not the most work chain - just the header 13:38 < wallet42> (581487−295000)×80 13:38 < nehan> jnewbery: block->nTime is set on line 41 in UpdateTime(), and it might have been changed at line 37 13:39 < ariard> wallet42: oh sorry right 13:39 < jnewbery> so if you're trying to use this to DOS nodes, you need to do a ton of work just to waste 80 bytes 13:39 < fl> jnewbery I agree just header data would get computed on, thought I would mention that there is some marginal increase in resource consumption 13:39 < jnewbery> if you want to use timewarp to ratchet down the difficulty, you still need to get to the next difficulty retarget block after 295000, and then you can only lower it by 75% 13:40 < jnewbery> fl: yes, but it's asymetric. The attacker needs to do a *lot* of work for a minimal amount of bandwidth/CPU/memory wastage on the civtim 13:40 < jnewbery> *victim 13:40 < fl> issuance rate and preserving DMMS are the more important network properties anti-timewarping attack measures benefit 13:41 < fl> IMO 13:41 < wallet42> hm but once you lowered it enough, you can generate 80 bytes very easily no? 13:41 < jnewbery> nehan: yes exactly right. The update time change here: https://github.com/bitcoin/bitcoin/pull/15481/files#diff-4a59b408ad3778278c3aeffa7da33c3cR36 is used when constructing the block template 13:41 < jnewbery> and `curtime` is taken from that block: https://github.com/bitcoin/bitcoin/blob/0221420d1a0550cd849e0f3a5ada3738d5931bdd/src/rpc/mining.cpp#L667 13:42 < jnewbery> ok, last question: Which function would need to be changed to enforce this timestamp restriction as a consensus rule? 13:42 < fl> jnewbery the resource consumption on a spoof timewarp chain is negligible but in your case where 51% miner stretches out the chain, they could start stuffing more and more data into blocks increasing node operation costs more 13:42 < nehan> jnewbery: but *why* was that change made? 13:43 < jnewbery> nehan: because the aim of this PR is to make miners not mine a difficulty retarget block more than 600 seconds before the prior block. When the miner callers GBT we want the block template returned to them to have a timestamp that is constrained by that rule 13:43 < fl> well not more data into blocks but more data per time 13:44 < jnewbery> and `curtime` is just taken from the block 13:44 < jnewbery> the help text would be technically wrong after this PR: https://github.com/bitcoin/bitcoin/blob/0221420d1a0550cd849e0f3a5ada3738d5931bdd/src/rpc/mining.cpp#L361 13:45 < jnewbery> by the way, GBT is defined in a BIP here: https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki 13:45 < jnewbery> Anyone brave enough to try to answer "Which function would need to be changed to enforce this timestamp restriction as a consensus rule?" :) 13:46 < jnewbery> hint: it's a consensus rule, so it's probably in validation.cpp 13:46 < lightlike> jnewbery: Change CheckBlock() in validation to not accepts new block that break it? 13:47 < jnewbery> lightlike: almost! 13:47 < jnewbery> the change would actually be in ContextualCheckBlockHeader() 13:47 < jnewbery> Header, because this is a field in the block header 13:48 < jnewbery> Contextual, because it's a context-dependant check (ie it depends on where the block is in the blockchain) 13:48 < jnewbery> Matt has a reference implementation for the Consensus Cleanup softfork: https://github.com/bitcoin/bitcoin/pull/15482 13:49 < jnewbery> the relevant change is here: https://github.com/bitcoin/bitcoin/pull/15482/files#diff-24efdb00bfbe56b140fb006b562cc70bR3251 13:49 < hugohn> q: what happens if there is a large hashrate drop between the second-to-last block and the last block in a period (so the gap between those 2 blocks is truly more than 2 minutes)? Won't this change make it so that we won't account for this hash rate drop in retargeting? then that means the next period's difficulty will be a lot longer than it has to be? 13:49 < hugohn> *more than 10 minutes 13:49 < jnewbery> so the code changes this week were very minor, but I hope you agree that there's a lot of interesting discussion behind them 13:50 < hugohn> *harder than it has to be 13:50 < jnewbery> hugohn: the change imposes a new minimum on the block timestamp, not a new maximum 13:51 < jnewbery> if the hashrate is dropping, then we'd expect the timestamps to become more spread out 13:51 < jnewbery> last 10 minutes. Any questions? 13:51 < pinheadmz> <timewarp attack> actually we have 2 hours still :-) 13:52 < fl> I dunno my local clock says... 13:53 < jnewbery> ok, thanks everyone! 13:53 < wallet42> thanks @jnewbery! 13:53 < lightlike> thanks! 13:53 < jonatack> V interesting discussion. No Concept ACK from you on the PR? 13:53 < pinheadmz> thanks 13:53 < fl> jnewbery thanks great pr review 13:53 < ariard> thanks jnewbery, was really interesting! 13:53 < rockstardev> pinheadmz: good one 13:54 < jnewbery> I'm out of office and won't make the next couple of review clubs. I'm going to try to find someone else to host, so keep an eye out on the website for details. 13:56 < jnewbery> jonatack: I believe Matt has some updates to make to his consensus cleanup proposal. I'm going to hold off on concept reviewing until after that 13:57 < jonatack> jnewbery: thanks