Skip to content

Commit 5b39a4c

Browse files
committed
add bitcoin header
1 parent a95118a commit 5b39a4c

File tree

2 files changed

+203
-1
lines changed

2 files changed

+203
-1
lines changed

README.md

+113-1
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ d2.to_s # convert 32-byte (256-bit) binary to hex string
10381038
```
10391039

10401040
Note: Classic bitcoin uses a double hash, that is,
1041-
for even higher security the hash gets hashed twice with the SHA256 algorithm
1041+
for even higher security the hash gets hashed twice with the SHA256 algorithm
10421042
e.g. `sha256(sha256(header))`.
10431043

10441044
In practice let's deal with the different byte order conversions
@@ -1184,13 +1184,125 @@ bin_to_hex32( d2 )
11841184
```
11851185

11861186

1187+
Bonus. For easy (re)use let's package up the bitcoin block header code into a class:
1188+
1189+
``` ruby
1190+
require 'digest'
1191+
1192+
module Bitcoin
1193+
class Header
1194+
attr_reader :version
1195+
attr_reader :prev
1196+
attr_reader :merkleroot
1197+
attr_reader :time
1198+
attr_reader :bits
1199+
attr_reader :nonce
1200+
1201+
def initialize( version, prev, merkleroot, time, bits, nonce )
1202+
@version = version
1203+
@prev = prev
1204+
@merkleroot = merkleroot
1205+
@time = time
1206+
@bits = bits
1207+
@nonce = nonce
1208+
end
1209+
1210+
## lets add a convenience c'tor helper
1211+
def self.from_hash( h )
1212+
new( h[:version],
1213+
h[:prev],
1214+
h[:merkleroot],
1215+
h[:time],
1216+
h[:bits],
1217+
h[:nonce] )
1218+
end
1219+
1220+
def to_bin
1221+
i4( version ) +
1222+
h32( prev ) +
1223+
h32( merkleroot ) +
1224+
i4( time ) +
1225+
i4( bits.to_i(16) ) +
1226+
i4( nonce )
1227+
end
1228+
1229+
def hash
1230+
bytes = sha256(sha256( to_bin ))
1231+
bin_to_h32( bytes )
1232+
end
1233+
1234+
def sha256( bytes )
1235+
Digest::SHA256.digest( bytes )
1236+
end
1237+
1238+
## binary pack/unpack conversion helpers
1239+
def i4( num ) ## integer (4 byte / 32bit) to binary (in little endian)
1240+
[num].pack( 'V' )
1241+
end
1242+
1243+
def h32( hex ) ## hex string (32 byte / 256 bit / 64 hex chars) to binary
1244+
[hex].pack( 'H*' ).reverse ## change byte order (w/ reverse)
1245+
end
1246+
1247+
def bin_to_h32( bytes )
1248+
bytes.reverse.unpack( 'H*' )[0] ## note: change byte order (w/ reverse)
1249+
end
1250+
end # class Header
1251+
end # module Bitcoin
1252+
```
1253+
1254+
and let's test drive it with the genesis block #0 and block #125552:
1255+
1256+
``` ruby
1257+
b0 =
1258+
Bitcoin::Header.from_hash(
1259+
version: 1,
1260+
prev: '0000000000000000000000000000000000000000000000000000000000000000',
1261+
merkleroot: '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b',
1262+
time: 1231006505,
1263+
bits: '1d00ffff',
1264+
nonce: 2083236893 )
1265+
1266+
b0.hash
1267+
#=> "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
1268+
1269+
b125552 =
1270+
Bitcoin::Header.from_hash(
1271+
version: 1,
1272+
prev: '00000000000008a3a41b85b8b29ad444def299fee21793cd8b9e567eab02cd81',
1273+
merkleroot: '2b12fcf1b09288fcaff797d71e950e71ae42b91e8bdb2304758dfcffc2b620e3',
1274+
time: 1305998791,
1275+
bits: '1a44b9f2',
1276+
nonce: 2504433986 )
1277+
1278+
b125552.hash
1279+
#=> "00000000000000001e8d6829a8a21adc5d38d0a473b144b6765798e61f98bd1d"
1280+
```
1281+
1282+
1283+
11871284

