Aug 07•9 min read
What follows is the story of how someone exploited a little-known piece of the core code to create over 184 billion (!!) new Bitcoin; an event early on in Bitcoin's history which threatened the integrity of the network.
Note: This is not FUD aimed at Bitcoin. If anything, this story shows how the Bitcoin community rallied and emerged triumphant in the midst of adversity, proving the resiliency of its Proof-of-Work consensus mechanism in the process.
With that, here's the story of the Value Overflow Incident of 2010.
August 15, 2010.
User jgarzik posts the following in the bitcointalk.org forum:
"The 'value out' in this block #74638 is quite strange:"
Strange indeed: as seen in the above image, the block contained a transaction with 2 outputs (spent BTC) sent to two separate wallets with values of 92,233,720,368.54277039 BTC each.
The transaction, by being accepted by the network and included in the block, had thus inflated the on-chain supply of Bitcoin by > 184 BILLION coins.
One of the core attributes of Bitcoin which makes it a value-added monetary network is its promise that only 21 million coins will ever exist; a feature secured by its code. If that promise were broken, the network - and thus the coins themselves - would cease to have value. As of Block 74638, the network had approved the creation of new coins which increased the supply by orders of magnitude above the 21 million limit, essentially out of thin air.
Block 74638 had violated the rules of the network.
A Network Governed by Code
To fully understand the "bug" that was exploited, we'll first need to dive into a little computer science, specifically the "Int64 Struct."
Int64 is an integer set (range of whole numbers) used in programming to define the limits by which the code will operate within. Int64 spans from -9223372036854775808 to 9223372036854775807, including 0. This is the range of numbers Bitcoin's code can handle when running the network and handling its traffic.
Within that range of numbers, Bitcoin's code also has other limits set to govern the network (most notably the 21-million coin limit): When a transaction is broadcast to the network, the nodes check it to ensure it's "valid," meaning it abides by all the rules defined by the code. Transactions which do not play by the rules are immediately discarded from the mempool and thus, are not included in a block.
Bitcoin checks all basic the things one would expect, just like what occurs when swiping a credit card:
Does the sender have enough balance to cover the amount they're trying to send?
Does the receiving wallet address exist?
Is the value being sent positive? (one cannot send a negative amount of Bitcoin, just like you can't spend negative amounts of dollars)
Does the input amount match the output amount?
Thus, if someone tried to send themselves a transaction of any value that exceeded their wallet balance, the nodes would reject it & the transaction would not exist on chain. This is also the case, as you would expect, if someone tried to include a transaction that totaled more than 21 million bitcoin (or any amount larger than the current total supply); the code would reject it as invalid.
So what went wrong on August 15th, 2010? Why did the code mark this transaction as valid and include it in Block 74638?
The Int64 Strut
Let's go back to the int64 strut: This wide range of numbers is where Bitcoin operates its many variables. In the case of a transaction amount, it counts/checks the total amount satoshi's (sats; 1/100-millionth of a bitcoin, or 0.00000001 BTC) being sent.
If I broadcast a transaction to send 1 bitcoin, the code processes it as sending an integer whose value is "100000000" (100m sats = 1 BTC). The network checks to make sure my balance can cover that, the receiving address exists, and that the output(s) (amount received on the other end) matches the input (amount I sent).
The exploited transaction within Block 74638 violated 3 rules in Bitcoin's code:
The outputs exceeded the balance in the senders wallet.
The outputs exceeded to total amount of coins allowed to exist on the network.
The input amount did not match the amounts of the outputs.
So why was this transaction included?
The fatal flaw here was that while the Bitcoin network ensured the input/output values don't exceed the limits of the code, in the instance where there are 2 recipients (1 input sent to 2 output addresses) it only checked the SUM of those outputs, not the values of each individual output.
By creating a transaction w/ such large outputs, the sender had exploited the limits of the Int64 Strut: the sum of both outputs went beyond the upper limit of the number set. When values overflow out of range, it typically produces an error.
In this specific case, the overflow produced an error by rolling over into the negative, giving a summed value of the transaction's outputs of -.01 BTC from the sender's balance.
To the nodes, it looked like a fee.
Transaction Fees
To quickly cover why this matters: The only exception to the inputs matching the outputs is when a FEE is included in the transaction. The protocol does this by, after checking the output values are positive, ensuring that the inputs(s) are greater-than-or-equal-to (>=) to the outputs.
Note: Fees were not typically required in the early years of the network like they are today; they were a voluntary addition to transactions in 2010, simply because the network didn't handle nearly as much traffic or capture nearly as much energy.
As an example: if I send you 1 bitcoin and pay a 1 satoshi "fee" to the miner of the block, the input would be seen as "100000001" while the output to the receiver would be "100000000" (100000001>=100000000). The spare satoshi left over goes to the miner, and is lumped in with their coinbase reward (reward for mining the block).
The Overflowing of Values
At Block 74638, the sender input (sent) .5 BTC (50000000 sats) with two outputs of ~92B BTC each (~184B total).
The nodes checked the input to ensure the sender had more than .5 BTC, and that the outputs were positive (>0)...
...then checked the SUM of the outputs, which to them only totaled .51 BTC: the .5 sent, as well as the -.01 BTC deducted from the sender that the sums of the 2 outputs produced in error.
To the network, it appeared that someone simply sent .5 BTC and included .01 BTC as a voluntary fee for the miner. The block was mined, attached to the chain, and the network continued onward processing transactions.
But on the blockchain, the addresses of the 2 individual outputs were allowed to accrue the total of each individual output (over 92B bitcoin each), since the transaction which created those outputs summed to only .5 BTC in and .51 BTC out.
The balances may have violated Bitcoin's rules, but the checks designed to prevent a transaction that could create such large balances failed to do so.
The Community Rallies
After discovering the transaction, many of the nodes (who were paying attention) decided to cease processing blocks until a fix could be found. Within a few hours later, the code was patched to ensure all inputs and outputs within a single transaction were checked, not just their sums.
These nodes rolled back the chain to block 74000 and started working again with the fix in place. All transactions which were removed from the blockchain as part of the rollback went back into the mempool (the "on deck circle" for transactions before they're included in a block) to be processed once again.
Although some nodes (those not paying attention in that moment) continued running the faulty code on the chain with the exploited transaction, the "honest" chain, with the fix in place, "out-worked" the exploited chain by ~Block 74691, thus removing the invalid transaction from the "strange block." The event was over and resolved within a matter of hours, and the exploited chain was automatically discarded by all nodes once surpassed in block height.
The "Honest" Nodes Remain Undefeated
This event certainly put Bitcoin in a precarious position, but at the same time it also tested one of Satoshi's original theories: if a bad actor is able to exploit Bitcoin in some fashion, does the network provide enough incentive for "honest" nodes to outwork and defeat them?
In this instance, the answer was undoubtedly "yes."
"We proposed a peer-to-peer network using proof-of-work to record a public history of transactions that quickly becomes computationally impractical for an attacker to change if honest nodes control a majority of CPU power.” -Satoshi Nakamoto
With that, thank you for reading! I hope you enjoyed this piece of Bitcoin history, and learned something new along the way. Skol!
-Trygg
Afterword: On 'Rollbacks'
This story has been used often to justify other blockchain rollbacks, specifically that of the "Ethereum DAO Hack of 2016," which resulted in a hard fork creating 2 seperate chains: Ethereum and Ethereum Classic.
In my opinion, even though they both rolled back their respective ledgers, the two events are not comparable:
In short: Fixing Bitcoin's "Value Overflow Bug" returned the network back to its intended state by removing a transaction which violated the network's rules. Thus, it had consensus as it benefitted the entirety of the network's users (as proven by the "honest" chain overtaking the exploited via PoW). No transactions were lost in the fix, except the invalid one which created the overflow (the patch checked each output individually and discarded the exploited tx as invalid), and the network continued to accept new transactions to the mempool throughout the event.
The rollback to "fix" the Ethereum DAO Hack in 2016 was done to reverse transactions which exploited an unsound smart contract written by the DAO developers themselves. Thus, it benefitted only the DAO's investors. The transaction itself did not violate Ethereum's network rules. This is why a large enough portion of the network was able to opt out and exit the ETH network (creating Ethereum Classic in the process) on ethical grounds that the code by which the network operates is law: a faulty smart contract authored by a minority of the network's users did not justify the majority to violate the network's rules in order to revert the network's state.
The two are not the same.