Skip to content

Commit 390db57

Browse files
committed
Refactor Block to ES6 Class
1 parent 5e1ae82 commit 390db57

File tree

1 file changed

+139
-140
lines changed

1 file changed

+139
-140
lines changed

src/block.js

Lines changed: 139 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -7,171 +7,170 @@ const varuint = require('varuint-bitcoin')
77

88
const 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

177176
module.exports = Block

0 commit comments

Comments
 (0)