@btc-vision/bitcoin 6.3.6 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/.mocharc.json +13 -0
  2. package/browser/address.d.ts +1 -1
  3. package/browser/index.js +1 -1
  4. package/browser/index.js.LICENSE.txt +3 -3
  5. package/browser/networks.d.ts +1 -0
  6. package/build/address.d.ts +1 -1
  7. package/build/address.js +12 -5
  8. package/build/block.js +2 -2
  9. package/build/bufferutils.js +5 -5
  10. package/build/networks.d.ts +1 -0
  11. package/build/networks.js +11 -0
  12. package/build/psbt/psbtutils.js +2 -2
  13. package/build/psbt.js +3 -7
  14. package/package.json +26 -26
  15. package/src/address.ts +20 -6
  16. package/src/block.ts +233 -233
  17. package/src/bufferutils.ts +188 -180
  18. package/src/index.ts +86 -86
  19. package/src/networks.ts +12 -0
  20. package/src/psbt/bip371.ts +441 -441
  21. package/src/psbt/psbtutils.ts +4 -3
  22. package/src/psbt.ts +2187 -2187
  23. package/test/address.spec.ts +155 -177
  24. package/test/bitcoin.core.spec.ts +212 -234
  25. package/test/block.spec.ts +171 -194
  26. package/test/bufferutils.spec.ts +450 -513
  27. package/test/crypto.spec.ts +49 -55
  28. package/test/fixtures/address.json +3 -3
  29. package/test/integration/addresses.spec.ts +142 -154
  30. package/test/integration/bip32.spec.ts +130 -151
  31. package/test/integration/blocks.spec.ts +28 -28
  32. package/test/integration/cltv.spec.ts +241 -283
  33. package/test/integration/csv.spec.ts +452 -527
  34. package/test/integration/payments.spec.ts +110 -135
  35. package/test/integration/taproot.spec.ts +663 -707
  36. package/test/integration/transactions.spec.ts +668 -769
  37. package/test/payments.spec.ts +114 -125
  38. package/test/payments.utils.ts +165 -208
  39. package/test/psbt.spec.ts +1285 -1414
  40. package/test/script.spec.ts +186 -210
  41. package/test/script_number.spec.ts +26 -29
  42. package/test/script_signature.spec.ts +66 -66
  43. package/test/transaction.spec.ts +337 -387
  44. package/test/ts-node-register.js +7 -5
  45. package/test/tsconfig.json +4 -1
  46. package/test/types.spec.ts +53 -58
  47. package/.nyc_output/6368a5b2-daa5-4821-8ed0-b742d6fc7eab.json +0 -1
  48. package/.nyc_output/processinfo/6368a5b2-daa5-4821-8ed0-b742d6fc7eab.json +0 -1
  49. package/.nyc_output/processinfo/index.json +0 -1
  50. package/test/address.spec.js +0 -124
  51. package/test/bitcoin.core.spec.js +0 -170
  52. package/test/block.spec.js +0 -141
  53. package/test/bufferutils.spec.js +0 -427
  54. package/test/crypto.spec.js +0 -41
  55. package/test/integration/_regtest.js +0 -7
  56. package/test/integration/addresses.spec.js +0 -116
  57. package/test/integration/bip32.spec.js +0 -85
  58. package/test/integration/blocks.spec.js +0 -26
  59. package/test/integration/cltv.spec.js +0 -199
  60. package/test/integration/csv.spec.js +0 -362
  61. package/test/integration/payments.spec.js +0 -98
  62. package/test/integration/taproot.spec.js +0 -532
  63. package/test/integration/transactions.spec.js +0 -561
  64. package/test/payments.spec.js +0 -97
  65. package/test/payments.utils.js +0 -190
  66. package/test/psbt.spec.js +0 -1044
  67. package/test/script.spec.js +0 -151
  68. package/test/script_number.spec.js +0 -24
  69. package/test/script_signature.spec.js +0 -52
  70. package/test/transaction.spec.js +0 -269
  71. package/test/types.spec.js +0 -46
