@@ -7,171 +7,170 @@ const varuint = require('varuint-bitcoin')
77
88const Transaction = require ( './transaction' )
99
10- function Block ( ) {
11- this . version = 1
12- this . prevHash = null
13- this . merkleRoot = null
14- this . timestamp = 0
15- this . bits = 0
16- this . nonce = 0
17- }
18-
19- Block . fromBuffer = function ( buffer ) {
20- if ( buffer . length < 80 ) throw new Error ( 'Buffer too small (< 80 bytes)' )
21-
22- let offset = 0
23- function readSlice ( n ) {
24- offset += n
25- return buffer . slice ( offset - n , offset )
10+ class Block {
11+ constructor ( ) {
12+ this . version = 1
13+ this . prevHash = null
14+ this . merkleRoot = null
15+ this . timestamp = 0
16+ this . bits = 0
17+ this . nonce = 0
2618 }
2719
28- function readUInt32 ( ) {
29- const i = buffer . readUInt32LE ( offset )
30- offset += 4
31- return i
20+ static fromBuffer ( buffer ) {
21+ if ( buffer . length < 80 ) throw new Error ( 'Buffer too small (< 80 bytes)' )
22+
23+ let offset = 0
24+ const readSlice = n => {
25+ offset += n
26+ return buffer . slice ( offset - n , offset )
27+ }
28+
29+ const readUInt32 = ( ) => {
30+ const i = buffer . readUInt32LE ( offset )
31+ offset += 4
32+ return i
33+ }
34+
35+ const readInt32 = ( ) => {
36+ const i = buffer . readInt32LE ( offset )
37+ offset += 4
38+ return i
39+ }
40+
41+ const block = new Block ( )
42+ block . version = readInt32 ( )
43+ block . prevHash = readSlice ( 32 )
44+ block . merkleRoot = readSlice ( 32 )
45+ block . timestamp = readUInt32 ( )
46+ block . bits = readUInt32 ( )
47+ block . nonce = readUInt32 ( )
48+
49+ if ( buffer . length === 80 ) return block
50+
51+ const readVarInt = ( ) => {
52+ const vi = varuint . decode ( buffer , offset )
53+ offset += varuint . decode . bytes
54+ return vi
55+ }
56+
57+ const readTransaction = ( ) => {
58+ const tx = Transaction . fromBuffer ( buffer . slice ( offset ) , true )
59+ offset += tx . byteLength ( )
60+ return tx
61+ }
62+
63+ const nTransactions = readVarInt ( )
64+ block . transactions = [ ]
65+
66+ for ( var i = 0 ; i < nTransactions ; ++ i ) {
67+ const tx = readTransaction ( )
68+ block . transactions . push ( tx )
69+ }
70+
71+ return block
3272 }
3373
34- function readInt32 ( ) {
35- const i = buffer . readInt32LE ( offset )
36- offset += 4
37- return i
74+ static fromHex ( hex ) {
75+ return Block . fromBuffer ( Buffer . from ( hex , 'hex' ) )
3876 }
3977
40- const block = new Block ( )
41- block . version = readInt32 ( )
42- block . prevHash = readSlice ( 32 )
43- block . merkleRoot = readSlice ( 32 )
44- block . timestamp = readUInt32 ( )
45- block . bits = readUInt32 ( )
46- block . nonce = readUInt32 ( )
47-
48- if ( buffer . length === 80 ) return block
49-
50- function readVarInt ( ) {
51- const vi = varuint . decode ( buffer , offset )
52- offset += varuint . decode . bytes
53- return vi
78+ static calculateTarget ( bits ) {
79+ const exponent = ( ( bits & 0xff000000 ) >> 24 ) - 3
80+ const mantissa = bits & 0x007fffff
81+ const target = Buffer . alloc ( 32 , 0 )
82+ target . writeUIntBE ( mantissa , 29 - exponent , 3 )
83+ return target
5484 }
5585
56- function readTransaction ( ) {
57- const tx = Transaction . fromBuffer ( buffer . slice ( offset ) , true )
58- offset += tx . byteLength ( )
59- return tx
60- }
86+ static calculateMerkleRoot ( transactions ) {
87+ typeforce ( [ { getHash : types . Function } ] , transactions )
88+ if ( transactions . length === 0 ) throw TypeError ( 'Cannot compute merkle root for zero transactions' )
6189
62- const nTransactions = readVarInt ( )
63- block . transactions = [ ]
90+ const hashes = transactions . map ( transaction => transaction . getHash ( ) )
6491
65- for ( var i = 0 ; i < nTransactions ; ++ i ) {
66- const tx = readTransaction ( )
67- block . transactions . push ( tx )
92+ return fastMerkleRoot ( hashes , bcrypto . hash256 )
6893 }
6994
70- return block
71- }
72-
73- Block . prototype . byteLength = function ( headersOnly ) {
74- if ( headersOnly || ! this . transactions ) return 80
75-
76- return 80 + varuint . encodingLength ( this . transactions . length ) + this . transactions . reduce ( function ( a , x ) {
77- return a + x . byteLength ( )
78- } , 0 )
79- }
80-
81- Block . fromHex = function ( hex ) {
82- return Block . fromBuffer ( Buffer . from ( hex , 'hex' ) )
83- }
84-
85- Block . prototype . getHash = function ( ) {
86- return bcrypto . hash256 ( this . toBuffer ( true ) )
87- }
88-
89- Block . prototype . getId = function ( ) {
90- return this . getHash ( ) . reverse ( ) . toString ( 'hex' )
91- }
92-
93- Block . prototype . getUTCDate = function ( ) {
94- const date = new Date ( 0 ) // epoch
95- date . setUTCSeconds ( this . timestamp )
96-
97- return date
98- }
95+ byteLength ( headersOnly ) {
96+ if ( headersOnly || ! this . transactions ) return 80
9997
100- // TODO: buffer, offset compatibility
101- Block . prototype . toBuffer = function ( headersOnly ) {
102- const buffer = Buffer . allocUnsafe ( this . byteLength ( headersOnly ) )
103-
104- let offset = 0
105- function writeSlice ( slice ) {
106- slice . copy ( buffer , offset )
107- offset += slice . length
98+ return 80 + varuint . encodingLength ( this . transactions . length ) +
99+ this . transactions . reduce ( ( a , x ) => a + x . byteLength ( ) , 0 )
108100 }
109101
110- function writeInt32 ( i ) {
111- buffer . writeInt32LE ( i , offset )
112- offset += 4
113- }
114- function writeUInt32 ( i ) {
115- buffer . writeUInt32LE ( i , offset )
116- offset += 4
102+ getHash ( ) {
103+ return bcrypto . hash256 ( this . toBuffer ( true ) )
117104 }
118105
119- writeInt32 ( this . version )
120- writeSlice ( this . prevHash )
121- writeSlice ( this . merkleRoot )
122- writeUInt32 ( this . timestamp )
123- writeUInt32 ( this . bits )
124- writeUInt32 ( this . nonce )
125-
126- if ( headersOnly || ! this . transactions ) return buffer
127-
128- varuint . encode ( this . transactions . length , buffer , offset )
129- offset += varuint . encode . bytes
130-
131- this . transactions . forEach ( function ( tx ) {
132- const txSize = tx . byteLength ( ) // TODO: extract from toBuffer?
133- tx . toBuffer ( buffer , offset )
134- offset += txSize
135- } )
136-
137- return buffer
138- }
139-
140- Block . prototype . toHex = function ( headersOnly ) {
141- return this . toBuffer ( headersOnly ) . toString ( 'hex' )
142- }
106+ getId ( ) {
107+ return this . getHash ( ) . reverse ( ) . toString ( 'hex' )
108+ }
143109
144- Block . calculateTarget = function ( bits ) {
145- const exponent = ( ( bits & 0xff000000 ) >> 24 ) - 3
146- const mantissa = bits & 0x007fffff
147- const target = Buffer . alloc ( 32 , 0 )
148- target . writeUIntBE ( mantissa , 29 - exponent , 3 )
149- return target
150- }
110+ getUTCDate ( ) {
111+ const date = new Date ( 0 ) // epoch
112+ date . setUTCSeconds ( this . timestamp )
151113
152- Block . calculateMerkleRoot = function ( transactions ) {
153- typeforce ( [ { getHash : types . Function } ] , transactions )
154- if ( transactions . length === 0 ) throw TypeError ( 'Cannot compute merkle root for zero transactions' )
114+ return date
115+ }
155116
156- const hashes = transactions . map ( function ( transaction ) {
157- return transaction . getHash ( )
158- } )
117+ // TODO: buffer, offset compatibility
118+ toBuffer ( headersOnly ) {
119+ const buffer = Buffer . allocUnsafe ( this . byteLength ( headersOnly ) )
120+
121+ let offset = 0
122+ const writeSlice = slice => {
123+ slice . copy ( buffer , offset )
124+ offset += slice . length
125+ }
126+
127+ const writeInt32 = i => {
128+ buffer . writeInt32LE ( i , offset )
129+ offset += 4
130+ }
131+ const writeUInt32 = i => {
132+ buffer . writeUInt32LE ( i , offset )
133+ offset += 4
134+ }
135+
136+ writeInt32 ( this . version )
137+ writeSlice ( this . prevHash )
138+ writeSlice ( this . merkleRoot )
139+ writeUInt32 ( this . timestamp )
140+ writeUInt32 ( this . bits )
141+ writeUInt32 ( this . nonce )
142+
143+ if ( headersOnly || ! this . transactions ) return buffer
144+
145+ varuint . encode ( this . transactions . length , buffer , offset )
146+ offset += varuint . encode . bytes
147+
148+ this . transactions . forEach ( tx => {
149+ const txSize = tx . byteLength ( ) // TODO: extract from toBuffer?
150+ tx . toBuffer ( buffer , offset )
151+ offset += txSize
152+ } )
153+
154+ return buffer
155+ }
159156
160- return fastMerkleRoot ( hashes , bcrypto . hash256 )
161- }
157+ toHex ( headersOnly ) {
158+ return this . toBuffer ( headersOnly ) . toString ( 'hex' )
159+ }
162160
163- Block . prototype . checkMerkleRoot = function ( ) {
164- if ( ! this . transactions ) return false
161+ checkMerkleRoot ( ) {
162+ if ( ! this . transactions ) return false
165163
166- const actualMerkleRoot = Block . calculateMerkleRoot ( this . transactions )
167- return this . merkleRoot . compare ( actualMerkleRoot ) === 0
168- }
164+ const actualMerkleRoot = Block . calculateMerkleRoot ( this . transactions )
165+ return this . merkleRoot . compare ( actualMerkleRoot ) === 0
166+ }
169167
170- Block . prototype . checkProofOfWork = function ( ) {
171- const hash = this . getHash ( ) . reverse ( )
172- const target = Block . calculateTarget ( this . bits )
168+ checkProofOfWork ( ) {
169+ const hash = this . getHash ( ) . reverse ( )
170+ const target = Block . calculateTarget ( this . bits )
173171
174- return hash . compare ( target ) <= 0
172+ return hash . compare ( target ) <= 0
173+ }
175174}
176175
177176module . exports = Block
0 commit comments