UNPKG

3.57 kBJavaScriptView Raw
1/**
2 * Block
3 * =====
4 *
5 * A block, of course, is a collection of transactions. This class is somewhat
6 * incompconste at the moment. In the future, it should support the ability to
7 * check to see if a transaction is in a block (thanks to the magic of merkle
8 * trees). You will probably never use Yours Bitcoin to create a block, since almost
9 * everyone will use bitcoind for that. As such, the primary way to use this is
10 * new Block().fromBuffer(buf), which will parse the block and prepare its insides
11 * for you to inspect.
12 */
13'use strict'
14
15import { Br } from './br'
16import { Bw } from './bw'
17import { BlockHeader } from './block-header'
18import { Hash } from './hash'
19import { Merkle } from './merkle'
20import { Struct } from './struct'
21import { Tx } from './tx'
22import { VarInt } from './var-int'
23import { Workers } from './workers'
24
25class Block extends Struct {
26 constructor (blockHeader, txsVi, txs) {
27 super({ blockHeader, txsVi, txs })
28 }
29
30 fromJSON (json) {
31 const txs = []
32 json.txs.forEach(function (tx) {
33 txs.push(new Tx().fromJSON(tx))
34 })
35 this.fromObject({
36 blockHeader: new BlockHeader().fromJSON(json.blockHeader),
37 txsVi: new VarInt().fromJSON(json.txsVi),
38 txs: txs
39 })
40 return this
41 }
42
43 toJSON () {
44 const txs = []
45 this.txs.forEach(function (tx) {
46 txs.push(tx.toJSON())
47 })
48 return {
49 blockHeader: this.blockHeader.toJSON(),
50 txsVi: this.txsVi.toJSON(),
51 txs: txs
52 }
53 }
54
55 fromBr (br) {
56 this.blockHeader = new BlockHeader().fromBr(br)
57 this.txsVi = new VarInt(br.readVarIntBuf())
58 const txsNum = this.txsVi.toNumber()
59 this.txs = []
60 for (let i = 0; i < txsNum; i++) {
61 this.txs.push(new Tx().fromBr(br))
62 }
63 return this
64 }
65
66 toBw (bw) {
67 if (!bw) {
68 bw = new Bw()
69 }
70 bw.write(this.blockHeader.toBuffer())
71 bw.write(this.txsVi.buf)
72 const txsNum = this.txsVi.toNumber()
73 for (let i = 0; i < txsNum; i++) {
74 this.txs[i].toBw(bw)
75 }
76 return bw
77 }
78
79 hash () {
80 return Hash.sha256Sha256(this.blockHeader.toBuffer())
81 }
82
83 async asyncHash () {
84 const workersResult = await Workers.asyncObjectMethod(this, 'hash', [])
85 return workersResult.resbuf
86 }
87
88 id () {
89 return new Br(this.hash()).readReverse().toString('hex')
90 }
91
92 async asyncId () {
93 const workersResult = await Workers.asyncObjectMethod(this, 'id', [])
94 return JSON.parse(workersResult.resbuf.toString())
95 }
96
97 verifyMerkleRoot () {
98 const txsbufs = this.txs.map(tx => tx.toBuffer())
99 const merkleRootBuf = Merkle.fromBuffers(txsbufs).hash()
100 return Buffer.compare(merkleRootBuf, this.blockHeader.merkleRootBuf)
101 }
102
103 /**
104 * Sometimes we don't want to parse an entire block into memory. Instead, we
105 * simply want to iterate through all transactions in the block. That is what
106 * this method is for. This method returns an efficient iterator which can be
107 * used in a `for (tx of txs)` construct that returns each tx one at a time
108 * without first parsing all of them into memory.
109 *
110 * @param {Buffer} blockBuf A buffer of a block.
111 */
112 static iterateTxs (blockBuf) {
113 const br = new Br(blockBuf)
114 const blockHeader = new BlockHeader().fromBr(br)
115 const txsVi = new VarInt(br.readVarIntBuf())
116 const txsNum = txsVi.toNumber()
117 return {
118 blockHeader,
119 txsVi,
120 txsNum,
121 * [Symbol.iterator] () {
122 for (let i = 0; i < txsNum; i++) {
123 yield new Tx().fromBr(br)
124 }
125 }
126 }
127 }
128}
129
130Block.MAX_BLOCK_SIZE = 1000000
131
132export { Block }