Restrict timestamp when mining a diff-adjustment block to prev-600 (
mining) Jun 19, 2019
This PR was proposed in preparation for Matt Corallo’s
Cleanup softfork proposal. ( Mailing list
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:
getblocktemplate (the RPC that a miner calls in order to get a
template block to work on). This PR changes the returned
field returned by
getblocktemplate, such that if the next block is a
difficulty adjustment block, it is constrained by the prev-600 rule.
UpdateTime(), which is called when creating a new block (either
for mining on the node for regtest, or for
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
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?
curtime return value of
getblocktemplate is now constrained by the
prev-600 rule. Why?
7 13:00 <rockstardev> hi... @jnewbery I'll follow up with details after PR review
10 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?
12 13:02 <pinheadmz> read everything, did not test locally
13 13:02 <ccdle12> same as above
15 13:03 <ariard> read notes/BIP and skim over commits
16 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.
18 13:03 <ariard> Getting around to fixing the timewarp attack
19 13:04 <jonatack> * yup built, tested, read
20 13:04 <PaulTroon> I looked over Jon's shoulder :-)
21 13:04 <jnewbery> ok, so let's hit some of those questions
22 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?
23 13:05 <pinheadmz> force a downward difficultly adjustment
24 13:06 <ariard> and so increase the block production rate?
25 13:06 <jnewbery> exactly right
26 13:06 <pinheadmz> making mining easier
27 13:06 <jnewbery> either push difficulty down or keep it low
28 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
29 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
30 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
31 13:08 <sosthene> Is it the same vulnerability that was exploited against Verge was attacked last year?
32 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?
33 13:09 <jnewbery> sosthene: I think similar. As far as I'm aware verge had some system that used multiple POW algorithms
34 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?
35 13:09 <pinheadmz> lightlike: correct, 2 hours
36 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
38 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)
39 13:10 <pinheadmz> and that 2 hours is measured against netwoek-adjusted wall-clock time? not MTP
40 13:10 <nehan> jnewbery: in matt's bip, it's called "timewarp inflation vulnerability". How does inflation come into it?
41 13:10 <jnewbery> pinheadmz: yes, your local time
42 13:10 <ariard> you could redo a blockchain but with less work, so you can't override current chain right?
43 13:11 <kanzure> inflation because subsidy goes out quicker than scheduled
44 13:11 <jnewbery> nehan: because if you can increase the rate of block production, you can increase the rate of new coin emission
45 13:11 <nehan> ok, so it refers to schedule and not # of coins
46 13:11 <jnewbery> nehan: exactly
47 13:11 <jnewbery> it doesn't affect the 21m cap
48 13:12 <pinheadmz> since retarget algo is based on median, how much effect can post-dating block #2015 by 2 hours really have?
49 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
50 13:12 <nehan> i'd appreciate more explanation about the bug, like what pinheadmz asked for (which blocks)
51 13:12 <pinheadmz> or does the attack have to involve more than just the last block
52 13:13 <jnewbery> so if I wanted to create a blockchain with many blocks, I'd do the following:
53 13:13 <jnewbery> create block 1 with a timestamp 1 second after the genesis block
54 13:13 <jnewbery> create block 2 with timestamp one second after that
56 13:14 <jnewbery> create block 2015 with timestamp genesis+2015
57 13:14 <jnewbery> create block 2016 with timestamp 2 weeks in the future
58 13:14 <jnewbery> sorry, timestamp genesis+2 weeks
59 13:14 <jnewbery> create block 2017 with timestmp genesis+2017
61 13:15 <nehan> jnewbery: is that within the 2 hour time bound?
62 13:15 <jnewbery> nehan: correction, not 2 weeks in the future from clock time, 2 weeks in the future from genesis
63 13:15 <nehan> it seems like two weeks + genesis - 2016s + geneses > 2 hours
64 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"
65 13:16 <jnewbery> but because 2017 is back to genesis+2017 seconds, the time hasn't advanced two weeks
66 13:16 <ariard> the hard limit of 2 hours is based on which clock ? Median-Time-Past of X blocks ?
67 13:16 <jnewbery> nehan: the 2 hours check is against clock time on the node
68 13:16 <nehan> hasn't it for block 2016 though? why would nodes accept 2016's with such a far off timestamp?
69 13:16 <jnewbery> the two hour rule is really weird
70 13:16 <nehan> or is it averaged over blocks?
71 13:17 <jnewbery> it's the only 'consensus' rule that isn't based on blockchain data but on local data
72 13:17 <ariard> okay if you're a malicious miner just tune your clock time like you want?
73 13:17 <jnewbery> it's almost better to not think of it as a consensus rule
74 13:17 <jnewbery> ariard: sure, but other people wouldn't accept your block
75 13:18 <jnewbery> because they're all comparing to their (presumably correct) clocks
76 13:18 <ccdle12> so what is the significance of updating previous block nTime to -600 seconds? (why -600 as an arbitrary number)
77 13:19 <ariard> the 600 seconds is to avoid messing with miner software using timestamp field for pow
78 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
79 13:19 <pinheadmz> jnewbery: in your example, why not just create blocks 1-2016 at ten minute intervals? the diff will still stay unchanged?
80 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
81 13:20 <jnewbery> ariard: exactly right. Some miners apparently use the timestamp field as extra nonce and roll it forward up to 10 minutes
82 13:20 <rockstardev> that's a good one... interesting to learn that miners do that with timestamp
83 13:20 <jnewbery> pinheadmz: because at blocks every 10 minutes the timestamp will advance to current time after ~580000 blocks
84 13:20 <fl> there's a bit of a dearth of nonce space IIRC
85 13:21 <jnewbery> the attack is to make a longer blockchain, but without increasing the difficulty
86 13:21 * pinheadmz thumbs up
87 13:21 <jnewbery> so more coinbase subsidy is realeased
88 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.
89 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?
90 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
91 13:23 <pinheadmz> does this attack have to start from genesis?
92 13:23 <fl> pinheadmz no
93 13:23 <lightlike> jnewbery: ok, thanks, I think I got it now :-)
94 13:23 <jnewbery> it means that a 51% attack can now increase the rate at which new coins are minted
95 13:23 <fl> timewarping can start at any block
96 13:23 <jnewbery> fl: yes, exactly correct
97 13:24 <fl> jnewbery to which comment?
98 13:24 <jnewbery> fl: correct that a timewarp can start at any block
100 13:24 <jnewbery> I used genesis as an example because I thought it might simplify the concept, but you could start anywhere
101 13:24 <hugohn> q: why is the 600sec limit in miner.cpp? don't miners run their own sw?
102 13:25 <jnewbery> obviously if you start a more recent block, it'll be more work
103 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)
104 13:26 <pinheadmz> jnewbery: thats awesome! ha
105 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
106 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...
107 13:27 <fl> What would be the effect of sending a timewarped-spoofed chain to a node, would chainstate get erased?
108 13:27 <jnewbery> block 2016 is in the future from the prior block, but it's in the past when your node is validating
109 13:27 <wallet42> jnewbery: awesome! wen polo?
110 13:27 <nehan> jnewbery: aha, because you're starting at genesis, which was a long time ago. got it, thanks!
111 13:27 <jnewbery> yes, my use of the word future was probably confusing
112 13:28 <jnewbery> hugohn: I believe most miners use the Bitcoin Core software to get block templates, which they then do work on
113 13:28 <jnewbery> the `getblocktemplate` RPC will give a block template with the timestamp filled in
115 13:29 <jnewbery> You can see that it also returns `curtime` and `mintime`
116 13:29 <jnewbery> this PR means the value returned for those fields may change. Why?
117 13:30 <ariard> fl: headers-sync first would happen first and your spoffed chain not queried as new chainstate ?
118 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
121 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
122 13:33 <ariard> jnewbery: yes and after 295,000 headers are the counter-measures against resource consumption to track spoofed-chain?
123 13:33 <jnewbery> anyone want to take a shot at why `curtime` and `mintime` might be changed?
124 13:33 <fl> i.e. unless timewarped chain had more chainwork after 295e3 nodes wouldn't switch tips, correct?
125 13:33 <jnewbery> fl: right, we wouldn't reorg unless the new chain contained more work
126 13:34 <jonatack> to cap the mintime at not less than nTime - 600 ?
127 13:34 <hugohn> so this is not a consensus change right? as the 600-limit is only in miner.cpp
128 13:34 <fl> jnewbery but a timewarp spoof chain target node would have some some resource consumption based on header-sync assesment I think
130 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
131 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
132 13:36 <fl> pinheadmz it would benefit miners with low block propogation latency
133 13:36 <jnewbery> hugohn: correct, not a consensus change. This is just miner behaviour change
134 13:36 <jnewbery> pinheadmz: potentially you could combine it with selfish mining if you're not sharing your chain
135 13:37 <jnewbery> but really, the dangerous attack is from a miner (or group of miners) that control 51%
136 13:37 <jnewbery> why might `curtime` change?
137 13:37 <ariard> fl: starting from checkpoints that's only 2,3 GB of headers with current height of 581487
138 13:38 <jonatack> to close the vuln without potentially breaking miner machines
139 13:38 <wallet42> 23 MB
140 13:38 <jnewbery> fl: I believe we won't download the full block if it's not the most work chain - just the header
141 13:38 <wallet42> (581487−295000)×80
142 13:38 <nehan> jnewbery: block->nTime is set on line 41 in UpdateTime(), and it might have been changed at line 37
143 13:39 <ariard> wallet42: oh sorry right
144 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
145 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
146 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%
147 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
148 13:40 <jnewbery> *victim
149 13:40 <fl> issuance rate and preserving DMMS are the more important network properties anti-timewarping attack measures benefit
151 13:41 <wallet42> hm but once you lowered it enough, you can generate 80 bytes very easily no?
154 13:42 <jnewbery> ok, last question: Which function would need to be changed to enforce this timestamp restriction as a consensus rule?
155 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
156 13:42 <nehan> jnewbery: but *why* was that change made?
157 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
158 13:43 <fl> well not more data into blocks but more data per time
159 13:44 <jnewbery> and `curtime` is just taken from the block
162 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?" :)
163 13:46 <jnewbery> hint: it's a consensus rule, so it's probably in validation.cpp
164 13:46 <lightlike> jnewbery: Change CheckBlock() in validation to not accepts new block that break it?
165 13:47 <jnewbery> lightlike: almost!
166 13:47 <jnewbery> the change would actually be in ContextualCheckBlockHeader()
167 13:47 <jnewbery> Header, because this is a field in the block header
168 13:48 <jnewbery> Contextual, because it's a context-dependant check (ie it depends on where the block is in the blockchain)
171 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?
172 13:49 <hugohn> *more than 10 minutes
173 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
174 13:50 <hugohn> *harder than it has to be
175 13:50 <jnewbery> hugohn: the change imposes a new minimum on the block timestamp, not a new maximum
176 13:51 <jnewbery> if the hashrate is dropping, then we'd expect the timestamps to become more spread out
177 13:51 <jnewbery> last 10 minutes. Any questions?
178 13:51 <pinheadmz> <timewarp attack> actually we have 2 hours still :-)
179 13:52 <fl> I dunno my local clock says...
180 13:53 <jnewbery> ok, thanks everyone!
181 13:53 <wallet42> thanks @jnewbery!
182 13:53 <lightlike> thanks!
183 13:53 <jonatack> V interesting discussion. No Concept ACK from you on the PR?
184 13:53 <pinheadmz> thanks
185 13:53 <fl> jnewbery thanks great pr review
186 13:53 <ariard> thanks jnewbery, was really interesting!
187 13:53 <rockstardev> pinheadmz: good one
188 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.
189 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
190 13:57 <jonatack> jnewbery: thanks