11881285

11891286
## (Crypto) Block with Transactions (Tx)
11901287

11911288
To be continued.
11921289

11931290

1291+
1292+
1293+
1294+
1295+
1296+
1297+
## References / Links
1298+
1299+
- [Programming Cryptocurrencies and Blockchains in Ruby](http://yukimotopress.github.io/blockchains)
1300+
@ [Yuki & Moto Press Bookshelf](http://yukimotopress.github.io), Free (Online) Booklet
1301+
- [Awesome Blockchains](https://github.com/openblockchains/awesome-blockchains) @ [Open Bockchains](https://github.com/openblockchains)
1302+
- [Awesome Crypto](https://github.com/planetruby/awesome-crypto) @ [Planet Ruby](https://github.com/planetruby)
1303+
1304+
1305+
11941306
## Questions? Comments?
11951307

11961308
Send them to the [ruby-talk mailing list](https://www.ruby-lang.org/en/community/mailing-lists/)

bitcoin_header.rb

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
require 'digest'
2+
require 'pp'
3+
4+
5+
module Bitcoin
6+
class Header
7+
attr_reader :version
8+
attr_reader :prev
9+
attr_reader :merkleroot
10+
attr_reader :time
11+
attr_reader :bits
12+
attr_reader :nonce
13+
14+
def initialize( version, prev, merkleroot, time, bits, nonce )
15+
@version = version
16+
@prev = prev
17+
@merkleroot = merkleroot
18+
@time = time
19+
@bits = bits
20+
@nonce = nonce
21+
end
22+
23+
## lets add a convenience c'tor helper
24+
def self.from_hash( h )
25+
new( h[:version],
26+
h[:prev],
27+
h[:merkleroot],
28+
h[:time],
29+
h[:bits],
30+
h[:nonce] )
31+
end
32+
33+
def to_bin
34+
i4( version ) +
35+
h32( prev ) +
36+
h32( merkleroot ) +
37+
i4( time ) +
38+
i4( bits.to_i(16) ) +
39+
i4( nonce )
40+
end
41+
42+
def hash
43+
bytes = sha256(sha256( to_bin ))
44+
bin_to_h32( bytes )
45+
end
46+
47+
def sha256( bytes )
48+
Digest::SHA256.digest( bytes )
49+
end
50+
51+
## binary pack/unpack conversion helpers
52+
def i4( num ) ## integer (4 byte / 32bit) to binary (in little endian)
53+
[num].pack( 'V' )
54+
end
55+
56+
def h32( hex ) ## hex string (32 byte / 256 bit / 64 hex chars) to binary
57+
[hex].pack( 'H*' ).reverse ## change byte order (w/ reverse)
58+
end
59+
60+
def bin_to_h32( bytes )
61+
bytes.reverse.unpack( 'H*' )[0] ## note: change byte order (w/ reverse)
62+
end
63+
end # class Header
64+
end # module Bitcoin
65+
66+
67+
68+
## test
69+
70+
pp b0 =
71+
Bitcoin::Header.from_hash(
72+
version: 1,
73+
prev: '0000000000000000000000000000000000000000000000000000000000000000',
74+
merkleroot: '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b',
75+
time: 1231006505,
76+
bits: '1d00ffff',
77+
nonce: 2083236893 )
78+
79+
pp b0.hash
80+
81+
pp b125552 =
82+
Bitcoin::Header.from_hash(
83+
version: 1,
84+
prev: '00000000000008a3a41b85b8b29ad444def299fee21793cd8b9e567eab02cd81',
85+
merkleroot: '2b12fcf1b09288fcaff797d71e950e71ae42b91e8bdb2304758dfcffc2b620e3',
86+
time: 1305998791, ## 2011-05-21 17:26:31
87+
bits: '1a44b9f2',
88+
nonce: 2504433986 )
89+
90+
pp b125552.hash

0 commit comments

Comments
 (0)