@btc-vision/bitcoin 6.3.1 → 6.3.2
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.
- package/.babelrc +4 -0
- package/.gitattributes +2 -0
- package/.nyc_output/6368a5b2-daa5-4821-8ed0-b742d6fc7eab.json +1 -0
- package/.nyc_output/processinfo/6368a5b2-daa5-4821-8ed0-b742d6fc7eab.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/.prettierrc.json +12 -0
- package/CHANGELOG.md +403 -0
- package/CONTRIBUTING.md +83 -0
- package/browser/address.d.ts +16 -0
- package/{src → browser}/bip66.d.ts +6 -7
- package/{src → browser}/block.d.ts +29 -30
- package/{src → browser}/bufferutils.d.ts +34 -54
- package/browser/crypto/crypto.d.ts +1 -0
- package/{src → browser}/crypto.d.ts +13 -18
- package/browser/ecc_lib.d.ts +3 -0
- package/browser/hooks/AdvancedSignatureManager.d.ts +16 -0
- package/{src → browser}/hooks/HookedSigner.d.ts +4 -4
- package/browser/hooks/SignatureManager.d.ts +13 -0
- package/browser/index.d.ts +58 -0
- package/browser/index.js +2 -0
- package/browser/index.js.LICENSE.txt +14 -0
- package/browser/merkle.d.ts +1 -0
- package/browser/networks.d.ts +23 -0
- package/{src → browser}/ops.d.ts +126 -126
- package/browser/payments/bip341.d.ts +23 -0
- package/browser/payments/embed.d.ts +2 -0
- package/browser/payments/index.d.ts +41 -0
- package/{src → browser}/payments/lazy.d.ts +2 -2
- package/browser/payments/p2ms.d.ts +2 -0
- package/browser/payments/p2pk.d.ts +2 -0
- package/browser/payments/p2pkh.d.ts +2 -0
- package/browser/payments/p2sh.d.ts +2 -0
- package/browser/payments/p2tr.d.ts +2 -0
- package/browser/payments/p2wpkh.d.ts +2 -0
- package/browser/payments/p2wsh.d.ts +2 -0
- package/browser/psbt/bip371.d.ts +16 -0
- package/browser/psbt/psbtutils.d.ts +26 -0
- package/{src → browser}/psbt.d.ts +167 -238
- package/browser/push_data.d.ts +7 -0
- package/browser/script.d.ts +17 -0
- package/browser/script_number.d.ts +2 -0
- package/browser/script_signature.d.ts +7 -0
- package/{src → browser}/transaction.d.ts +48 -60
- package/{src → browser}/types.d.ts +37 -54
- package/build/address.d.ts +16 -0
- package/build/address.js +148 -0
- package/build/bip66.d.ts +6 -0
- package/build/bip66.js +99 -0
- package/build/block.d.ts +29 -0
- package/build/block.js +181 -0
- package/build/bufferutils.d.ts +34 -0
- package/build/bufferutils.js +141 -0
- package/build/crypto/crypto.d.ts +1 -0
- package/build/crypto/crypto.js +1 -0
- package/build/crypto.d.ts +13 -0
- package/build/crypto.js +87 -0
- package/build/ecc_lib.d.ts +3 -0
- package/build/ecc_lib.js +61 -0
- package/build/hooks/AdvancedSignatureManager.d.ts +16 -0
- package/build/hooks/AdvancedSignatureManager.js +52 -0
- package/build/hooks/HookedSigner.d.ts +4 -0
- package/build/hooks/HookedSigner.js +64 -0
- package/build/hooks/SignatureManager.d.ts +13 -0
- package/build/hooks/SignatureManager.js +45 -0
- package/build/index.d.ts +58 -0
- package/build/index.js +32 -0
- package/build/merkle.d.ts +1 -0
- package/build/merkle.js +19 -0
- package/build/networks.d.ts +23 -0
- package/build/networks.js +121 -0
- package/build/ops.d.ts +126 -0
- package/{src → build}/ops.js +127 -131
- package/build/payments/bip341.d.ts +23 -0
- package/build/payments/bip341.js +82 -0
- package/build/payments/embed.d.ts +2 -0
- package/build/payments/embed.js +39 -0
- package/build/payments/index.d.ts +41 -0
- package/build/payments/index.js +10 -0
- package/build/payments/lazy.d.ts +2 -0
- package/{src → build}/payments/lazy.js +28 -32
- package/build/payments/p2ms.d.ts +2 -0
- package/{src → build}/payments/p2ms.js +128 -158
- package/build/payments/p2pk.d.ts +2 -0
- package/build/payments/p2pk.js +68 -0
- package/build/payments/p2pkh.d.ts +2 -0
- package/build/payments/p2pkh.js +135 -0
- package/build/payments/p2sh.d.ts +2 -0
- package/build/payments/p2sh.js +175 -0
- package/build/payments/p2tr.d.ts +2 -0
- package/build/payments/p2tr.js +254 -0
- package/build/payments/p2wpkh.d.ts +2 -0
- package/build/payments/p2wpkh.js +130 -0
- package/build/payments/p2wsh.d.ts +2 -0
- package/build/payments/p2wsh.js +180 -0
- package/build/psbt/bip371.d.ts +16 -0
- package/build/psbt/bip371.js +246 -0
- package/build/psbt/psbtutils.d.ts +26 -0
- package/build/psbt/psbtutils.js +170 -0
- package/build/psbt.d.ts +167 -0
- package/build/psbt.js +1305 -0
- package/build/push_data.d.ts +7 -0
- package/build/push_data.js +57 -0
- package/build/script.d.ts +17 -0
- package/build/script.js +167 -0
- package/build/script_number.d.ts +2 -0
- package/build/script_number.js +49 -0
- package/build/script_signature.d.ts +7 -0
- package/build/script_signature.js +49 -0
- package/build/transaction.d.ts +48 -0
- package/build/transaction.js +445 -0
- package/build/types.d.ts +37 -0
- package/build/types.js +73 -0
- package/cjs/package.json +3 -0
- package/eslint.config.js +56 -0
- package/gulpfile.js +42 -0
- package/package.json +105 -50
- package/src/{address.js → address.ts} +93 -73
- package/src/{bip66.js → bip66.ts} +23 -19
- package/src/{block.js → block.ts} +114 -105
- package/src/{bufferutils.js → bufferutils.ts} +65 -67
- package/src/crypto/crypto-browser.js +75 -0
- package/src/crypto/crypto.ts +1 -0
- package/src/crypto.ts +108 -0
- package/src/{ecc_lib.js → ecc_lib.ts} +25 -53
- package/src/hooks/{AdvancedSignatureManager.js → AdvancedSignatureManager.ts} +34 -18
- package/src/hooks/HookedSigner.ts +108 -0
- package/src/hooks/{SignatureManager.js → SignatureManager.ts} +26 -14
- package/src/index.ts +86 -0
- package/src/{merkle.js → merkle.ts} +8 -7
- package/src/{networks.js → networks.ts} +44 -29
- package/src/ops.ts +282 -0
- package/src/payments/bip341.ts +140 -0
- package/src/payments/embed.ts +55 -0
- package/src/payments/{index.d.ts → index.ts} +20 -10
- package/src/payments/lazy.ts +28 -0
- package/src/payments/p2ms.ts +150 -0
- package/src/payments/{p2pk.js → p2pk.ts} +32 -29
- package/src/payments/{p2pkh.js → p2pkh.ts} +53 -47
- package/src/payments/{p2sh.js → p2sh.ts} +72 -71
- package/src/payments/{p2tr.js → p2tr.ts} +114 -125
- package/src/payments/{p2wpkh.js → p2wpkh.ts} +51 -56
- package/src/payments/{p2wsh.js → p2wsh.ts} +69 -81
- package/src/psbt/{bip371.js → bip371.ts} +191 -174
- package/src/psbt/psbtutils.ts +299 -0
- package/src/{psbt.js → psbt.ts} +1025 -679
- package/src/{push_data.js → push_data.ts} +35 -21
- package/src/{script.js → script.ts} +93 -77
- package/src/{script_number.js → script_number.ts} +15 -21
- package/src/{script_signature.js → script_signature.ts} +26 -14
- package/src/{transaction.js → transaction.ts} +247 -167
- package/src/types.ts +122 -0
- package/test/address.spec.js +124 -0
- package/test/address.spec.ts +177 -0
- package/test/bitcoin.core.spec.js +170 -0
- package/test/bitcoin.core.spec.ts +234 -0
- package/test/block.spec.js +141 -0
- package/test/block.spec.ts +194 -0
- package/test/bufferutils.spec.js +427 -0
- package/test/bufferutils.spec.ts +513 -0
- package/test/crypto.spec.js +41 -0
- package/test/crypto.spec.ts +55 -0
- package/test/fixtures/address.json +329 -0
- package/test/fixtures/block.json +148 -0
- package/test/fixtures/bufferutils.json +102 -0
- package/test/fixtures/core/README.md +26 -0
- package/test/fixtures/core/base58_encode_decode.json +50 -0
- package/test/fixtures/core/base58_keys_invalid.json +152 -0
- package/test/fixtures/core/base58_keys_valid.json +452 -0
- package/test/fixtures/core/blocks.json +27 -0
- package/test/fixtures/core/sig_canonical.json +7 -0
- package/test/fixtures/core/sig_noncanonical.json +33 -0
- package/test/fixtures/core/sighash.json +3505 -0
- package/test/fixtures/core/tx_valid.json +2023 -0
- package/test/fixtures/crypto.json +43 -0
- package/test/fixtures/ecdsa.json +217 -0
- package/test/fixtures/ecpair.json +141 -0
- package/test/fixtures/embed.json +108 -0
- package/test/fixtures/p2ms.json +434 -0
- package/test/fixtures/p2pk.json +179 -0
- package/test/fixtures/p2pkh.json +276 -0
- package/test/fixtures/p2sh.json +508 -0
- package/test/fixtures/p2tr.json +1198 -0
- package/test/fixtures/p2wpkh.json +290 -0
- package/test/fixtures/p2wsh.json +489 -0
- package/test/fixtures/psbt.json +924 -0
- package/test/fixtures/script.json +465 -0
- package/test/fixtures/script_number.json +225 -0
- package/test/fixtures/signature.json +140 -0
- package/test/fixtures/transaction.json +916 -0
- package/test/integration/_regtest.js +7 -0
- package/test/integration/_regtest.ts +6 -0
- package/test/integration/addresses.spec.js +116 -0
- package/test/integration/addresses.spec.ts +154 -0
- package/test/integration/bip32.spec.js +85 -0
- package/test/integration/bip32.spec.ts +151 -0
- package/test/integration/blocks.spec.js +26 -0
- package/test/integration/blocks.spec.ts +28 -0
- package/test/integration/cltv.spec.js +199 -0
- package/test/integration/cltv.spec.ts +283 -0
- package/test/integration/csv.spec.js +362 -0
- package/test/integration/csv.spec.ts +527 -0
- package/test/integration/payments.spec.js +98 -0
- package/test/integration/payments.spec.ts +135 -0
- package/test/integration/taproot.spec.js +532 -0
- package/test/integration/taproot.spec.ts +707 -0
- package/test/integration/transactions.spec.js +561 -0
- package/test/integration/transactions.spec.ts +769 -0
- package/test/payments.spec.js +97 -0
- package/test/payments.spec.ts +125 -0
- package/test/payments.utils.js +190 -0
- package/test/payments.utils.ts +208 -0
- package/test/psbt.spec.js +1044 -0
- package/test/psbt.spec.ts +1414 -0
- package/test/script.spec.js +151 -0
- package/test/script.spec.ts +210 -0
- package/test/script_number.spec.js +24 -0
- package/test/script_number.spec.ts +29 -0
- package/test/script_signature.spec.js +52 -0
- package/test/script_signature.spec.ts +66 -0
- package/test/transaction.spec.js +269 -0
- package/test/transaction.spec.ts +387 -0
- package/test/ts-node-register.js +5 -0
- package/test/tsconfig.json +45 -0
- package/test/types.spec.js +46 -0
- package/test/types.spec.ts +58 -0
- package/tsconfig.base.json +27 -0
- package/tsconfig.json +19 -0
- package/tsconfig.webpack.json +18 -0
- package/webpack.config.js +79 -0
- package/src/address.d.ts +0 -42
- package/src/crypto.js +0 -128
- package/src/ecc_lib.d.ts +0 -17
- package/src/hooks/AdvancedSignatureManager.d.ts +0 -44
- package/src/hooks/HookedSigner.js +0 -90
- package/src/hooks/SignatureManager.d.ts +0 -35
- package/src/index.d.ts +0 -42
- package/src/index.js +0 -87
- package/src/merkle.d.ts +0 -10
- package/src/networks.d.ts +0 -83
- package/src/payments/bip341.d.ts +0 -49
- package/src/payments/bip341.js +0 -124
- package/src/payments/embed.d.ts +0 -9
- package/src/payments/embed.js +0 -54
- package/src/payments/index.js +0 -69
- package/src/payments/p2ms.d.ts +0 -9
- package/src/payments/p2pk.d.ts +0 -10
- package/src/payments/p2pkh.d.ts +0 -10
- package/src/payments/p2sh.d.ts +0 -10
- package/src/payments/p2tr.d.ts +0 -10
- package/src/payments/p2wpkh.d.ts +0 -10
- package/src/payments/p2wsh.d.ts +0 -10
- package/src/psbt/bip371.d.ts +0 -42
- package/src/psbt/psbtutils.d.ts +0 -64
- package/src/psbt/psbtutils.js +0 -191
- package/src/push_data.d.ts +0 -29
- package/src/script.d.ts +0 -42
- package/src/script_number.d.ts +0 -19
- package/src/script_signature.d.ts +0 -21
- package/src/types.js +0 -106
package/src/types.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Buffer as NBuffer } from 'buffer';
|
|
2
|
+
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import * as _typeforce from 'typeforce';
|
|
5
|
+
|
|
6
|
+
export const typeforce = _typeforce.default;
|
|
7
|
+
|
|
8
|
+
const ZERO32 = NBuffer.alloc(32, 0);
|
|
9
|
+
const EC_P = NBuffer.from(
|
|
10
|
+
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
|
|
11
|
+
'hex',
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Checks if two arrays of Buffers are equal.
|
|
16
|
+
* @param a - The first array of Buffers.
|
|
17
|
+
* @param b - The second array of Buffers.
|
|
18
|
+
* @returns True if the arrays are equal, false otherwise.
|
|
19
|
+
*/
|
|
20
|
+
export function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
|
|
21
|
+
if (a.length !== b.length) return false;
|
|
22
|
+
|
|
23
|
+
return a.every((x, i) => {
|
|
24
|
+
return x.equals(b[i]);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Checks if the given value is a valid elliptic curve point.
|
|
30
|
+
* @param p - The value to check.
|
|
31
|
+
* @returns True if the value is a valid elliptic curve point, false otherwise.
|
|
32
|
+
*/
|
|
33
|
+
export function isPoint(p: Buffer | number | undefined | null): boolean {
|
|
34
|
+
if (!NBuffer.isBuffer(p)) return false;
|
|
35
|
+
if (p.length < 33) return false;
|
|
36
|
+
|
|
37
|
+
const t = p[0]; // First byte = point format indicator
|
|
38
|
+
const x = p.slice(1, 33); // Next 32 bytes = X coordinate
|
|
39
|
+
|
|
40
|
+
// Validate X coordinate
|
|
41
|
+
if (x.compare(ZERO32) === 0) return false; // X cannot be zero
|
|
42
|
+
if (x.compare(EC_P) >= 0) return false; // X must be < P
|
|
43
|
+
|
|
44
|
+
// Check for compressed format (0x02 or 0x03), must be exactly 33 bytes total
|
|
45
|
+
if ((t === 0x02 || t === 0x03) && p.length === 33) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// For uncompressed (0x04) or hybrid (0x06 or 0x07) formats, must be 65 bytes total
|
|
50
|
+
if (p.length !== 65) return false;
|
|
51
|
+
|
|
52
|
+
const y = p.slice(33); // Last 32 bytes = Y coordinate
|
|
53
|
+
|
|
54
|
+
// Validate Y coordinate
|
|
55
|
+
if (y.compare(ZERO32) === 0) return false; // Y cannot be zero
|
|
56
|
+
if (y.compare(EC_P) >= 0) return false; // Y must be < P
|
|
57
|
+
|
|
58
|
+
// 0x04 = uncompressed, 0x06/0x07 = hybrid (also 65 bytes, but with Y's parity bit set)
|
|
59
|
+
return t === 0x04 || t === 0x06 || t === 0x07;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const SATOSHI_MAX: number = 21 * 1e14;
|
|
63
|
+
|
|
64
|
+
export function Satoshi(value: number): boolean {
|
|
65
|
+
return typeforce.UInt53(value) && value <= SATOSHI_MAX;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface XOnlyPointAddTweakResult {
|
|
69
|
+
parity: 1 | 0;
|
|
70
|
+
xOnlyPubkey: Uint8Array;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface Tapleaf {
|
|
74
|
+
output: Buffer;
|
|
75
|
+
version?: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const TAPLEAF_VERSION_MASK = 0xfe;
|
|
79
|
+
|
|
80
|
+
export function isTapleaf(o: any): o is Tapleaf {
|
|
81
|
+
if (!o || !('output' in o)) return false;
|
|
82
|
+
if (!NBuffer.isBuffer(o.output)) return false;
|
|
83
|
+
if (o.version !== undefined) return (o.version & TAPLEAF_VERSION_MASK) === o.version;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Binary tree repsenting script path spends for a Taproot input.
|
|
89
|
+
* Each node is either a single Tapleaf, or a pair of Tapleaf | Taptree.
|
|
90
|
+
* The tree has no balancing requirements.
|
|
91
|
+
*/
|
|
92
|
+
export type Taptree = [Taptree | Tapleaf, Taptree | Tapleaf] | Tapleaf;
|
|
93
|
+
|
|
94
|
+
export function isTaptree(scriptTree: any): scriptTree is Taptree {
|
|
95
|
+
if (!Array(scriptTree)) return isTapleaf(scriptTree);
|
|
96
|
+
if (scriptTree.length !== 2) return false;
|
|
97
|
+
return scriptTree.every((t: any) => isTaptree(t));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface TinySecp256k1Interface {
|
|
101
|
+
isXOnlyPoint(p: Uint8Array): boolean;
|
|
102
|
+
|
|
103
|
+
xOnlyPointAddTweak(p: Uint8Array, tweak: Uint8Array): XOnlyPointAddTweakResult | null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const Buffer256bit = typeforce.BufferN(32);
|
|
107
|
+
export const Hash160bit = typeforce.BufferN(20);
|
|
108
|
+
export const Hash256bit = typeforce.BufferN(32);
|
|
109
|
+
export const Number = typeforce.Number;
|
|
110
|
+
export const Array = typeforce.Array;
|
|
111
|
+
export const Boolean = typeforce.Boolean;
|
|
112
|
+
export const String = typeforce.String;
|
|
113
|
+
export const Buffer = typeforce.Buffer;
|
|
114
|
+
export const Hex = typeforce.Hex;
|
|
115
|
+
export const maybe = typeforce.maybe;
|
|
116
|
+
export const tuple = typeforce.tuple;
|
|
117
|
+
export const UInt8 = typeforce.UInt8;
|
|
118
|
+
export const UInt32 = typeforce.UInt32;
|
|
119
|
+
export const Function = typeforce.Function;
|
|
120
|
+
export const BufferN = typeforce.BufferN;
|
|
121
|
+
export const Null = typeforce.Null;
|
|
122
|
+
export const oneOf = typeforce.oneOf;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const assert = require("assert");
|
|
4
|
+
const mocha_1 = require("mocha");
|
|
5
|
+
const ecc = require("tiny-secp256k1");
|
|
6
|
+
const baddress = require("../src/address");
|
|
7
|
+
const bscript = require("../src/script");
|
|
8
|
+
const fixtures = require("./fixtures/address.json");
|
|
9
|
+
const src_1 = require("../src");
|
|
10
|
+
const NETWORKS = Object.assign({
|
|
11
|
+
litecoin: {
|
|
12
|
+
messagePrefix: '\x19Litecoin Signed Message:\n',
|
|
13
|
+
bip32: {
|
|
14
|
+
public: 0x019da462,
|
|
15
|
+
private: 0x019d9cfe,
|
|
16
|
+
},
|
|
17
|
+
pubKeyHash: 0x30,
|
|
18
|
+
scriptHash: 0x32,
|
|
19
|
+
wif: 0xb0,
|
|
20
|
+
},
|
|
21
|
+
}, require('../src/networks'));
|
|
22
|
+
(0, mocha_1.describe)('address', () => {
|
|
23
|
+
(0, mocha_1.describe)('fromBase58Check', () => {
|
|
24
|
+
fixtures.standard.forEach(f => {
|
|
25
|
+
if (!f.base58check)
|
|
26
|
+
return;
|
|
27
|
+
(0, mocha_1.it)('decodes ' + f.base58check, () => {
|
|
28
|
+
const decode = baddress.fromBase58Check(f.base58check);
|
|
29
|
+
assert.strictEqual(decode.version, f.version);
|
|
30
|
+
assert.strictEqual(decode.hash.toString('hex'), f.hash);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
fixtures.invalid.fromBase58Check.forEach(f => {
|
|
34
|
+
(0, mocha_1.it)('throws on ' + f.exception, () => {
|
|
35
|
+
assert.throws(() => {
|
|
36
|
+
baddress.fromBase58Check(f.address);
|
|
37
|
+
}, new RegExp(f.address + ' ' + f.exception));
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
(0, mocha_1.describe)('fromBech32', () => {
|
|
42
|
+
fixtures.standard.forEach(f => {
|
|
43
|
+
if (!f.bech32)
|
|
44
|
+
return;
|
|
45
|
+
(0, mocha_1.it)('decodes ' + f.bech32, () => {
|
|
46
|
+
const actual = baddress.fromBech32(f.bech32);
|
|
47
|
+
assert.strictEqual(actual.version, f.version);
|
|
48
|
+
assert.strictEqual(actual.prefix, NETWORKS[f.network].bech32);
|
|
49
|
+
assert.strictEqual(actual.data.toString('hex'), f.data);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
fixtures.invalid.bech32.forEach(f => {
|
|
53
|
+
(0, mocha_1.it)('decode fails for ' + f.address + '(' + f.exception + ')', () => {
|
|
54
|
+
assert.throws(() => {
|
|
55
|
+
baddress.fromBech32(f.address);
|
|
56
|
+
}, new RegExp(f.exception));
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
(0, mocha_1.describe)('fromOutputScript', () => {
|
|
61
|
+
(0, src_1.initEccLib)(ecc);
|
|
62
|
+
fixtures.standard.forEach(f => {
|
|
63
|
+
(0, mocha_1.it)('encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => {
|
|
64
|
+
const script = bscript.fromASM(f.script);
|
|
65
|
+
const address = baddress.fromOutputScript(script, NETWORKS[f.network]);
|
|
66
|
+
assert.strictEqual(address, f.base58check || f.bech32.toLowerCase());
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
fixtures.invalid.fromOutputScript.forEach(f => {
|
|
70
|
+
(0, mocha_1.it)('throws when ' + f.script.slice(0, 30) + '... ' + f.exception, () => {
|
|
71
|
+
const script = bscript.fromASM(f.script);
|
|
72
|
+
assert.throws(() => {
|
|
73
|
+
baddress.fromOutputScript(script, undefined);
|
|
74
|
+
}, new RegExp(f.exception));
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
(0, mocha_1.describe)('toBase58Check', () => {
|
|
79
|
+
fixtures.standard.forEach(f => {
|
|
80
|
+
if (!f.base58check)
|
|
81
|
+
return;
|
|
82
|
+
(0, mocha_1.it)('encodes ' + f.hash + ' (' + f.network + ')', () => {
|
|
83
|
+
const address = baddress.toBase58Check(Buffer.from(f.hash, 'hex'), f.version);
|
|
84
|
+
assert.strictEqual(address, f.base58check);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
(0, mocha_1.describe)('toBech32', () => {
|
|
89
|
+
fixtures.bech32.forEach(f => {
|
|
90
|
+
if (!f.address)
|
|
91
|
+
return;
|
|
92
|
+
const data = Buffer.from(f.data, 'hex');
|
|
93
|
+
(0, mocha_1.it)('encode ' + f.address, () => {
|
|
94
|
+
assert.deepStrictEqual(baddress.toBech32(data, f.version, f.prefix), f.address.toLowerCase());
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
// TODO: These fixtures (according to TypeScript) have none of the data used below
|
|
98
|
+
fixtures.invalid.bech32.forEach((f) => {
|
|
99
|
+
if (!f.prefix || f.version === undefined || f.data === undefined)
|
|
100
|
+
return;
|
|
101
|
+
(0, mocha_1.it)('encode fails (' + f.exception, () => {
|
|
102
|
+
assert.throws(() => {
|
|
103
|
+
baddress.toBech32(Buffer.from(f.data, 'hex'), f.version, f.prefix);
|
|
104
|
+
}, new RegExp(f.exception));
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
(0, mocha_1.describe)('toOutputScript', () => {
|
|
109
|
+
fixtures.standard.forEach(f => {
|
|
110
|
+
(0, mocha_1.it)('decodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => {
|
|
111
|
+
const script = baddress.toOutputScript((f.base58check || f.bech32), NETWORKS[f.network]);
|
|
112
|
+
assert.strictEqual(bscript.toASM(script), f.script);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
fixtures.invalid.toOutputScript.forEach(f => {
|
|
116
|
+
(0, mocha_1.it)('throws when ' + (f.exception || f.paymentException), () => {
|
|
117
|
+
const exception = f.paymentException || `${f.address} ${f.exception}`;
|
|
118
|
+
assert.throws(() => {
|
|
119
|
+
baddress.toOutputScript(f.address, f.network);
|
|
120
|
+
}, new RegExp(exception));
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import * as assert from 'assert';
|
|
2
|
+
import { describe, it } from 'mocha';
|
|
3
|
+
import * as ecc from 'tiny-secp256k1';
|
|
4
|
+
import * as baddress from '../src/address';
|
|
5
|
+
import * as bscript from '../src/script';
|
|
6
|
+
import * as fixtures from './fixtures/address.json';
|
|
7
|
+
|
|
8
|
+
import { initEccLib } from '../src';
|
|
9
|
+
|
|
10
|
+
const NETWORKS = Object.assign(
|
|
11
|
+
{
|
|
12
|
+
litecoin: {
|
|
13
|
+
messagePrefix: '\x19Litecoin Signed Message:\n',
|
|
14
|
+
bip32: {
|
|
15
|
+
public: 0x019da462,
|
|
16
|
+
private: 0x019d9cfe,
|
|
17
|
+
},
|
|
18
|
+
pubKeyHash: 0x30,
|
|
19
|
+
scriptHash: 0x32,
|
|
20
|
+
wif: 0xb0,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
require('../src/networks'),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
describe('address', () => {
|
|
27
|
+
describe('fromBase58Check', () => {
|
|
28
|
+
fixtures.standard.forEach(f => {
|
|
29
|
+
if (!f.base58check) return;
|
|
30
|
+
|
|
31
|
+
it('decodes ' + f.base58check, () => {
|
|
32
|
+
const decode = baddress.fromBase58Check(f.base58check);
|
|
33
|
+
|
|
34
|
+
assert.strictEqual(decode.version, f.version);
|
|
35
|
+
assert.strictEqual(decode.hash.toString('hex'), f.hash);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
fixtures.invalid.fromBase58Check.forEach(f => {
|
|
40
|
+
it('throws on ' + f.exception, () => {
|
|
41
|
+
assert.throws(() => {
|
|
42
|
+
baddress.fromBase58Check(f.address);
|
|
43
|
+
}, new RegExp(f.address + ' ' + f.exception));
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('fromBech32', () => {
|
|
49
|
+
fixtures.standard.forEach(f => {
|
|
50
|
+
if (!f.bech32) return;
|
|
51
|
+
|
|
52
|
+
it('decodes ' + f.bech32, () => {
|
|
53
|
+
const actual = baddress.fromBech32(f.bech32);
|
|
54
|
+
|
|
55
|
+
assert.strictEqual(actual.version, f.version);
|
|
56
|
+
assert.strictEqual(actual.prefix, NETWORKS[f.network].bech32);
|
|
57
|
+
assert.strictEqual(actual.data.toString('hex'), f.data);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
fixtures.invalid.bech32.forEach(f => {
|
|
62
|
+
it(
|
|
63
|
+
'decode fails for ' + f.address + '(' + f.exception + ')',
|
|
64
|
+
() => {
|
|
65
|
+
assert.throws(() => {
|
|
66
|
+
baddress.fromBech32(f.address);
|
|
67
|
+
}, new RegExp(f.exception));
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('fromOutputScript', () => {
|
|
74
|
+
initEccLib(ecc);
|
|
75
|
+
fixtures.standard.forEach(f => {
|
|
76
|
+
it(
|
|
77
|
+
'encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')',
|
|
78
|
+
() => {
|
|
79
|
+
const script = bscript.fromASM(f.script);
|
|
80
|
+
const address = baddress.fromOutputScript(
|
|
81
|
+
script,
|
|
82
|
+
NETWORKS[f.network],
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
assert.strictEqual(
|
|
86
|
+
address,
|
|
87
|
+
f.base58check || f.bech32!.toLowerCase(),
|
|
88
|
+
);
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
fixtures.invalid.fromOutputScript.forEach(f => {
|
|
94
|
+
it(
|
|
95
|
+
'throws when ' + f.script.slice(0, 30) + '... ' + f.exception,
|
|
96
|
+
() => {
|
|
97
|
+
const script = bscript.fromASM(f.script);
|
|
98
|
+
|
|
99
|
+
assert.throws(() => {
|
|
100
|
+
baddress.fromOutputScript(script, undefined);
|
|
101
|
+
}, new RegExp(f.exception));
|
|
102
|
+
},
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('toBase58Check', () => {
|
|
108
|
+
fixtures.standard.forEach(f => {
|
|
109
|
+
if (!f.base58check) return;
|
|
110
|
+
|
|
111
|
+
it('encodes ' + f.hash + ' (' + f.network + ')', () => {
|
|
112
|
+
const address = baddress.toBase58Check(
|
|
113
|
+
Buffer.from(f.hash, 'hex'),
|
|
114
|
+
f.version,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
assert.strictEqual(address, f.base58check);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('toBech32', () => {
|
|
123
|
+
fixtures.bech32.forEach(f => {
|
|
124
|
+
if (!f.address) return;
|
|
125
|
+
const data = Buffer.from(f.data, 'hex');
|
|
126
|
+
|
|
127
|
+
it('encode ' + f.address, () => {
|
|
128
|
+
assert.deepStrictEqual(
|
|
129
|
+
baddress.toBech32(data, f.version, f.prefix),
|
|
130
|
+
f.address.toLowerCase(),
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// TODO: These fixtures (according to TypeScript) have none of the data used below
|
|
136
|
+
fixtures.invalid.bech32.forEach((f: any) => {
|
|
137
|
+
if (!f.prefix || f.version === undefined || f.data === undefined)
|
|
138
|
+
return;
|
|
139
|
+
|
|
140
|
+
it('encode fails (' + f.exception, () => {
|
|
141
|
+
assert.throws(() => {
|
|
142
|
+
baddress.toBech32(
|
|
143
|
+
Buffer.from(f.data, 'hex'),
|
|
144
|
+
f.version,
|
|
145
|
+
f.prefix,
|
|
146
|
+
);
|
|
147
|
+
}, new RegExp(f.exception));
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe('toOutputScript', () => {
|
|
153
|
+
fixtures.standard.forEach(f => {
|
|
154
|
+
it(
|
|
155
|
+
'decodes ' + f.script.slice(0, 30) + '... (' + f.network + ')',
|
|
156
|
+
() => {
|
|
157
|
+
const script = baddress.toOutputScript(
|
|
158
|
+
(f.base58check || f.bech32)!,
|
|
159
|
+
NETWORKS[f.network],
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
assert.strictEqual(bscript.toASM(script), f.script);
|
|
163
|
+
},
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
fixtures.invalid.toOutputScript.forEach(f => {
|
|
168
|
+
it('throws when ' + (f.exception || f.paymentException), () => {
|
|
169
|
+
const exception =
|
|
170
|
+
f.paymentException || `${f.address} ${f.exception}`;
|
|
171
|
+
assert.throws(() => {
|
|
172
|
+
baddress.toOutputScript(f.address, f.network as any);
|
|
173
|
+
}, new RegExp(exception));
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const assert = require("assert");
|
|
4
|
+
const base58 = require("bs58");
|
|
5
|
+
const mocha_1 = require("mocha");
|
|
6
|
+
const bitcoin = require("..");
|
|
7
|
+
const base58EncodeDecode = require("./fixtures/core/base58_encode_decode.json");
|
|
8
|
+
const base58KeysInvalid = require("./fixtures/core/base58_keys_invalid.json");
|
|
9
|
+
const base58KeysValid = require("./fixtures/core/base58_keys_valid.json");
|
|
10
|
+
const blocksValid = require("./fixtures/core/blocks.json");
|
|
11
|
+
const sigCanonical = require("./fixtures/core/sig_canonical.json");
|
|
12
|
+
const sigNoncanonical = require("./fixtures/core/sig_noncanonical.json");
|
|
13
|
+
const sigHash = require("./fixtures/core/sighash.json");
|
|
14
|
+
const txValid = require("./fixtures/core/tx_valid.json");
|
|
15
|
+
(0, mocha_1.describe)('Bitcoin-core', () => {
|
|
16
|
+
// base58EncodeDecode
|
|
17
|
+
(0, mocha_1.describe)('base58', () => {
|
|
18
|
+
base58EncodeDecode.forEach(f => {
|
|
19
|
+
const fhex = f[0];
|
|
20
|
+
const fb58 = f[1];
|
|
21
|
+
(0, mocha_1.it)('can decode ' + fb58, () => {
|
|
22
|
+
const buffer = base58.decode(fb58);
|
|
23
|
+
const actual = buffer.toString('hex');
|
|
24
|
+
assert.strictEqual(actual, fhex);
|
|
25
|
+
});
|
|
26
|
+
(0, mocha_1.it)('can encode ' + fhex, () => {
|
|
27
|
+
const buffer = Buffer.from(fhex, 'hex');
|
|
28
|
+
const actual = base58.encode(buffer);
|
|
29
|
+
assert.strictEqual(actual, fb58);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
// base58KeysValid
|
|
34
|
+
(0, mocha_1.describe)('address.toBase58Check', () => {
|
|
35
|
+
const typeMap = {
|
|
36
|
+
pubkey: 'pubKeyHash',
|
|
37
|
+
script: 'scriptHash',
|
|
38
|
+
};
|
|
39
|
+
base58KeysValid.forEach(f => {
|
|
40
|
+
const expected = f[0];
|
|
41
|
+
const hash = Buffer.from(f[1], 'hex');
|
|
42
|
+
const params = f[2];
|
|
43
|
+
if (params.isPrivkey)
|
|
44
|
+
return;
|
|
45
|
+
const network = params.isTestnet
|
|
46
|
+
? bitcoin.networks.testnet
|
|
47
|
+
: bitcoin.networks.bitcoin;
|
|
48
|
+
const version = network[typeMap[params.addrType]];
|
|
49
|
+
(0, mocha_1.it)('can export ' + expected, () => {
|
|
50
|
+
assert.strictEqual(bitcoin.address.toBase58Check(hash, version), expected);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
// base58KeysInvalid
|
|
55
|
+
(0, mocha_1.describe)('address.fromBase58Check', () => {
|
|
56
|
+
const allowedNetworks = [
|
|
57
|
+
bitcoin.networks.bitcoin.pubKeyHash,
|
|
58
|
+
bitcoin.networks.bitcoin.scriptHash,
|
|
59
|
+
bitcoin.networks.testnet.pubKeyHash,
|
|
60
|
+
bitcoin.networks.testnet.scriptHash,
|
|
61
|
+
];
|
|
62
|
+
base58KeysInvalid.forEach(f => {
|
|
63
|
+
const strng = f[0];
|
|
64
|
+
(0, mocha_1.it)('throws on ' + strng, () => {
|
|
65
|
+
assert.throws(() => {
|
|
66
|
+
const address = bitcoin.address.fromBase58Check(strng);
|
|
67
|
+
assert.notStrictEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network');
|
|
68
|
+
}, /(Invalid (checksum|network))|(too (short|long))/);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
(0, mocha_1.describe)('Block.fromHex', () => {
|
|
73
|
+
blocksValid.forEach(f => {
|
|
74
|
+
(0, mocha_1.it)('can parse ' + f.id, () => {
|
|
75
|
+
const block = bitcoin.Block.fromHex(f.hex);
|
|
76
|
+
assert.strictEqual(block.getId(), f.id);
|
|
77
|
+
assert.strictEqual(block.transactions.length, f.transactions);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
// txValid
|
|
82
|
+
(0, mocha_1.describe)('Transaction.fromHex', () => {
|
|
83
|
+
txValid.forEach(f => {
|
|
84
|
+
// Objects that are only a single string are ignored
|
|
85
|
+
if (f.length === 1)
|
|
86
|
+
return;
|
|
87
|
+
const inputs = f[0];
|
|
88
|
+
const fhex = f[1];
|
|
89
|
+
// const verifyFlags = f[2] // TODO: do we need to test this?
|
|
90
|
+
(0, mocha_1.it)('can decode ' + fhex, () => {
|
|
91
|
+
const transaction = bitcoin.Transaction.fromHex(fhex);
|
|
92
|
+
transaction.ins.forEach((txIn, i) => {
|
|
93
|
+
const input = inputs[i];
|
|
94
|
+
// reverse because test data is reversed
|
|
95
|
+
const prevOutHash = Buffer.from(input[0], 'hex').reverse();
|
|
96
|
+
const prevOutIndex = input[1];
|
|
97
|
+
assert.deepStrictEqual(txIn.hash, prevOutHash);
|
|
98
|
+
// we read UInt32, not Int32
|
|
99
|
+
assert.strictEqual(txIn.index & 0xffffffff, prevOutIndex);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
// sighash
|
|
105
|
+
(0, mocha_1.describe)('Transaction', () => {
|
|
106
|
+
sigHash.forEach(f => {
|
|
107
|
+
// Objects that are only a single string are ignored
|
|
108
|
+
if (f.length === 1)
|
|
109
|
+
return;
|
|
110
|
+
const txHex = f[0];
|
|
111
|
+
const scriptHex = f[1];
|
|
112
|
+
const inIndex = f[2];
|
|
113
|
+
const hashType = f[3];
|
|
114
|
+
const expectedHash = f[4];
|
|
115
|
+
const hashTypes = [];
|
|
116
|
+
if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_NONE)
|
|
117
|
+
hashTypes.push('SIGHASH_NONE');
|
|
118
|
+
else if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_SINGLE)
|
|
119
|
+
hashTypes.push('SIGHASH_SINGLE');
|
|
120
|
+
else
|
|
121
|
+
hashTypes.push('SIGHASH_ALL');
|
|
122
|
+
if (hashType & bitcoin.Transaction.SIGHASH_ANYONECANPAY)
|
|
123
|
+
hashTypes.push('SIGHASH_ANYONECANPAY');
|
|
124
|
+
const hashTypeName = hashTypes.join(' | ');
|
|
125
|
+
(0, mocha_1.it)('should hash ' +
|
|
126
|
+
txHex.slice(0, 40) +
|
|
127
|
+
'... (' +
|
|
128
|
+
hashTypeName +
|
|
129
|
+
')', () => {
|
|
130
|
+
const transaction = bitcoin.Transaction.fromHex(txHex);
|
|
131
|
+
assert.strictEqual(transaction.toHex(), txHex);
|
|
132
|
+
const script = Buffer.from(scriptHex, 'hex');
|
|
133
|
+
const scriptChunks = bitcoin.script.decompile(script);
|
|
134
|
+
assert.strictEqual(bitcoin.script.compile(scriptChunks).toString('hex'), scriptHex);
|
|
135
|
+
const hash = transaction.hashForSignature(inIndex, script, hashType);
|
|
136
|
+
// reverse because test data is reversed
|
|
137
|
+
assert.strictEqual(hash.reverse().toString('hex'), expectedHash);
|
|
138
|
+
assert.doesNotThrow(() => transaction.hashForWitnessV0(inIndex, script, 0,
|
|
139
|
+
// convert to UInt32
|
|
140
|
+
hashType < 0 ? 0x100000000 + hashType : hashType));
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
(0, mocha_1.describe)('script.signature.decode', () => {
|
|
145
|
+
sigCanonical.forEach(hex => {
|
|
146
|
+
const buffer = Buffer.from(hex, 'hex');
|
|
147
|
+
(0, mocha_1.it)('can parse ' + hex, () => {
|
|
148
|
+
const parsed = bitcoin.script.signature.decode(buffer);
|
|
149
|
+
const actual = bitcoin.script.signature.encode(parsed.signature, parsed.hashType);
|
|
150
|
+
assert.strictEqual(actual.toString('hex'), hex);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
sigNoncanonical.forEach((hex, i) => {
|
|
154
|
+
if (i === 0)
|
|
155
|
+
return;
|
|
156
|
+
if (i % 2 !== 0)
|
|
157
|
+
return;
|
|
158
|
+
const description = sigNoncanonical[i - 1].slice(0, -1);
|
|
159
|
+
const buffer = Buffer.from(hex, 'hex');
|
|
160
|
+
(0, mocha_1.it)('throws on ' + description, () => {
|
|
161
|
+
const reg = new RegExp('Expected DER (integer|sequence)|(R|S) value (excessively ' +
|
|
162
|
+
'padded|is negative)|(R|S|DER sequence) length is (zero|too ' +
|
|
163
|
+
'short|too long|invalid)|Invalid hashType');
|
|
164
|
+
assert.throws(() => {
|
|
165
|
+
bitcoin.script.signature.decode(buffer);
|
|
166
|
+
}, reg);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|