package/src/block.ts CHANGED
@@ -1,233 +1,233 @@
1
- import { BufferReader, BufferWriter, reverseBuffer, varuint } from './bufferutils.js';
2
- import * as bcrypto from './crypto.js';
3
- import { fastMerkleRoot } from './merkle.js';
4
- import { Transaction } from './transaction.js';
5
- import * as types from './types.js';
6
-
7
- const { typeforce } = types;
8
-
9
- const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions');
10
- const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block');
11
-
12
- export class Block {
13
- version: number = 1;
14
- prevHash?: Buffer = undefined;
15
- merkleRoot?: Buffer = undefined;
16
- timestamp: number = 0;
17
- witnessCommit?: Buffer = undefined;
18
- bits: number = 0;
19
- nonce: number = 0;
20
- transactions?: Transaction[] = undefined;
21
-
22
- static fromBuffer(buffer: Buffer): Block {
23
- if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)');
24
-
25
- const bufferReader = new BufferReader(buffer);
26
-
27
- const block = new Block();
28
- block.version = bufferReader.readInt32();
29
- block.prevHash = bufferReader.readSlice(32);
30
- block.merkleRoot = bufferReader.readSlice(32);
31
- block.timestamp = bufferReader.readUInt32();
32
- block.bits = bufferReader.readUInt32();
33
- block.nonce = bufferReader.readUInt32();
34
-
35
- if (buffer.length === 80) return block;
36
-
37
- const readTransaction = (): any => {
38
- const tx = Transaction.fromBuffer(bufferReader.buffer.slice(bufferReader.offset), true);
39
- bufferReader.offset += tx.byteLength();
40
- return tx;
41
- };
42
-
43
- const nTransactions = bufferReader.readVarInt();
44
- block.transactions = [];
45
-
46
- for (let i = 0; i < nTransactions; ++i) {
47
- const tx = readTransaction();
48
- block.transactions.push(tx);
49
- }
50
-
51
- const witnessCommit = block.getWitnessCommit();
52
- // This Block contains a witness commit
53
- if (witnessCommit) block.witnessCommit = witnessCommit;
54
-
55
- return block;
56
- }
57
-
58
- static fromHex(hex: string): Block {
59
- return Block.fromBuffer(Buffer.from(hex, 'hex'));
60
- }
61
-
62
- static calculateTarget(bits: number): Buffer {
63
- const exponent = ((bits & 0xff000000) >> 24) - 3;
64
- const mantissa = bits & 0x007fffff;
65
- const target = Buffer.alloc(32, 0);
66
- target.writeUIntBE(mantissa, 29 - exponent, 3);
67
- return target;
68
- }
69
-
70
- static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Buffer {
71
- typeforce([{ getHash: types.Function }], transactions);
72
- if (transactions.length === 0) throw errorMerkleNoTxes;
73
- if (forWitness && !txesHaveWitnessCommit(transactions)) throw errorWitnessNotSegwit;
74
-
75
- const hashes = transactions.map((transaction) => transaction.getHash(forWitness!));
76
-
77
- const rootHash = fastMerkleRoot(hashes, bcrypto.hash256);
78
-
79
- return forWitness
80
- ? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]))
81
- : rootHash;
82
- }
83
-
84
- getWitnessCommit(): Buffer | null {
85
- if (!txesHaveWitnessCommit(this.transactions!)) return null;
86
-
87
- // The merkle root for the witness data is in an OP_RETURN output.
88
- // There is no rule for the index of the output, so use filter to find it.
89
- // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed
90
- // If multiple commits are found, the output with highest index is assumed.
91
- const witnessCommits = this.transactions![0].outs.filter((out) =>
92
- out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')),
93
- ).map((out) => out.script.slice(6, 38));
94
- if (witnessCommits.length === 0) return null;
95
- // Use the commit with the highest output (should only be one though)
96
- const result = witnessCommits[witnessCommits.length - 1];
97
-
98
- if (!(result instanceof Buffer && result.length === 32)) return null;
99
- return result;
100
- }
101
-
102
- hasWitnessCommit(): boolean {
103
- if (this.witnessCommit instanceof Buffer && this.witnessCommit.length === 32) return true;
104
- if (this.getWitnessCommit() !== null) return true;
105
- return false;
106
- }
107
-
108
- hasWitness(): boolean {
109
- return anyTxHasWitness(this.transactions!);
110
- }
111
-
112
- weight(): number {
113
- const base = this.byteLength(false, false);
114
- const total = this.byteLength(false, true);
115
- return base * 3 + total;
116
- }
117
-
118
- byteLength(headersOnly?: boolean, allowWitness: boolean = true): number {
119
- if (headersOnly || !this.transactions) return 80;
120
-
121
- return (
122
- 80 +
123
- varuint.encodingLength(this.transactions.length) +
124
- this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0)
125
- );
126
- }
127
-
128
- getHash(): Buffer {
129
- return bcrypto.hash256(this.toBuffer(true));
130
- }
131
-
132
- getId(): string {
133
- return reverseBuffer(this.getHash()).toString('hex');
134
- }
135
-
136
- getUTCDate(): Date {
137
- const date = new Date(0); // epoch
138
- date.setUTCSeconds(this.timestamp);
139
-
140
- return date;
141
- }
142
-
143
- // TODO: buffer, offset compatibility
144
- toBuffer(headersOnly?: boolean): Buffer {
145
- const buffer: Buffer = Buffer.allocUnsafe(this.byteLength(headersOnly));
146
-
147
- const bufferWriter = new BufferWriter(buffer);
148
-
149
- bufferWriter.writeInt32(this.version);
150
- bufferWriter.writeSlice(this.prevHash!);
151
- bufferWriter.writeSlice(this.merkleRoot!);
152
- bufferWriter.writeUInt32(this.timestamp);
153
- bufferWriter.writeUInt32(this.bits);
154
- bufferWriter.writeUInt32(this.nonce);
155
-
156
- if (headersOnly || !this.transactions) return buffer;
157
-
158
- varuint.encode(this.transactions.length, buffer, bufferWriter.offset);
159
- bufferWriter.offset += varuint.encode.bytes;
160
-
161
- this.transactions.forEach((tx) => {
162
- const txSize = tx.byteLength(); // TODO: extract from toBuffer?
163
- tx.toBuffer(buffer, bufferWriter.offset);
164
- bufferWriter.offset += txSize;
165
- });
166
-
167
- return buffer;
168
- }
169
-
170
- toHex(headersOnly?: boolean): string {
171
- return this.toBuffer(headersOnly).toString('hex');
172
- }
173
-
174
- checkTxRoots(): boolean {
175
- // If the Block has segwit transactions but no witness commit,
176
- // there's no way it can be valid, so fail the check.
177
- const hasWitnessCommit = this.hasWitnessCommit();
178
- if (!hasWitnessCommit && this.hasWitness()) return false;
179
- return this.__checkMerkleRoot() && (hasWitnessCommit ? this.__checkWitnessCommit() : true);
180
- }
181
-
182
- checkProofOfWork(): boolean {
183
- const hash: Buffer = reverseBuffer(this.getHash());
184
- const target = Block.calculateTarget(this.bits);
185
-
186
- return hash.compare(target) <= 0;
187
- }
188
-
189
- private __checkMerkleRoot(): boolean {
190
- if (!this.transactions) throw errorMerkleNoTxes;
191
-
192
- const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions);
193
- return this.merkleRoot!.compare(actualMerkleRoot) === 0;
194
- }
195
-
196
- private __checkWitnessCommit(): boolean {
197
- if (!this.transactions) throw errorMerkleNoTxes;
198
- if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit;
199
-
200
- const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true);
201
- return this.witnessCommit!.compare(actualWitnessCommit) === 0;
202
- }
203
- }
204
-
205
- function txesHaveWitnessCommit(transactions: Transaction[]): boolean {
206
- return (
207
- transactions instanceof Array &&
208
- transactions[0] &&
209
- transactions[0].ins &&
210
- transactions[0].ins instanceof Array &&
211
- transactions[0].ins[0] &&
212
- transactions[0].ins[0].witness &&
213
- transactions[0].ins[0].witness instanceof Array &&
214
- transactions[0].ins[0].witness.length > 0
215
- );
216
- }
217
-
218
- function anyTxHasWitness(transactions: Transaction[]): boolean {
219
- return (
220
- transactions instanceof Array &&
221
- transactions.some(
222
- (tx) =>
223
- typeof tx === 'object' &&
224
- tx.ins instanceof Array &&
225
- tx.ins.some(
226
- (input) =>
227
- typeof input === 'object' &&
228
- input.witness instanceof Array &&
229
- input.witness.length > 0,
230
- ),
231
- )
232
- );
233
- }
1
+ import { BufferReader, BufferWriter, reverseBuffer, varuint } from './bufferutils.js';
2
+ import * as bcrypto from './crypto.js';
3
+ import { fastMerkleRoot } from './merkle.js';
4
+ import { Transaction } from './transaction.js';
5
+ import * as types from './types.js';
6
+
7
+ const { typeforce } = types;
8
+
9
+ const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions');
10
+ const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block');
11
+
12
+ export class Block {
13
+ version: number = 1;
14
+ prevHash?: Buffer = undefined;
15
+ merkleRoot?: Buffer = undefined;
16
+ timestamp: number = 0;
17
+ witnessCommit?: Buffer = undefined;
18
+ bits: number = 0;
19
+ nonce: number = 0;
20
+ transactions?: Transaction[] = undefined;
21
+
22
+ static fromBuffer(buffer: Buffer): Block {
23
+ if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)');
24
+
25
+ const bufferReader = new BufferReader(buffer);
26
+
27
+ const block = new Block();
28
+ block.version = bufferReader.readInt32();
29
+ block.prevHash = bufferReader.readSlice(32);
30
+ block.merkleRoot = bufferReader.readSlice(32);
31
+ block.timestamp = bufferReader.readUInt32();
32
+ block.bits = bufferReader.readUInt32();
33
+ block.nonce = bufferReader.readUInt32();
34
+
35
+ if (buffer.length === 80) return block;
36
+
37
+ const readTransaction = (): any => {
38
+ const tx = Transaction.fromBuffer(bufferReader.buffer.slice(bufferReader.offset), true);
39
+ bufferReader.offset += tx.byteLength();
40
+ return tx;
41
+ };
42
+
43
+ const nTransactions = bufferReader.readVarInt();
44
+ block.transactions = [];
45
+
46
+ for (let i = 0; i < nTransactions; ++i) {
47
+ const tx = readTransaction();
48
+ block.transactions.push(tx);
49
+ }
50
+
51
+ const witnessCommit = block.getWitnessCommit();
52
+ // This Block contains a witness commit
53
+ if (witnessCommit) block.witnessCommit = witnessCommit;
54
+
55
+ return block;
56
+ }
57
+
58
+ static fromHex(hex: string): Block {
59
+ return Block.fromBuffer(Buffer.from(hex, 'hex'));
60
+ }
61
+
62
+ static calculateTarget(bits: number): Buffer {
63
+ const exponent = ((bits & 0xff000000) >> 24) - 3;
64
+ const mantissa = bits & 0x007fffff;
65
+ const target = Buffer.alloc(32, 0);
66
+ target.writeUIntBE(mantissa, 29 - exponent, 3);
67
+ return target;
68
+ }
69
+
70
+ static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Buffer {
71
+ typeforce([{ getHash: types.Function }], transactions);
72
+ if (transactions.length === 0) throw errorMerkleNoTxes;
73
+ if (forWitness && !txesHaveWitnessCommit(transactions)) throw errorWitnessNotSegwit;
74
+
75
+ const hashes = transactions.map((transaction) => transaction.getHash(forWitness!));
76
+
77
+ const rootHash = fastMerkleRoot(hashes, bcrypto.hash256);
78
+
79
+ return forWitness
80
+ ? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]))
81
+ : rootHash;
82
+ }
83
+
84
+ getWitnessCommit(): Buffer | null {
85
+ if (!txesHaveWitnessCommit(this.transactions!)) return null;
86
+
87
+ // The merkle root for the witness data is in an OP_RETURN output.
88
+ // There is no rule for the index of the output, so use filter to find it.
89
+ // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed
90
+ // If multiple commits are found, the output with highest index is assumed.
91
+ const witnessCommits = this.transactions![0].outs.filter((out) =>
92
+ out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')),
93
+ ).map((out) => out.script.slice(6, 38));
94
+ if (witnessCommits.length === 0) return null;
95
+ // Use the commit with the highest output (should only be one though)
96
+ const result = witnessCommits[witnessCommits.length - 1];
97
+
98
+ if (!(result instanceof Buffer && result.length === 32)) return null;
99
+ return result;
100
+ }
101
+
102
+ hasWitnessCommit(): boolean {
103
+ if (this.witnessCommit instanceof Buffer && this.witnessCommit.length === 32) return true;
104
+ if (this.getWitnessCommit() !== null) return true;
105
+ return false;
106
+ }
107
+
108
+ hasWitness(): boolean {
109
+ return anyTxHasWitness(this.transactions!);
110
+ }
111
+
112
+ weight(): number {
113
+ const base = this.byteLength(false, false);
114
+ const total = this.byteLength(false, true);
115
+ return base * 3 + total;
116
+ }
117
+
118
+ byteLength(headersOnly?: boolean, allowWitness: boolean = true): number {
119
+ if (headersOnly || !this.transactions) return 80;
120
+
121
+ return (
122
+ 80 +
123
+ varuint.encodingLength(this.transactions.length) +
124
+ this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0)
125
+ );
126
+ }
127
+
128
+ getHash(): Buffer {
129
+ return bcrypto.hash256(this.toBuffer(true));
130
+ }
131
+
132
+ getId(): string {
133
+ return reverseBuffer(this.getHash()).toString('hex');
134
+ }
135
+
136
+ getUTCDate(): Date {
137
+ const date = new Date(0); // epoch
138
+ date.setUTCSeconds(this.timestamp);
139
+
140
+ return date;
141
+ }
142
+
143
+ // TODO: buffer, offset compatibility
144
+ toBuffer(headersOnly?: boolean): Buffer {
145
+ const buffer: Buffer = Buffer.allocUnsafe(this.byteLength(headersOnly));
146
+
147
+ const bufferWriter = new BufferWriter(buffer);
148
+
149
+ bufferWriter.writeInt32(this.version);
150
+ bufferWriter.writeSlice(this.prevHash!);
151
+ bufferWriter.writeSlice(this.merkleRoot!);
152
+ bufferWriter.writeUInt32(this.timestamp);
153
+ bufferWriter.writeUInt32(this.bits);
154
+ bufferWriter.writeUInt32(this.nonce);
155
+
156
+ if (headersOnly || !this.transactions) return buffer;
157
+
158
+ const encoded = varuint.encode(this.transactions.length, buffer, bufferWriter.offset);
159
+ bufferWriter.offset += encoded.bytes;
160
+
161
+ this.transactions.forEach((tx) => {
162
+ const txSize = tx.byteLength(); // TODO: extract from toBuffer?
163
+ tx.toBuffer(buffer, bufferWriter.offset);
164
+ bufferWriter.offset += txSize;
165
+ });
166
+
167
+ return buffer;
168
+ }
169
+
170
+ toHex(headersOnly?: boolean): string {
171
+ return this.toBuffer(headersOnly).toString('hex');
172
+ }
173
+
174
+ checkTxRoots(): boolean {
175
+ // If the Block has segwit transactions but no witness commit,
176
+ // there's no way it can be valid, so fail the check.
177
+ const hasWitnessCommit = this.hasWitnessCommit();
178
+ if (!hasWitnessCommit && this.hasWitness()) return false;
179
+ return this.__checkMerkleRoot() && (hasWitnessCommit ? this.__checkWitnessCommit() : true);
180
+ }
181
+
182
+ checkProofOfWork(): boolean {
183
+ const hash: Buffer = reverseBuffer(this.getHash());
184
+ const target = Block.calculateTarget(this.bits);
185
+
186
+ return hash.compare(target) <= 0;
187
+ }
188
+
189
+ private __checkMerkleRoot(): boolean {
190
+ if (!this.transactions) throw errorMerkleNoTxes;
191
+
192
+ const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions);
193
+ return this.merkleRoot!.compare(actualMerkleRoot) === 0;
194
+ }
195
+
196
+ private __checkWitnessCommit(): boolean {
197
+ if (!this.transactions) throw errorMerkleNoTxes;
198
+ if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit;
199
+
200
+ const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true);
201
+ return this.witnessCommit!.compare(actualWitnessCommit) === 0;
202
+ }
203
+ }
204
+
205
+ function txesHaveWitnessCommit(transactions: Transaction[]): boolean {
206
+ return (
207
+ transactions instanceof Array &&
208
+ transactions[0] &&
209
+ transactions[0].ins &&
210
+ transactions[0].ins instanceof Array &&
211
+ transactions[0].ins[0] &&
212
+ transactions[0].ins[0].witness &&
213
+ transactions[0].ins[0].witness instanceof Array &&
214
+ transactions[0].ins[0].witness.length > 0
215
+ );
216
+ }
217
+
218
+ function anyTxHasWitness(transactions: Transaction[]): boolean {
219
+ return (
220
+ transactions instanceof Array &&
221
+ transactions.some(
222
+ (tx) =>
223
+ typeof tx === 'object' &&
224
+ tx.ins instanceof Array &&
225
+ tx.ins.some(
226
+ (input) =>
227
+ typeof input === 'object' &&
228
+ input.witness instanceof Array &&
229
+ input.witness.length > 0,
230
+ ),
231
+ )
232
+ );
233
+ }