How Bitcoin Mining Works:
Me: I just set a $100 bill on fire.
Everyone: That's stupid.
Me: I have undeniable proof.
Bitcoiners: We'll give you $200 for it.
Did you know? The Proof-of-work / waste mining lottery in bitcoin is a global energy environmental disaster. The estimate for bitcoin classic transactions is 300 kW-h per bitcoin transaction (!) that's about 179 kilograms of CO₂ emissions¹.
¹: Assuming let's say 0.596 kilograms of CO₂ per kW-h (that's the energy efficiency in Germany) that's about 179 kilograms of CO₂ per bitcoin transaction (300 kW-h × 0.596 kg). For more insights see Bitcoin CO₂ - The Proof-of-Work / Waste Environmental Mining Disaster.
Let's look how Bitcoin's Proof-of-Work / Waste 10-Minute Mining Lottery works and what's the lucky number used once (nonce) that wins the mining lottery and what's the difficulty target to make it easier or harder to find the nonce.
Let's say the base string that we are going to do work on is
"Hello, world!"
. Our target is to find a variation of it that SHA-256 hashes to a value smaller than2^240
. We vary the string by adding an integer value to the end called a nonce and incrementing it each time, then interpreting the hash result as a long integer and checking whether it's smaller than the target2^240
. Finding a match for"Hello, world!"
takes us 4251 tries."Hello, world!0" => 1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64 = 2^252.253458683 "Hello, world!1" => e9afc424b79e4f6ab42d99c81156d3a17228d6e1eef4139be78e948a9332a7d8 = 2^255.868431117 "Hello, world!2" => ae37343a357a8297591625e7134cbea22f5928be8ca2a32aa475cf05fd4266b7 = 2^255.444730341 ... "Hello, world!4248" => 6e110d98b388e77e9c6f042ac6b497cec46660deef75a55ebc7cfdf65cc0b965 = 2^254.782233115 "Hello, world!4249" => c004190b822f1669cac8dc37e761cb73652e7832fb814565702245cf26ebb9e6 = 2^255.585082774 "Hello, world!4250" => 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9 = 2^239.61238653
4 251 hashes on a modern computer is not very much work (most computers can achieve at least 4 million hashes per second). Bitcoin automatically varies the target (and thus the amount of work required to generate a block) to keep a roughly constant rate of block generation [,that is, about every 10 minutes for the mining lottery].
(Source: Proof of work @ Bitcoin Wiki)
Let's break down the "magic" proof-of-work / waste lottery step-by-step and let's start with calculating the SHA-256 hash:
require "digest"
def sha256( msg )
Digest::SHA256.hexdigest( msg )
end
sha256( "Hello, world!0" )
#=> "1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64"
sha256( "Hello, world!1" )
#=> "e9afc424b79e4f6ab42d99c81156d3a17228d6e1eef4139be78e948a9332a7d8"
sha256( "Hello, world!2" )
#=> "ae37343a357a8297591625e7134cbea22f5928be8ca2a32aa475cf05fd4266b7"
# ...
sha256( "Hello, world!4248" )
#=> "6e110d98b388e77e9c6f042ac6b497cec46660deef75a55ebc7cfdf65cc0b965"
sha256( "Hello, world!4249" )
#=> "c004190b822f1669cac8dc37e761cb73652e7832fb814565702245cf26ebb9e6"
sha256( "Hello, world!4250" )
#=> "0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9"
(Source: hashes.rb
)
Note: The resulting hash is always a fixed 256-bit in size or 64 hex(adecimal) characters (0-9,a-f) in length even if the input is less than 256-bit or much bigger than 256-bit.
Trivia Quiz: What's SHA256?
- (A) Still Hacking Anyway
- (B) Secure Hash Algorithm
- (C) Sweet Home Austria
- (D) Super High Aperture
B: SHA256 == Secure Hash Algorithms 256 Bits
SHA256 is a (secure) hashing algorithm designed by the National Security Agency (NSA) of the United States of America (USA).
Find out more @ Secure Hash Algorithms (SHA) @ Wikipedia.
Let's get back to:
4 251 hashes on a modern computer is not very much work - most computers can achieve at least 4 million (or 4,000,000) hashes per second.
Bitcoin's hash rate experienced an explosive increase over 2019, jumping from 42 exahashes per second (EH/s) (or, 42,000,000,000,000,000,000 hashes per second) to 112 EH/s (or, 112,000,000,000,000,000,000 hashes per second).
(Source: Happy Birthday Bitcoin! Here's a Look at Bitcoin's 11th Year by the Numbers)
What's your hash rate per second? Let's calculate 10 million (or 10,000,000) hashes and check...
#################
## Let's calculate 10 million, that is, 10 000 000 hashes.
## e.g. "Hello, world!0"
## "Hello, world!1"
## "Hello, world!2"
## "Hello, world!3"
## and on and on and on
t1 = Time.now
10_000_000.times do |i|
sha256( "Hello, world!#{i}")
# bonus: print a dot (.) for progress for every one hundred thousand hashes calculated
print "." if i % 100_000 == 0
end
t2 = Time.now
delta = t2 - t1
puts ""
puts "Elapsed Time: %.4f seconds" % delta
hashrate = Float( 10_000_000 / delta )
puts "Hash Rate: %d hashes/second" % hashrate
(Source: hashrate.rb
)
Resulting in (using a plain-vanilla personal computer in 2020):
....................................................................................................
Elapsed Time: 26.7724 seconds
Hash Rate: 373,518 hashes/second
Try the script at your computer. What's your hash rate today?
Trivia Quiz: What's the (advertised) hash rate/s for the ASIC (Application-specific integrated circuit) AntMiner S9 sold by Bitmain for US$ 2,400?
- (A) 14,000,000 hashes/second
- (B) 14,000,000,000 hashes/second
- (C) 14,000,000,000,000 hashes/second
- (D) 14,000,000,000,000,000 hashes/second
C: 14,000,000,000,000 hashes/second (or 14,000,000 million hashes/s)
Find out more @ Mining hardware comparison @ Bitcoin Wiki
Hitting the difficulty target - Find the lucky number used once (nonce) - Find the winning mining lottery ticket
Let's get back to:
Our target is to find a variation of it that SHA-256 hashes
to a value smaller than 2^240
.
Every hash is really a big 256-bit (integer) number.
Let's convert the "Hello, world!0"
hash in hex(adecimal) format
e.g. "1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64"
to a big (integer) number
e.g. 8626955810696577806643191367156697543225924734479747394789354329720975740004
and than calculate the binary base 2 logarithm (log2
)
e.g. 2^252.253458683
.
hash = sha256( "Hello, world!0" )
#=> "1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64"
num = hash.to_i( 16 ) ## convert hex(adecimal) hash to (integer) number
#=> 8626955810696577806643191367156697543225924734479747394789354329720975740004
(Source: target.rb
)
Q: What's the binary base 2 logarithm (log2
)?
In mathematics, the binary logarithm (
log2 n
) is the power to which the number 2 must be raised to obtain the valuen
. That is, for any real numberx
,x = log2(n) <==> 2^x = n.
Let's try:
log2 = Math.log2( num )
#=> 252.2534586827243
Bingo! 2^252.2534586827243
is an even more accurate calculation
than the expected 2^252.253458683
.
Let's try the winning lucky number example:
"Hello, world!4250" => 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9 = 2^239.61238653
And here we go:
hash = sha256( "Hello, world!4250" )
#=> "0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9"
Note: The "lucky number" hash has four leading zeros in hex(adecimal), that is, 0000
.
num = hash.to_i( 16 )
#=> 1350565582647790482127632554504241516291697500941742491868079705537959145
log2 = Math.log2( num )
#=> 239.61238652983653
Bingo! 2^239.61238652983653
is an even more accurate calculation
than the expected 2^239.61238653
.
What's up with 2^252
or 2^239
?
The binary logarithm (e.g. 252
or 239
)
tells you how many binary digits the number has.
The higher (252
) the binary logarithm (log2
) the bigger the number,
the lower (239
) the binary logarithm (log2
) the smaller the number.
The maximum for a 256-bit number is - surprise, surprise - 256. Let's double check and calculate:
max = "f"*64
#=> "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
num = max.to_i( 16 )
#=> 115792089237316195423570985008687907853269984665640564039457584007913129639935
log2 = Math.log2( num )
#=> 256.0
Hashes get printed in hexa(decimal) and NOT binary - the computer's native 0
and 1
format - because hexa(decimal) is 4 times more compact.
Let's try:
hash = sha256( "Hello, world!4250" )
#=> "0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9"
num = hash.to_i( 16 )
#=> 1350565582647790482127632554504241516291697500941742491868079705537959145
puts "%0256b" % num
#=> 0000000000000000110000111010111101000010111111000011000100010000
# 0011111100011111110111000000000101010001111110100111010001111111
# 1111100001110011010010011010010001110001010011011111011111001100
# 0101001011101010010001100100111000010010110111001101010011101001
If you count the binary number for the "Hello, world!4250"
hash, it has 16 leading zeros (that is, 0000000000000000
)
in the 256-bit number.
Remember: The more leading zeros (in fixed binary or hexadecimal format) the smaller the number and the more difficult the proof-of-work mining lottery.
Let's put everything together in a mine_hash_with_proof_of_work
method:
def mine_hash_with_proof_of_work( msg, target: 2**240 )
nonce = 0
loop do
hash = sha256( "#{msg}#{nonce}" )
if hash.to_i(16) < target
## bingo! proof of work if hash is smaller than the difficulty target number
return [nonce,hash]
else
## keep trying (and trying and trying)
nonce += 1
end
end # loop
end
(Source: proof_of_work.rb
)
And let's try the Proof-of-Work example from the Bitcoin Wiki.
Note: The difficulty target 2^240
translates to
2**240
and, yes, 2**240
is a big (integer) number.
Try:
2**240 # 2^240
#=> 1766847064778384329583297500742918515827483896875618958121606201292619776
And let's use "Hello, world!"
for the hash:
nonce, hash = mine_hash_with_proof_of_work( "Hello, world!", target: 2**240)
#=> 4250, "0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9"
Bingo! The lucky number used once (nonce) is as expected 4250
and the hash 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9
and the only way to find the lucky winning nonce in the lottery is brute force, that is,
trying and trying and trying.
The proof-of-work involves scanning for a value that when hashed, such as with SHA-256, the hash begins with a number of zero bits. The average work required is exponential in the number of zero bits required and can be verified by executing a single hash.
Note: You can always verify (and double-check) if the hash is smaller than the target difficulty and, thus, valid.
nonce = 4250
msg = "Hello, world!"
hash = sha256( "#{msg}#{nonce}" )
#=> "0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9"
target = 2**240
#=> 1766847064778384329583297500742918515827483896875618958121606201292619776
num = hash.to_i(16)
#=> 1350565582647790482127632554504241516291697500941742491868079705537959145
num < target
#=> true
(Source: verify.rb
)
Try to change the nonce back to 0, 1, 2, etc. and
you will always get false
because the resulting hash is bigger
(and NOT smaller) than the target difficulty and, thus, NOT valid.
Target - The number you need to get below to mine a block.
Difficulty - The difficulty is a number that regulates how long it takes for miners to add new blocks of transactions to the blockchain. This difficulty value updates every 2016 blocks (on average every 2 weeks) to ensure that it takes 10 minutes (on average) to add a new block to the blockchain.
In the genesis block on Jan/3, 2009 the bitcoin classic network
started with a hard-coded maximum target (targetmax
) of:
0x00000000ffff0000000000000000000000000000000000000000000000000000
and the maximum (highest-ever possible) target sets by definition the (lowest-ever possible) difficulty to 1.
If the difficulty goes up (by two, for example), the target number will go down (by half).
If you have only the difficulty you can calculate the target number from the difficulty with the equation:
target = targetmax / difficulty
Let's use the difficulty of block 100,000 (mined on Dec/29, 2010), that is,
14,484.162361
. Yes, that's more than 14 thousand times more difficult since genesis.
targetmax = 0x00000000ffff0000000000000000000000000000000000000000000000000000
#=> 26959535291011309493156476344723991336010898738574164086137773096960
difficulty = 14484.162361
target = targetmax / difficulty
#=> 1861311315012765306929610463010191006516769515973403833769533170
(Source: difficulty.rb
)
Let's try another one and let's use the difficulty seven years later
of block 500,000 (mined on Dec/1, 2017), that is, 1,873,105,475,221.6
.
Yes, that's more than about 2 thousand billion (!) times more difficult since genesis.
Note: As the difficulty goes up, the target goes down.
difficulty = 1873105475221.6
target = targetmax / difficulty
#=> 14392961660539606926930209015440658523615307253181250777
Aside: Floating Point Precision in Calculations with Big Integer Numbers
If you use floating point numbers in your calculations e.g. 14484.162361
with big integer numbers
you will get imprecise results. One alternate way is to
convert everything to integer using a scale factor
(that is, for six digits after the comma multiple by 10**6 equal to 1000000).
Example:
difficulty = 14484.162361
#=> 14484.162361
difficulty = (14484.162361*1000000).to_i
#=> 14484162361
target = (targetmax*1000000) / difficulty
#=> 1861311315012765306929610463010191006516769515973403833769533170
And let's pack up the code in a difficulty_to_target
method
for easy (re)use:
def difficulty_to_target( difficulty, scale: )
targetmax = 0x00000000ffff0000000000000000000000000000000000000000000000000000
factor = 10**scale
targetmax*factor / (difficulty*factor).to_i
end
difficulty_to_target( 14484.162361, scale: 6 )
#=> 1861311315012765306929610463010191006516769515973403833769533170
difficulty_to_target( 1873105475221.6, scale: 1 )
#=> 14392961660539606926930209015440658523615307253181250777
If you print the target in hex(adecimal) you count the leading zeros:
Block | Date | Difficulty | Target | Log2 |
---|---|---|---|---|
0 (Genesis) | Jan/3, 2009 | 1 | 00000000FFFF0000000000000000000000000000000000000000000000000000 |
2^224 |
100,000 | Dec/29, 2010 | 14,484.162361 | 000000000004864c00004d6ac7cd33f734b8eb28b24729fe151953ec57a21ef2 |
2^210 |
500,000 | Dec/1, 2017 | 1,873,105,475,221.6 | 000000000000000000964500000000fc2cc6932cfb3a8ff7cbbf47bd8e22fcd9 |
2^183 |
614,190 | Jan/23, 2020 | 14,776,367,535,688.64 | 000000000000000000130c77ffffffffccc21951757a6bc6d24a653f04e4c7a9 |
2^180 |
What's today's bitcoin network difficulty?
You can use the getdifficulty
Bitcoin API service.
The documentation reads:
getdifficulty
Returns the proof-of-work difficulty as a multiple of the minimum difficulty.
For example, on Jan/23, 2020 you will get:
{
"result": 14776367535688.64
}
Or lookup the difficulty in a chart:
That's all the magic of the proof-of-work / waste mining lottery. The environmental disaster in Bitcoin is the gigantic industrial scale. In 2019 the hash rate/second hit an all-time-high.
And the only purpose for burning millions of $$$ in energy every day (or billions every year) for the proof-of-work / waste hashing is... running a lottery that picks one (!) random winner every 10-minute, that's all.
Bitcoin's hash rate experienced an explosive increase over 2019, jumping from 42 exahashes per second (EH/s) (or, 42,000,000,000,000,000,000 hashes per second) to 112 EH/s (or, 112,000,000,000,000,000,000 hashes per second).
Mining difficulty more than doubled from the beginning to the end of 2019, rising from 6 Trillion to 13 Trillion.
(Source: Happy Birthday Bitcoin! Here's a Look at Bitcoin's 11th Year by the Numbers)
Note: No matter how many more lottery tickets (e.g. from 42,000,000,000,000,000,000/s to 112,000,000,000,000,000,000/s) you "buy" by hashing more and burning more energy - the difficulty will rise (e.g. from 6 T to 13 T) and the lottery keeps on picking one (!) random winner every 10-minute.
Burn, baby, burn! The Planet cannot win. Is there a Planet B?
How to Buy Bitcoin (The CO₂-Friendly Way):
- Take one $50 bill, five $10 bills, or ten $5 bills (I wouldn’t recommend change - stay with paper money).
- Go to the bathroom.
- Lift the lid of the loo.
- Throw money in.
- Flush down water.
Congrats! You just purchased $50 worth of Bitcoin - without fucking the planet!