@bsv/sdk 1.5.3 → 1.6.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.
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/primitives/AESGCM.js +113 -137
- package/dist/cjs/src/primitives/AESGCM.js.map +1 -1
- package/dist/cjs/src/primitives/BigNumber.js +1019 -3947
- package/dist/cjs/src/primitives/BigNumber.js.map +1 -1
- package/dist/cjs/src/primitives/K256.js +53 -37
- package/dist/cjs/src/primitives/K256.js.map +1 -1
- package/dist/cjs/src/primitives/Mersenne.js +16 -21
- package/dist/cjs/src/primitives/Mersenne.js.map +1 -1
- package/dist/cjs/src/primitives/MontgomoryMethod.js.map +1 -1
- package/dist/cjs/src/primitives/utils.js +27 -17
- package/dist/cjs/src/primitives/utils.js.map +1 -1
- package/dist/cjs/src/script/Spend.js +618 -858
- package/dist/cjs/src/script/Spend.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/primitives/AESGCM.js +112 -137
- package/dist/esm/src/primitives/AESGCM.js.map +1 -1
- package/dist/esm/src/primitives/BigNumber.js +1011 -3969
- package/dist/esm/src/primitives/BigNumber.js.map +1 -1
- package/dist/esm/src/primitives/K256.js +53 -37
- package/dist/esm/src/primitives/K256.js.map +1 -1
- package/dist/esm/src/primitives/Mersenne.js +16 -21
- package/dist/esm/src/primitives/Mersenne.js.map +1 -1
- package/dist/esm/src/primitives/MontgomoryMethod.js.map +1 -1
- package/dist/esm/src/primitives/utils.js +29 -17
- package/dist/esm/src/primitives/utils.js.map +1 -1
- package/dist/esm/src/script/Spend.js +618 -857
- package/dist/esm/src/script/Spend.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/primitives/AESGCM.d.ts.map +1 -1
- package/dist/types/src/primitives/BigNumber.d.ts +238 -1705
- package/dist/types/src/primitives/BigNumber.d.ts.map +1 -1
- package/dist/types/src/primitives/K256.d.ts.map +1 -1
- package/dist/types/src/primitives/Mersenne.d.ts +2 -2
- package/dist/types/src/primitives/Mersenne.d.ts.map +1 -1
- package/dist/types/src/primitives/utils.d.ts +2 -0
- package/dist/types/src/primitives/utils.d.ts.map +1 -1
- package/dist/types/src/script/Spend.d.ts +11 -1
- package/dist/types/src/script/Spend.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/performance.md +70 -0
- package/docs/primitives.md +262 -3049
- package/package.json +1 -1
- package/src/auth/__tests/Peer.test.ts +38 -23
- package/src/auth/certificates/__tests/MasterCertificate.test.ts +27 -20
- package/src/auth/certificates/__tests/VerifiableCertificate.test.ts +24 -24
- package/src/primitives/AESGCM.ts +118 -164
- package/src/primitives/BigNumber.ts +867 -4180
- package/src/primitives/K256.ts +57 -37
- package/src/primitives/Mersenne.ts +16 -20
- package/src/primitives/MontgomoryMethod.ts +2 -2
- package/src/primitives/__tests/ReductionContext.test.ts +6 -1
- package/src/primitives/utils.ts +28 -17
- package/src/script/Spend.ts +634 -1309
- package/src/transaction/__tests/Transaction.test.ts +14 -16
- package/src/transaction/__tests/Transaction.benchmarks.test.ts +0 -237
|
@@ -26,6 +26,9 @@ const BRC62Hex =
|
|
|
26
26
|
const MerkleRootFromBEEF =
|
|
27
27
|
'bb6f640cc4ee56bf38eb5a1969ac0c16caa2d3d202b22bf3735d10eec0ca6e00'
|
|
28
28
|
|
|
29
|
+
const testPrivateKey = new PrivateKey(11)
|
|
30
|
+
const testP2PKHScript = new P2PKH().lock(testPrivateKey.toPublicKey().toHash())
|
|
31
|
+
|
|
29
32
|
describe('Transaction', () => {
|
|
30
33
|
const txhex =
|
|
31
34
|
'000000000100000000000000000000000000000000000000000000000000000000000000000000000001ae0000000001050000000000000001ae00000000'
|
|
@@ -713,19 +716,18 @@ describe('Transaction', () => {
|
|
|
713
716
|
value: 10000
|
|
714
717
|
}
|
|
715
718
|
]
|
|
716
|
-
const priv = PrivateKey.fromRandom()
|
|
717
719
|
const tx = new Transaction()
|
|
718
720
|
utxos.forEach(utxo => {
|
|
719
721
|
const u = {
|
|
720
722
|
txid: utxo.tx_hash,
|
|
721
723
|
vout: utxo.tx_pos,
|
|
722
|
-
script:
|
|
724
|
+
script: testP2PKHScript.toHex(),
|
|
723
725
|
satoshis: utxo.value
|
|
724
726
|
}
|
|
725
|
-
tx.addInput(fromUtxo(u, new P2PKH().unlock(
|
|
727
|
+
tx.addInput(fromUtxo(u, new P2PKH().unlock(testPrivateKey)))
|
|
726
728
|
})
|
|
727
729
|
tx.addOutput({
|
|
728
|
-
lockingScript:
|
|
730
|
+
lockingScript: testP2PKHScript,
|
|
729
731
|
change: true
|
|
730
732
|
})
|
|
731
733
|
await tx.fee({ computeFee: async () => 10 })
|
|
@@ -1138,26 +1140,24 @@ describe('Transaction', () => {
|
|
|
1138
1140
|
|
|
1139
1141
|
describe('addP2PKHOutput', () => {
|
|
1140
1142
|
it('should create an output on the current transaction using an address hash or string', async () => {
|
|
1141
|
-
const
|
|
1142
|
-
const pubKeyHash = privateKey.toPublicKey().toHash()
|
|
1143
|
-
const lockingScript = new P2PKH().lock(privateKey.toAddress())
|
|
1143
|
+
const pubKeyHash = testPrivateKey.toPublicKey().toHash()
|
|
1144
1144
|
const tx = new Transaction()
|
|
1145
1145
|
tx.addInput({
|
|
1146
1146
|
sourceTXID: '00'.repeat(32),
|
|
1147
1147
|
sourceOutputIndex: 0,
|
|
1148
|
-
unlockingScriptTemplate: new P2PKH().unlock(
|
|
1148
|
+
unlockingScriptTemplate: new P2PKH().unlock(testPrivateKey)
|
|
1149
1149
|
})
|
|
1150
|
-
tx.addP2PKHOutput(
|
|
1150
|
+
tx.addP2PKHOutput(testPrivateKey.toAddress(), 10000)
|
|
1151
1151
|
tx.addP2PKHOutput(pubKeyHash, 10000)
|
|
1152
1152
|
expect(tx.outputs.length).toEqual(2)
|
|
1153
1153
|
expect(tx.outputs[0].satoshis).toEqual(10000)
|
|
1154
1154
|
expect(tx.outputs[1].satoshis).toEqual(10000)
|
|
1155
1155
|
expect(
|
|
1156
|
-
tx.outputs[0].lockingScript.toHex() ===
|
|
1156
|
+
tx.outputs[0].lockingScript.toHex() === testP2PKHScript.toHex()
|
|
1157
1157
|
).toBeTruthy()
|
|
1158
1158
|
expect(
|
|
1159
1159
|
tx.outputs[0].lockingScript.toHex() === tx.outputs[1].lockingScript.toHex()
|
|
1160
|
-
).toBeTruthy()
|
|
1160
|
+
).toBeTruthy()
|
|
1161
1161
|
})
|
|
1162
1162
|
})
|
|
1163
1163
|
})
|
|
@@ -1290,13 +1290,11 @@ describe('Transaction', () => {
|
|
|
1290
1290
|
|
|
1291
1291
|
describe('addP2PKHOutput', () => {
|
|
1292
1292
|
it('should create an output on the current transaction using an address hash or string', async () => {
|
|
1293
|
-
const privateKey = PrivateKey.fromRandom()
|
|
1294
|
-
const lockingScript = new P2PKH().lock(privateKey.toAddress())
|
|
1295
1293
|
const tx = new Transaction()
|
|
1296
1294
|
tx.addInput({
|
|
1297
1295
|
sourceTXID: '00'.repeat(32),
|
|
1298
1296
|
sourceOutputIndex: 0,
|
|
1299
|
-
unlockingScriptTemplate: new P2PKH().unlock(
|
|
1297
|
+
unlockingScriptTemplate: new P2PKH().unlock(testPrivateKey),
|
|
1300
1298
|
})
|
|
1301
1299
|
})
|
|
1302
1300
|
})
|
|
@@ -1311,7 +1309,7 @@ describe('Transaction', () => {
|
|
|
1311
1309
|
})
|
|
1312
1310
|
sourceTransaction.addOutput({
|
|
1313
1311
|
satoshis: 2,
|
|
1314
|
-
lockingScript: Script.fromASM('OP_2 OP_MUL ' + 'OP_DUP OP_MUL '.repeat(
|
|
1312
|
+
lockingScript: Script.fromASM('OP_2 OP_MUL ' + 'OP_DUP OP_MUL '.repeat(22) + 'OP_DROP'),
|
|
1315
1313
|
})
|
|
1316
1314
|
await sourceTransaction.sign()
|
|
1317
1315
|
|
|
@@ -1336,7 +1334,7 @@ describe('Transaction', () => {
|
|
|
1336
1334
|
await tx.sign()
|
|
1337
1335
|
|
|
1338
1336
|
// default should be 100KB
|
|
1339
|
-
await expect(tx.verify('scripts only', new SatoshisPerKilobyte(1))).rejects.toThrow('Stack memory usage has exceeded
|
|
1337
|
+
await expect(tx.verify('scripts only', new SatoshisPerKilobyte(1))).rejects.toThrow('Stack memory usage has exceeded 32000000 bytes')
|
|
1340
1338
|
})
|
|
1341
1339
|
})
|
|
1342
1340
|
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
// __tests__/transaction.benchmark.test.ts
|
|
2
|
-
|
|
3
|
-
import Transaction from '../../transaction/Transaction'
|
|
4
|
-
import PrivateKey from '../../primitives/PrivateKey'
|
|
5
|
-
import P2PKH from '../../script/templates/P2PKH'
|
|
6
|
-
import { jest } from '@jest/globals'
|
|
7
|
-
import MerklePath from '../MerklePath'
|
|
8
|
-
|
|
9
|
-
jest.setTimeout(60000) // Increase timeout for benchmarking tests if necessary
|
|
10
|
-
|
|
11
|
-
// Helper function to measure execution time
|
|
12
|
-
async function measureTime(fn: () => Promise<void>): Promise<number> {
|
|
13
|
-
const start = process.hrtime()
|
|
14
|
-
await fn()
|
|
15
|
-
const diff = process.hrtime(start)
|
|
16
|
-
const timeInMs = diff[0] * 1000 + diff[1] / 1e6
|
|
17
|
-
return timeInMs
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe('Transaction Verification Benchmark', () => {
|
|
21
|
-
const privateKey = new PrivateKey(1)
|
|
22
|
-
const publicKey = privateKey.toPublicKey()
|
|
23
|
-
const publicKeyHash = publicKey.toHash()
|
|
24
|
-
const p2pkh = new P2PKH()
|
|
25
|
-
|
|
26
|
-
it('verifies a transaction with a deep input chain', async () => {
|
|
27
|
-
const depth = 100
|
|
28
|
-
let tx = new Transaction()
|
|
29
|
-
tx.addOutput({
|
|
30
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
31
|
-
satoshis: 100000
|
|
32
|
-
})
|
|
33
|
-
const blockHeight = 1631619
|
|
34
|
-
const txid = tx.hash('hex') as string
|
|
35
|
-
|
|
36
|
-
const path = [
|
|
37
|
-
[
|
|
38
|
-
{ offset: 0, hash: txid, txid: true, duplicate: false },
|
|
39
|
-
{ offset: 1, hash: 'otherHash1', txid: false, duplicate: false }
|
|
40
|
-
],
|
|
41
|
-
[{ offset: 1, hash: 'mergedHash1', txid: false, duplicate: false }]
|
|
42
|
-
]
|
|
43
|
-
|
|
44
|
-
const merklePath = new MerklePath(blockHeight, path)
|
|
45
|
-
|
|
46
|
-
// Assign the MerklePath to the transaction
|
|
47
|
-
tx.merklePath = merklePath
|
|
48
|
-
|
|
49
|
-
for (let i = 1; i < depth + 1; i++) {
|
|
50
|
-
const newTx = new Transaction()
|
|
51
|
-
newTx.addInput({
|
|
52
|
-
sourceTransaction: tx,
|
|
53
|
-
sourceOutputIndex: 0,
|
|
54
|
-
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
55
|
-
sequence: 0xffffffff
|
|
56
|
-
})
|
|
57
|
-
newTx.addOutput({
|
|
58
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
59
|
-
satoshis: 100000 - i * 10
|
|
60
|
-
})
|
|
61
|
-
await newTx.sign()
|
|
62
|
-
tx = newTx
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('verifies a transaction with a wide input set', async () => {
|
|
67
|
-
// Create a transaction with many inputs (e.g., 100 inputs)
|
|
68
|
-
const inputCount = 100
|
|
69
|
-
const sourceTxs: Transaction[] = []
|
|
70
|
-
|
|
71
|
-
// Create source transactions
|
|
72
|
-
for (let i = 0; i < inputCount; i++) {
|
|
73
|
-
const sourceTx = new Transaction()
|
|
74
|
-
sourceTx.addOutput({
|
|
75
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
76
|
-
satoshis: 1000
|
|
77
|
-
})
|
|
78
|
-
const blockHeight = 1631619
|
|
79
|
-
const txid = sourceTx.hash('hex') as string
|
|
80
|
-
const path = [
|
|
81
|
-
[
|
|
82
|
-
{ offset: 0, hash: txid, txid: true, duplicate: false },
|
|
83
|
-
{ offset: 1, hash: 'otherHash1', txid: false, duplicate: false }
|
|
84
|
-
],
|
|
85
|
-
[{ offset: 1, hash: 'mergedHash1', txid: false, duplicate: false }]
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
const merklePath = new MerklePath(blockHeight, path)
|
|
89
|
-
|
|
90
|
-
// Assign the MerklePath to the transaction
|
|
91
|
-
sourceTx.merklePath = merklePath
|
|
92
|
-
sourceTxs.push(sourceTx)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Create transaction with many inputs
|
|
96
|
-
const tx = new Transaction()
|
|
97
|
-
for (let i = 0; i < inputCount; i++) {
|
|
98
|
-
tx.addInput({
|
|
99
|
-
sourceTransaction: sourceTxs[i],
|
|
100
|
-
sourceOutputIndex: 0,
|
|
101
|
-
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
102
|
-
sequence: 0xffffffff
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
tx.addOutput({
|
|
106
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
107
|
-
satoshis: inputCount * 1000 - 1000
|
|
108
|
-
})
|
|
109
|
-
await tx.sign()
|
|
110
|
-
|
|
111
|
-
// Measure verification time
|
|
112
|
-
const timeTaken = await measureTime(async () => {
|
|
113
|
-
const verified = await tx.verify('scripts only')
|
|
114
|
-
expect(verified).toBe(true)
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
it('verifies a large transaction with many inputs and outputs', async () => {
|
|
119
|
-
const inputCount = 50
|
|
120
|
-
const outputCount = 50
|
|
121
|
-
const sourceTxs: Transaction[] = []
|
|
122
|
-
|
|
123
|
-
// Create source transactions
|
|
124
|
-
for (let i = 0; i < inputCount; i++) {
|
|
125
|
-
const sourceTx = new Transaction()
|
|
126
|
-
sourceTx.addOutput({
|
|
127
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
128
|
-
satoshis: 2000
|
|
129
|
-
})
|
|
130
|
-
const blockHeight = 1631619
|
|
131
|
-
const txid = sourceTx.hash('hex') as string
|
|
132
|
-
const path = [
|
|
133
|
-
[
|
|
134
|
-
{ offset: 0, hash: txid, txid: true, duplicate: false },
|
|
135
|
-
{ offset: 1, hash: 'otherHash1', txid: false, duplicate: false }
|
|
136
|
-
],
|
|
137
|
-
[{ offset: 1, hash: 'mergedHash1', txid: false, duplicate: false }]
|
|
138
|
-
]
|
|
139
|
-
|
|
140
|
-
const merklePath = new MerklePath(blockHeight, path)
|
|
141
|
-
|
|
142
|
-
// Assign the MerklePath to the transaction
|
|
143
|
-
sourceTx.merklePath = merklePath
|
|
144
|
-
sourceTxs.push(sourceTx)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Create transaction with many inputs and outputs
|
|
148
|
-
const tx = new Transaction()
|
|
149
|
-
for (let i = 0; i < inputCount; i++) {
|
|
150
|
-
tx.addInput({
|
|
151
|
-
sourceTransaction: sourceTxs[i],
|
|
152
|
-
sourceOutputIndex: 0,
|
|
153
|
-
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
154
|
-
sequence: 0xffffffff
|
|
155
|
-
})
|
|
156
|
-
}
|
|
157
|
-
for (let i = 0; i < outputCount; i++) {
|
|
158
|
-
tx.addOutput({
|
|
159
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
160
|
-
satoshis: 1000
|
|
161
|
-
})
|
|
162
|
-
}
|
|
163
|
-
await tx.sign()
|
|
164
|
-
|
|
165
|
-
// Measure verification time
|
|
166
|
-
const timeTaken = await measureTime(async () => {
|
|
167
|
-
const verified = await tx.verify('scripts only')
|
|
168
|
-
expect(verified).toBe(true)
|
|
169
|
-
})
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
it('verifies a transaction with nested inputs (complex graph)', async () => {
|
|
173
|
-
// Create a transaction graph where inputs come from transactions with multiple inputs
|
|
174
|
-
const depth = 5
|
|
175
|
-
const fanOut = 3
|
|
176
|
-
let txs: Transaction[] = []
|
|
177
|
-
|
|
178
|
-
// Create base transactions
|
|
179
|
-
for (let i = 0; i < fanOut; i++) {
|
|
180
|
-
const baseTx = new Transaction()
|
|
181
|
-
baseTx.addOutput({
|
|
182
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
183
|
-
satoshis: 100000
|
|
184
|
-
})
|
|
185
|
-
const blockHeight = 1631619
|
|
186
|
-
const txid = baseTx.hash('hex') as string
|
|
187
|
-
const path = [
|
|
188
|
-
[
|
|
189
|
-
{ offset: 0, hash: txid, txid: true, duplicate: false },
|
|
190
|
-
{ offset: 1, hash: 'otherHash1', txid: false, duplicate: false }
|
|
191
|
-
],
|
|
192
|
-
[{ offset: 1, hash: 'mergedHash1', txid: false, duplicate: false }]
|
|
193
|
-
]
|
|
194
|
-
|
|
195
|
-
const merklePath = new MerklePath(blockHeight, path)
|
|
196
|
-
|
|
197
|
-
// Assign the MerklePath to the transaction
|
|
198
|
-
baseTx.merklePath = merklePath
|
|
199
|
-
txs.push(baseTx)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Build the graph
|
|
203
|
-
for (let d = 0; d < depth; d++) {
|
|
204
|
-
const newTxs: Transaction[] = [] // Ensure newTxs is properly typed
|
|
205
|
-
for (const tx of txs) {
|
|
206
|
-
const newTx = new Transaction()
|
|
207
|
-
for (let i = 0; i < fanOut; i++) {
|
|
208
|
-
newTx.addInput({
|
|
209
|
-
sourceTransaction: tx,
|
|
210
|
-
sourceOutputIndex: 0,
|
|
211
|
-
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
212
|
-
sequence: 0xffffffff
|
|
213
|
-
})
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Ensure tx.outputs[0] exists before accessing satoshis
|
|
217
|
-
newTx.addOutput({
|
|
218
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
219
|
-
satoshis: (tx.outputs[0]?.satoshis ?? 0) - 1000 * fanOut
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
await newTx.sign()
|
|
223
|
-
newTxs.push(newTx)
|
|
224
|
-
}
|
|
225
|
-
txs = newTxs // Reassign txs with newly created transactions
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Take the last transaction for verification
|
|
229
|
-
const finalTx = txs[0]
|
|
230
|
-
|
|
231
|
-
// Measure verification time
|
|
232
|
-
const timeTaken = await measureTime(async () => {
|
|
233
|
-
const verified = await finalTx.verify('scripts only')
|
|
234
|
-
expect(verified).toBe(true)
|
|
235
|
-
})
|
|
236
|
-
})
|
|
237
|
-
})
|