@bsv/sdk 1.10.4 → 2.0.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/mod.js +1 -0
- package/dist/cjs/mod.js.map +1 -1
- package/dist/cjs/package.json +2 -3
- package/dist/cjs/src/auth/Peer.js +18 -20
- package/dist/cjs/src/auth/Peer.js.map +1 -1
- package/dist/cjs/src/identity/IdentityClient.js +20 -124
- package/dist/cjs/src/identity/IdentityClient.js.map +1 -1
- package/dist/cjs/src/primitives/TransactionSignature.js +115 -10
- package/dist/cjs/src/primitives/TransactionSignature.js.map +1 -1
- package/dist/cjs/src/primitives/utils.js +13 -112
- package/dist/cjs/src/primitives/utils.js.map +1 -1
- package/dist/cjs/src/remittance/CommsLayer.js +3 -0
- package/dist/cjs/src/remittance/CommsLayer.js.map +1 -0
- package/dist/cjs/src/remittance/IdentityLayer.js +3 -0
- package/dist/cjs/src/remittance/IdentityLayer.js.map +1 -0
- package/dist/cjs/src/remittance/RemittanceManager.js +1245 -0
- package/dist/cjs/src/remittance/RemittanceManager.js.map +1 -0
- package/dist/cjs/src/remittance/RemittanceModule.js +3 -0
- package/dist/cjs/src/remittance/RemittanceModule.js.map +1 -0
- package/dist/cjs/src/remittance/index.js +23 -0
- package/dist/cjs/src/remittance/index.js.map +1 -0
- package/dist/cjs/src/remittance/modules/BasicBRC29.js +225 -0
- package/dist/cjs/src/remittance/modules/BasicBRC29.js.map +1 -0
- package/dist/cjs/src/remittance/modules/index.js +18 -0
- package/dist/cjs/src/remittance/modules/index.js.map +1 -0
- package/dist/cjs/src/remittance/types.js +22 -0
- package/dist/cjs/src/remittance/types.js.map +1 -0
- package/dist/cjs/src/script/OP.js +15 -13
- package/dist/cjs/src/script/OP.js.map +1 -1
- package/dist/cjs/src/script/Script.js +4 -1
- package/dist/cjs/src/script/Script.js.map +1 -1
- package/dist/cjs/src/script/Spend.js +128 -46
- package/dist/cjs/src/script/Spend.js.map +1 -1
- package/dist/cjs/src/transaction/BeefTx.js +2 -2
- package/dist/cjs/src/transaction/Transaction.js +160 -0
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/mod.js +1 -0
- package/dist/esm/mod.js.map +1 -1
- package/dist/esm/src/auth/Peer.js +18 -20
- package/dist/esm/src/auth/Peer.js.map +1 -1
- package/dist/esm/src/identity/IdentityClient.js +20 -124
- package/dist/esm/src/identity/IdentityClient.js.map +1 -1
- package/dist/esm/src/primitives/TransactionSignature.js +115 -10
- package/dist/esm/src/primitives/TransactionSignature.js.map +1 -1
- package/dist/esm/src/primitives/utils.js +13 -112
- package/dist/esm/src/primitives/utils.js.map +1 -1
- package/dist/esm/src/remittance/CommsLayer.js +2 -0
- package/dist/esm/src/remittance/CommsLayer.js.map +1 -0
- package/dist/esm/src/remittance/IdentityLayer.js +2 -0
- package/dist/esm/src/remittance/IdentityLayer.js.map +1 -0
- package/dist/esm/src/remittance/RemittanceManager.js +1254 -0
- package/dist/esm/src/remittance/RemittanceManager.js.map +1 -0
- package/dist/esm/src/remittance/RemittanceModule.js +2 -0
- package/dist/esm/src/remittance/RemittanceModule.js.map +1 -0
- package/dist/esm/src/remittance/index.js +7 -0
- package/dist/esm/src/remittance/index.js.map +1 -0
- package/dist/esm/src/remittance/modules/BasicBRC29.js +227 -0
- package/dist/esm/src/remittance/modules/BasicBRC29.js.map +1 -0
- package/dist/esm/src/remittance/modules/index.js +2 -0
- package/dist/esm/src/remittance/modules/index.js.map +1 -0
- package/dist/esm/src/remittance/types.js +19 -0
- package/dist/esm/src/remittance/types.js.map +1 -0
- package/dist/esm/src/script/OP.js +15 -13
- package/dist/esm/src/script/OP.js.map +1 -1
- package/dist/esm/src/script/Script.js +4 -1
- package/dist/esm/src/script/Script.js.map +1 -1
- package/dist/esm/src/script/Spend.js +129 -46
- package/dist/esm/src/script/Spend.js.map +1 -1
- package/dist/esm/src/transaction/BeefTx.js +3 -3
- package/dist/esm/src/transaction/BeefTx.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +160 -0
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/mod.d.ts +1 -0
- package/dist/types/mod.d.ts.map +1 -1
- package/dist/types/src/auth/Peer.d.ts +3 -7
- package/dist/types/src/auth/Peer.d.ts.map +1 -1
- package/dist/types/src/identity/IdentityClient.d.ts +0 -8
- package/dist/types/src/identity/IdentityClient.d.ts.map +1 -1
- package/dist/types/src/primitives/TransactionSignature.d.ts +16 -4
- package/dist/types/src/primitives/TransactionSignature.d.ts.map +1 -1
- package/dist/types/src/primitives/utils.d.ts +1 -0
- package/dist/types/src/primitives/utils.d.ts.map +1 -1
- package/dist/types/src/remittance/CommsLayer.d.ts +50 -0
- package/dist/types/src/remittance/CommsLayer.d.ts.map +1 -0
- package/dist/types/src/remittance/IdentityLayer.d.ts +35 -0
- package/dist/types/src/remittance/IdentityLayer.d.ts.map +1 -0
- package/dist/types/src/remittance/RemittanceManager.d.ts +452 -0
- package/dist/types/src/remittance/RemittanceManager.d.ts.map +1 -0
- package/dist/types/src/remittance/RemittanceModule.d.ts +106 -0
- package/dist/types/src/remittance/RemittanceModule.d.ts.map +1 -0
- package/dist/types/src/remittance/index.d.ts +7 -0
- package/dist/types/src/remittance/index.d.ts.map +1 -0
- package/dist/types/src/remittance/modules/BasicBRC29.d.ts +133 -0
- package/dist/types/src/remittance/modules/BasicBRC29.d.ts.map +1 -0
- package/dist/types/src/remittance/modules/index.d.ts +2 -0
- package/dist/types/src/remittance/modules/index.d.ts.map +1 -0
- package/dist/types/src/remittance/types.d.ts +238 -0
- package/dist/types/src/remittance/types.d.ts.map +1 -0
- package/dist/types/src/script/OP.d.ts +5 -3
- package/dist/types/src/script/OP.d.ts.map +1 -1
- package/dist/types/src/script/Script.d.ts.map +1 -1
- package/dist/types/src/script/Spend.d.ts +7 -0
- package/dist/types/src/script/Spend.d.ts.map +1 -1
- package/dist/types/src/transaction/BeefTx.d.ts +2 -2
- package/dist/types/src/transaction/Transaction.d.ts +14 -0
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/src/wallet/Wallet.interfaces.d.ts +5 -5
- package/dist/types/src/wallet/Wallet.interfaces.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +13 -13
- package/dist/umd/bundle.js.map +1 -1
- package/docs/index.md +2 -14
- package/docs/reference/auth.md +6 -12
- package/docs/reference/primitives.md +20 -78
- package/docs/reference/remittance.md +2166 -0
- package/docs/reference/script.md +11 -3
- package/docs/reference/transaction.md +27 -1
- package/docs/reference/wallet.md +6 -5
- package/docs/remittance-getting-started.md +138 -0
- package/mod.ts +1 -0
- package/package.json +12 -3
- package/src/auth/Peer.ts +18 -29
- package/src/auth/__tests/Peer.test.ts +253 -1
- package/src/identity/IdentityClient.ts +29 -153
- package/src/identity/__tests/IdentityClient.test.ts +1 -289
- package/src/overlay-tools/__tests/SHIPBroadcaster.test.ts +7 -9
- package/src/primitives/TransactionSignature.ts +129 -10
- package/src/primitives/__tests/utils.test.ts +30 -7
- package/src/primitives/utils.ts +13 -129
- package/src/remittance/CommsLayer.ts +41 -0
- package/src/remittance/IdentityLayer.ts +32 -0
- package/src/remittance/RemittanceManager.ts +1672 -0
- package/src/remittance/RemittanceModule.ts +92 -0
- package/src/remittance/__tests/BasicBRC29.test.ts +188 -0
- package/src/remittance/__tests/RemittanceManager.test.ts +493 -0
- package/src/remittance/__tests/examples.ts +130 -0
- package/src/remittance/index.ts +6 -0
- package/src/remittance/modules/BasicBRC29.ts +361 -0
- package/src/remittance/modules/index.ts +1 -0
- package/src/remittance/types.ts +284 -0
- package/src/script/OP.ts +15 -13
- package/src/script/Script.ts +3 -1
- package/src/script/Spend.ts +128 -52
- package/src/script/__tests/Chronicle.test.ts +186 -0
- package/src/script/__tests/Spend.test.ts +1 -1
- package/src/script/__tests/SpendValildVectors.test.ts +63 -0
- package/src/script/__tests/lrshiftnum.test.ts +185 -0
- package/src/script/__tests/sighashTestData.ts +1031 -0
- package/src/script/__tests/spend.valid.vectors.ts +9 -16
- package/src/transaction/BeefTx.ts +3 -3
- package/src/transaction/Transaction.ts +186 -0
- package/src/transaction/__tests/Beef.test.ts +2 -0
- package/src/transaction/__tests/Transaction.test.ts +641 -3
- package/src/wallet/Wallet.interfaces.ts +5 -5
package/src/script/Script.ts
CHANGED
|
@@ -356,11 +356,13 @@ export default class Script {
|
|
|
356
356
|
findAndDelete (script: Script): Script {
|
|
357
357
|
this.invalidateSerializationCaches()
|
|
358
358
|
const buf = script.toHex()
|
|
359
|
-
for (let i = 0; i < this.chunks.length;
|
|
359
|
+
for (let i = 0; i < this.chunks.length;) {
|
|
360
360
|
const script2 = new Script([this.chunks[i]])
|
|
361
361
|
const buf2 = script2.toHex()
|
|
362
362
|
if (buf === buf2) {
|
|
363
363
|
this.chunks.splice(i, 1)
|
|
364
|
+
} else {
|
|
365
|
+
i++
|
|
364
366
|
}
|
|
365
367
|
}
|
|
366
368
|
return this
|
package/src/script/Spend.ts
CHANGED
|
@@ -17,10 +17,6 @@ import TransactionOutput from '../transaction/TransactionOutput.js'
|
|
|
17
17
|
const maxScriptElementSize = 1024 * 1024 * 1024
|
|
18
18
|
const maxMultisigKeyCount = Math.pow(2, 31) - 1
|
|
19
19
|
const maxMultisigKeyCountBigInt = BigInt(maxMultisigKeyCount)
|
|
20
|
-
const requireMinimalPush = true
|
|
21
|
-
const requirePushOnlyUnlockingScripts = true
|
|
22
|
-
const requireLowSSignatures = true
|
|
23
|
-
const requireCleanStack = true
|
|
24
20
|
|
|
25
21
|
// --- Optimization: Pre-computed script numbers ---
|
|
26
22
|
const SCRIPTNUM_NEG_1 = Object.freeze(new BigNumber(-1).toScriptNum())
|
|
@@ -89,16 +85,6 @@ function isChecksigFormatHelper (buf: Readonly<number[]>): boolean {
|
|
|
89
85
|
return true
|
|
90
86
|
}
|
|
91
87
|
|
|
92
|
-
function isOpcodeDisabledHelper (op: number): boolean {
|
|
93
|
-
return (
|
|
94
|
-
op === OP.OP_2MUL ||
|
|
95
|
-
op === OP.OP_2DIV ||
|
|
96
|
-
op === OP.OP_VERIF ||
|
|
97
|
-
op === OP.OP_VERNOTIF ||
|
|
98
|
-
op === OP.OP_VER
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
88
|
function isChunkMinimalPushHelper (chunk: ScriptChunk): boolean {
|
|
103
89
|
const data = chunk.data
|
|
104
90
|
const op = chunk.op
|
|
@@ -130,6 +116,8 @@ function isChunkMinimalPushHelper (chunk: ScriptChunk): boolean {
|
|
|
130
116
|
* @property {UnlockingScript} unlockingScript - The unlocking script that unlocks the UTXO for spending.
|
|
131
117
|
* @property {number} inputSequence - The sequence number of this input.
|
|
132
118
|
* @property {number} lockTime - The lock time of the transaction.
|
|
119
|
+
* @property {number} memoryLimit - Control over script interpreter memory usage.
|
|
120
|
+
* @property {boolean} isRelaxed - Optional. If true, disables all the unlocking script maleability restrictions consitent with Chronicle release. Maleability restrictions are neve appliced to locking scripts.
|
|
133
121
|
*/
|
|
134
122
|
export default class Spend {
|
|
135
123
|
sourceTXID: string
|
|
@@ -153,6 +141,8 @@ export default class Spend {
|
|
|
153
141
|
memoryLimit: number
|
|
154
142
|
stackMem: number
|
|
155
143
|
altStackMem: number
|
|
144
|
+
isRelaxedOverride: boolean
|
|
145
|
+
|
|
156
146
|
private sigHashCache: SignatureHashCache
|
|
157
147
|
|
|
158
148
|
/**
|
|
@@ -171,6 +161,8 @@ export default class Spend {
|
|
|
171
161
|
* @param {UnlockingScript} params.unlockingScript - The unlocking script for this spend.
|
|
172
162
|
* @param {number} params.inputSequence - The sequence number of this input.
|
|
173
163
|
* @param {number} params.lockTime - The lock time of the transaction.
|
|
164
|
+
* @param {number} params.memoryLimit - Optional control over script interpreter memory usage.
|
|
165
|
+
* @param {boolean} params.isRelaxed - Optional. If true, disables all the unlocking script maleability restrictions consitent with Chronicle release. Maleability restrictions are neve appliced to locking scripts.
|
|
174
166
|
*
|
|
175
167
|
* @example
|
|
176
168
|
* const spend = new Spend({
|
|
@@ -200,6 +192,7 @@ export default class Spend {
|
|
|
200
192
|
inputIndex: number
|
|
201
193
|
lockTime: number
|
|
202
194
|
memoryLimit?: number
|
|
195
|
+
isRelaxed?: boolean
|
|
203
196
|
}) {
|
|
204
197
|
this.sourceTXID = params.sourceTXID
|
|
205
198
|
this.sourceOutputIndex = params.sourceOutputIndex
|
|
@@ -213,6 +206,7 @@ export default class Spend {
|
|
|
213
206
|
this.inputSequence = params.inputSequence
|
|
214
207
|
this.lockTime = params.lockTime
|
|
215
208
|
this.memoryLimit = params.memoryLimit ?? 32000000
|
|
209
|
+
this.isRelaxedOverride = params.isRelaxed === true
|
|
216
210
|
this.stack = []
|
|
217
211
|
this.altStack = []
|
|
218
212
|
this.ifStack = []
|
|
@@ -222,6 +216,11 @@ export default class Spend {
|
|
|
222
216
|
this.reset()
|
|
223
217
|
}
|
|
224
218
|
|
|
219
|
+
private isRelaxed (): boolean {
|
|
220
|
+
return this.isRelaxedOverride ||
|
|
221
|
+
(this.transactionVersion > 1)
|
|
222
|
+
}
|
|
223
|
+
|
|
225
224
|
reset (): void {
|
|
226
225
|
this.context = 'UnlockingScript'
|
|
227
226
|
this.programCounter = 0
|
|
@@ -305,14 +304,10 @@ export default class Spend {
|
|
|
305
304
|
}
|
|
306
305
|
try {
|
|
307
306
|
const sig = TransactionSignature.fromChecksigFormat(buf as number[]) // This can throw for stricter DER rules
|
|
308
|
-
if (
|
|
307
|
+
if (!this.isRelaxed() && !sig.hasLowS()) {
|
|
309
308
|
this.scriptEvaluationError('The signature must have a low S value.')
|
|
310
309
|
return false
|
|
311
310
|
}
|
|
312
|
-
if ((sig.scope & TransactionSignature.SIGHASH_FORKID) === 0) {
|
|
313
|
-
this.scriptEvaluationError('The signature must use SIGHASH_FORKID.')
|
|
314
|
-
return false
|
|
315
|
-
}
|
|
316
311
|
} catch (e) {
|
|
317
312
|
this.scriptEvaluationError('The signature format is invalid.')
|
|
318
313
|
return false
|
|
@@ -409,12 +404,8 @@ export default class Spend {
|
|
|
409
404
|
|
|
410
405
|
const isScriptExecuting = !this.ifStack.includes(false)
|
|
411
406
|
|
|
412
|
-
if (isScriptExecuting && isOpcodeDisabledHelper(currentOpcode)) {
|
|
413
|
-
this.scriptEvaluationError(`This opcode is currently disabled. (Opcode: ${OP[currentOpcode] as string}, PC: ${this.programCounter})`) // Error thrown
|
|
414
|
-
}
|
|
415
|
-
|
|
416
407
|
if (isScriptExecuting && currentOpcode >= 0 && currentOpcode <= OP.OP_PUSHDATA4) {
|
|
417
|
-
if (
|
|
408
|
+
if (!this.isRelaxed() && !isChunkMinimalPushHelper(operation)) {
|
|
418
409
|
this.scriptEvaluationError(`This data is not minimally-encoded. (PC: ${this.programCounter})`) // Error thrown
|
|
419
410
|
}
|
|
420
411
|
this.pushStack(Array.isArray(operation.data) ? operation.data : [])
|
|
@@ -428,6 +419,77 @@ export default class Spend {
|
|
|
428
419
|
let i: number, ikey: number, isig: number, nKeysCount: number, nSigsCount: number, fOk: boolean
|
|
429
420
|
|
|
430
421
|
switch (currentOpcode) {
|
|
422
|
+
case OP.OP_VER:
|
|
423
|
+
this.pushStackCopy(new BigNumber(this.transactionVersion).toScriptNum())
|
|
424
|
+
break
|
|
425
|
+
case OP.OP_SUBSTR: {
|
|
426
|
+
if (this.stack.length < 3) this.scriptEvaluationError('OP_SUBSTR requires at least three items to be on the stack.')
|
|
427
|
+
const len = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()).toNumber()
|
|
428
|
+
const offset = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()).toNumber()
|
|
429
|
+
buf = this.popStack()
|
|
430
|
+
const size = buf.length
|
|
431
|
+
|
|
432
|
+
if (offset < 0 || offset >= size || len < 0 || len > size - offset) {
|
|
433
|
+
this.scriptEvaluationError(`OP_SUBSTR offset (${offset}) must be in range [0, ${size}) and length (${len}) must be in range [0, ${size - offset}]`)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
this.pushStack(buf.slice(offset, offset + len))
|
|
437
|
+
break
|
|
438
|
+
}
|
|
439
|
+
case OP.OP_LEFT: {
|
|
440
|
+
if (this.stack.length < 2) this.scriptEvaluationError('OP_LEFT requires at least two items to be on the stack.')
|
|
441
|
+
const len = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()).toNumber()
|
|
442
|
+
buf = this.popStack()
|
|
443
|
+
const size = buf.length
|
|
444
|
+
|
|
445
|
+
if (len < 0 || len > size) {
|
|
446
|
+
this.scriptEvaluationError(`OP_LEFT length (${len}) must be in range [0, ${size}]`)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
this.pushStack(buf.slice(0, len))
|
|
450
|
+
break
|
|
451
|
+
}
|
|
452
|
+
case OP.OP_RIGHT: {
|
|
453
|
+
if (this.stack.length < 2) this.scriptEvaluationError('OP_RIGHT requires at least two items to be on the stack.')
|
|
454
|
+
const len = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()).toNumber()
|
|
455
|
+
buf = this.popStack()
|
|
456
|
+
const size = buf.length
|
|
457
|
+
|
|
458
|
+
if (len < 0 || len > size) {
|
|
459
|
+
this.scriptEvaluationError(`OP_RIGHT length (${len}) must be in range [0, ${size}]`)
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
this.pushStack(buf.slice(size - len, len))
|
|
463
|
+
break
|
|
464
|
+
}
|
|
465
|
+
case OP.OP_LSHIFTNUM: {
|
|
466
|
+
if (this.stack.length < 2) this.scriptEvaluationError('OP_LSHIFTNUM requires at least two items to be on the stack.')
|
|
467
|
+
const bits = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()).toBigInt()
|
|
468
|
+
if (bits < 0) {
|
|
469
|
+
this.scriptEvaluationError('OP_LSHIFTNUM bits to shift must not be negative.')
|
|
470
|
+
}
|
|
471
|
+
const value = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()).toBigInt()
|
|
472
|
+
const resultBn = new BigNumber(value << bits)
|
|
473
|
+
this.pushStack(resultBn.toScriptNum())
|
|
474
|
+
break
|
|
475
|
+
}
|
|
476
|
+
case OP.OP_RSHIFTNUM: {
|
|
477
|
+
if (this.stack.length < 2) this.scriptEvaluationError('OP_RSHIFTNUM requires at least two items to be on the stack.')
|
|
478
|
+
const bits = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()).toBigInt()
|
|
479
|
+
if (bits < 0) {
|
|
480
|
+
this.scriptEvaluationError('OP_RSHIFTNUM bits to shift must not be negative.')
|
|
481
|
+
}
|
|
482
|
+
const value = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()).toBigInt()
|
|
483
|
+
let resultBn: BigNumber
|
|
484
|
+
if (value < 0) {
|
|
485
|
+
resultBn = new BigNumber(-(-value >> bits))
|
|
486
|
+
} else {
|
|
487
|
+
resultBn = new BigNumber(value >> bits)
|
|
488
|
+
}
|
|
489
|
+
this.pushStack(resultBn.toScriptNum())
|
|
490
|
+
break
|
|
491
|
+
}
|
|
492
|
+
|
|
431
493
|
case OP.OP_1NEGATE: this.pushStackCopy(SCRIPTNUM_NEG_1); break
|
|
432
494
|
case OP.OP_0: this.pushStackCopy(SCRIPTNUMS_0_TO_16[0]); break
|
|
433
495
|
case OP.OP_1: case OP.OP_2: case OP.OP_3: case OP.OP_4:
|
|
@@ -439,18 +501,17 @@ export default class Spend {
|
|
|
439
501
|
break
|
|
440
502
|
|
|
441
503
|
case OP.OP_NOP:
|
|
442
|
-
case OP.OP_NOP2: // Formerly CHECKLOCKTIMEVERIFY
|
|
443
|
-
case OP.OP_NOP3: // Formerly CHECKSEQUENCEVERIFY
|
|
444
504
|
case OP.OP_NOP1:
|
|
445
|
-
case OP.
|
|
446
|
-
case OP.
|
|
447
|
-
case OP.
|
|
505
|
+
case OP.OP_NOP2:
|
|
506
|
+
case OP.OP_NOP3:
|
|
507
|
+
// case OP.OP_NOP4: // Allocated to OP_SUBSTR
|
|
508
|
+
// case OP.OP_NOP5: // Allocated to OP_LEFT
|
|
509
|
+
// case OP.OP_NOP6: // Allocated to OP_RIGHT
|
|
510
|
+
// eslint-disable-next-line no-fallthrough
|
|
448
511
|
case OP.OP_NOP7:
|
|
449
512
|
case OP.OP_NOP8:
|
|
450
513
|
case OP.OP_NOP9:
|
|
451
514
|
case OP.OP_NOP10:
|
|
452
|
-
/* falls through */
|
|
453
|
-
// eslint-disable-next-line no-fallthrough
|
|
454
515
|
// eslint-disable-next-line no-fallthrough
|
|
455
516
|
case OP.OP_NOP11: case OP.OP_NOP12: case OP.OP_NOP13: case OP.OP_NOP14: case OP.OP_NOP15:
|
|
456
517
|
case OP.OP_NOP16: case OP.OP_NOP17: case OP.OP_NOP18: case OP.OP_NOP19: case OP.OP_NOP20:
|
|
@@ -468,6 +529,18 @@ export default class Spend {
|
|
|
468
529
|
case OP.OP_NOP77:
|
|
469
530
|
break
|
|
470
531
|
|
|
532
|
+
case OP.OP_VERIF:
|
|
533
|
+
case OP.OP_VERNOTIF:
|
|
534
|
+
fValue = false
|
|
535
|
+
if (isScriptExecuting) {
|
|
536
|
+
if (this.stack.length < 1) this.scriptEvaluationError('OP_VERIF and OP_VERNOTIF require at least one item on the stack when they are used!')
|
|
537
|
+
buf2 = new BigNumber(this.transactionVersion).toScriptNum()
|
|
538
|
+
buf1 = this.popStack()
|
|
539
|
+
fValue = compareNumberArrays(buf1, buf2)
|
|
540
|
+
if (currentOpcode === OP.OP_VERNOTIF) fValue = !fValue
|
|
541
|
+
}
|
|
542
|
+
this.ifStack.push(fValue)
|
|
543
|
+
break
|
|
471
544
|
case OP.OP_IF:
|
|
472
545
|
case OP.OP_NOTIF:
|
|
473
546
|
fValue = false
|
|
@@ -581,7 +654,7 @@ export default class Spend {
|
|
|
581
654
|
case OP.OP_PICK:
|
|
582
655
|
case OP.OP_ROLL: {
|
|
583
656
|
if (this.stack.length < 2) this.scriptEvaluationError(`${OP[currentOpcode] as string} requires at least two items to be on the stack.`)
|
|
584
|
-
bn = BigNumber.fromScriptNum(this.popStack(),
|
|
657
|
+
bn = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed())
|
|
585
658
|
const nBigInt = bn.toBigInt()
|
|
586
659
|
if (nBigInt < 0n || nBigInt >= BigInt(this.stack.length)) {
|
|
587
660
|
this.scriptEvaluationError(`${OP[currentOpcode] as string} requires the top stack element to be 0 or a positive number less than the current size of the stack.`)
|
|
@@ -654,7 +727,7 @@ export default class Spend {
|
|
|
654
727
|
case OP.OP_LSHIFT:
|
|
655
728
|
case OP.OP_RSHIFT: {
|
|
656
729
|
if (this.stack.length < 2) this.scriptEvaluationError(`${OP[currentOpcode] as string} requires at least two items to be on the stack.`)
|
|
657
|
-
bn2 = BigNumber.fromScriptNum(this.popStack(),
|
|
730
|
+
bn2 = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()) // n (shift amount)
|
|
658
731
|
buf1 = this.popStack() // value to shift
|
|
659
732
|
const shiftBits = bn2.toBigInt()
|
|
660
733
|
if (shiftBits < 0n) this.scriptEvaluationError(`${OP[currentOpcode] as string} requires the top item on the stack not to be negative.`)
|
|
@@ -684,14 +757,16 @@ export default class Spend {
|
|
|
684
757
|
}
|
|
685
758
|
break
|
|
686
759
|
|
|
687
|
-
case OP.OP_1ADD: case OP.OP_1SUB:
|
|
760
|
+
case OP.OP_1ADD: case OP.OP_1SUB: case OP.OP_2MUL: case OP.OP_2DIV:
|
|
688
761
|
case OP.OP_NEGATE: case OP.OP_ABS:
|
|
689
762
|
case OP.OP_NOT: case OP.OP_0NOTEQUAL:
|
|
690
763
|
if (this.stack.length < 1) this.scriptEvaluationError(`${OP[currentOpcode] as string} requires at least one item to be on the stack.`)
|
|
691
|
-
bn = BigNumber.fromScriptNum(this.popStack(),
|
|
764
|
+
bn = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed())
|
|
692
765
|
switch (currentOpcode) {
|
|
693
766
|
case OP.OP_1ADD: bn = bn.add(new BigNumber(1)); break
|
|
694
767
|
case OP.OP_1SUB: bn = bn.sub(new BigNumber(1)); break
|
|
768
|
+
case OP.OP_2MUL: bn = bn.mul(new BigNumber(2)); break
|
|
769
|
+
case OP.OP_2DIV: bn = bn.div(new BigNumber(2)); break
|
|
695
770
|
case OP.OP_NEGATE: bn = bn.neg(); break
|
|
696
771
|
case OP.OP_ABS: if (bn.isNeg()) bn = bn.neg(); break
|
|
697
772
|
case OP.OP_NOT: bn = new BigNumber(bn.cmpn(0) === 0 ? 1 : 0); break
|
|
@@ -708,8 +783,8 @@ export default class Spend {
|
|
|
708
783
|
if (this.stack.length < 2) this.scriptEvaluationError(`${OP[currentOpcode] as string} requires at least two items to be on the stack.`)
|
|
709
784
|
buf2 = this.popStack()
|
|
710
785
|
buf1 = this.popStack()
|
|
711
|
-
bn2 = BigNumber.fromScriptNum(buf2,
|
|
712
|
-
bn1 = BigNumber.fromScriptNum(buf1,
|
|
786
|
+
bn2 = BigNumber.fromScriptNum(buf2, !this.isRelaxed())
|
|
787
|
+
bn1 = BigNumber.fromScriptNum(buf1, !this.isRelaxed())
|
|
713
788
|
let predictedLen = 0
|
|
714
789
|
switch (currentOpcode) {
|
|
715
790
|
case OP.OP_MUL:
|
|
@@ -755,9 +830,9 @@ export default class Spend {
|
|
|
755
830
|
}
|
|
756
831
|
case OP.OP_WITHIN:
|
|
757
832
|
if (this.stack.length < 3) this.scriptEvaluationError('OP_WITHIN requires at least three items to be on the stack.')
|
|
758
|
-
bn3 = BigNumber.fromScriptNum(this.popStack(),
|
|
759
|
-
bn2 = BigNumber.fromScriptNum(this.popStack(),
|
|
760
|
-
bn1 = BigNumber.fromScriptNum(this.popStack(),
|
|
833
|
+
bn3 = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()) // max
|
|
834
|
+
bn2 = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()) // min
|
|
835
|
+
bn1 = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()) // x
|
|
761
836
|
fValue = bn1.cmp(bn2) >= 0 && bn1.cmp(bn3) < 0
|
|
762
837
|
this.pushStack(fValue ? [1] : [])
|
|
763
838
|
break
|
|
@@ -789,15 +864,16 @@ export default class Spend {
|
|
|
789
864
|
this.scriptEvaluationError(`${OP[currentOpcode] as string} requires correct encoding for the public key and signature.`) // Fallback, should be unreachable
|
|
790
865
|
}
|
|
791
866
|
|
|
792
|
-
const scriptForChecksig = this.context === 'UnlockingScript' ? this.unlockingScript : this.lockingScript
|
|
793
|
-
const scriptCodeChunks = scriptForChecksig.chunks.slice(this.lastCodeSeparator === null ? 0 : this.lastCodeSeparator + 1)
|
|
794
|
-
subscript = new Script(scriptCodeChunks)
|
|
795
|
-
subscript.findAndDelete(new Script().writeBin(bufSig))
|
|
796
|
-
|
|
797
867
|
fSuccess = false
|
|
798
868
|
if (bufSig.length > 0) {
|
|
799
869
|
try {
|
|
800
870
|
sig = TransactionSignature.fromChecksigFormat(bufSig)
|
|
871
|
+
|
|
872
|
+
const scriptForChecksig: Script = this.context === 'UnlockingScript' ? this.unlockingScript : this.lockingScript
|
|
873
|
+
const scriptCodeChunks = scriptForChecksig.chunks.slice(this.lastCodeSeparator === null ? 0 : this.lastCodeSeparator + 1)
|
|
874
|
+
subscript = new Script(scriptCodeChunks)
|
|
875
|
+
subscript.findAndDelete(new Script().writeBin(bufSig))
|
|
876
|
+
|
|
801
877
|
pubkey = PublicKey.fromDER(bufPubkey)
|
|
802
878
|
fSuccess = this.verifySignature(sig, pubkey, subscript)
|
|
803
879
|
} catch (e) {
|
|
@@ -819,7 +895,7 @@ export default class Spend {
|
|
|
819
895
|
this.scriptEvaluationError(`${OP[currentOpcode] as string} requires at least 1 item for nKeys.`)
|
|
820
896
|
}
|
|
821
897
|
|
|
822
|
-
const nKeysCountBN = BigNumber.fromScriptNum(this.stackTop(-i),
|
|
898
|
+
const nKeysCountBN = BigNumber.fromScriptNum(this.stackTop(-i), !this.isRelaxed())
|
|
823
899
|
const nKeysCountBigInt = nKeysCountBN.toBigInt()
|
|
824
900
|
if (nKeysCountBigInt < 0n || nKeysCountBigInt > maxMultisigKeyCountBigInt) {
|
|
825
901
|
this.scriptEvaluationError(`${OP[currentOpcode] as string} requires a key count between 0 and ${maxMultisigKeyCount}.`)
|
|
@@ -833,7 +909,7 @@ export default class Spend {
|
|
|
833
909
|
this.scriptEvaluationError(`${OP[currentOpcode] as string} stack too small for nKeys and keys. Need ${i}, have ${this.stack.length}.`)
|
|
834
910
|
}
|
|
835
911
|
|
|
836
|
-
const nSigsCountBN = BigNumber.fromScriptNum(this.stackTop(-i),
|
|
912
|
+
const nSigsCountBN = BigNumber.fromScriptNum(this.stackTop(-i), !this.isRelaxed())
|
|
837
913
|
const nSigsCountBigInt = nSigsCountBN.toBigInt()
|
|
838
914
|
if (nSigsCountBigInt < 0n || nSigsCountBigInt > BigInt(nKeysCount)) {
|
|
839
915
|
this.scriptEvaluationError(`${OP[currentOpcode] as string} requires the number of signatures to be no greater than the number of keys.`)
|
|
@@ -907,7 +983,7 @@ export default class Spend {
|
|
|
907
983
|
this.scriptEvaluationError(`${OP[currentOpcode] as string} requires an extra item (dummy) to be on the stack.`)
|
|
908
984
|
}
|
|
909
985
|
const dummyBuf = this.popStack()
|
|
910
|
-
if (dummyBuf.length > 0) { // SCRIPT_VERIFY_NULLDUMMY
|
|
986
|
+
if (!this.isRelaxed() && dummyBuf.length > 0) { // SCRIPT_VERIFY_NULLDUMMY
|
|
911
987
|
this.scriptEvaluationError(`${OP[currentOpcode] as string} requires the extra stack item (dummy) to be empty.`)
|
|
912
988
|
}
|
|
913
989
|
|
|
@@ -933,7 +1009,7 @@ export default class Spend {
|
|
|
933
1009
|
const posBuf = this.popStack()
|
|
934
1010
|
const dataToSplit = this.popStack()
|
|
935
1011
|
|
|
936
|
-
const splitIndexBigInt = BigNumber.fromScriptNum(posBuf,
|
|
1012
|
+
const splitIndexBigInt = BigNumber.fromScriptNum(posBuf, !this.isRelaxed()).toBigInt()
|
|
937
1013
|
if (splitIndexBigInt < 0n || splitIndexBigInt > BigInt(dataToSplit.length)) {
|
|
938
1014
|
this.scriptEvaluationError('OP_SPLIT requires the first stack item to be a non-negative number less than or equal to the size of the second-from-top stack item.')
|
|
939
1015
|
}
|
|
@@ -946,7 +1022,7 @@ export default class Spend {
|
|
|
946
1022
|
case OP.OP_NUM2BIN: {
|
|
947
1023
|
if (this.stack.length < 2) this.scriptEvaluationError('OP_NUM2BIN requires at least two items to be on the stack.')
|
|
948
1024
|
|
|
949
|
-
const sizeBigInt = BigNumber.fromScriptNum(this.popStack(),
|
|
1025
|
+
const sizeBigInt = BigNumber.fromScriptNum(this.popStack(), !this.isRelaxed()).toBigInt()
|
|
950
1026
|
if (sizeBigInt > BigInt(maxScriptElementSize) || sizeBigInt < 0n) { // size can be 0
|
|
951
1027
|
this.scriptEvaluationError(`It's not currently possible to push data larger than ${maxScriptElementSize} bytes or negative size.`)
|
|
952
1028
|
}
|
|
@@ -1016,7 +1092,7 @@ export default class Spend {
|
|
|
1016
1092
|
* }
|
|
1017
1093
|
*/
|
|
1018
1094
|
validate (): boolean {
|
|
1019
|
-
if (
|
|
1095
|
+
if (!this.isRelaxed() && !this.unlockingScript.isPushOnly()) {
|
|
1020
1096
|
this.scriptEvaluationError(
|
|
1021
1097
|
'Unlocking scripts can only contain push operations, and no other opcodes.'
|
|
1022
1098
|
)
|
|
@@ -1037,7 +1113,7 @@ export default class Spend {
|
|
|
1037
1113
|
)
|
|
1038
1114
|
}
|
|
1039
1115
|
|
|
1040
|
-
if (
|
|
1116
|
+
if (!this.isRelaxed()) {
|
|
1041
1117
|
if (this.stack.length !== 1) {
|
|
1042
1118
|
this.scriptEvaluationError(
|
|
1043
1119
|
`The clean stack rule requires exactly one item to be on the stack after script execution, found ${this.stack.length}.`
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import TransactionSignature from '../../primitives/TransactionSignature.js'
|
|
2
|
+
import { Hash, Utils } from '../../primitives/index.js'
|
|
3
|
+
import Script from '../Script.js'
|
|
4
|
+
import Spend from '../Spend.js'
|
|
5
|
+
import Transaction from '../../transaction/Transaction.js'
|
|
6
|
+
import { sighashTestData, sighashTestDataWip } from './sighashTestData.js'
|
|
7
|
+
|
|
8
|
+
describe('Chronicle Tests', () => {
|
|
9
|
+
|
|
10
|
+
it('spend bip143 input', () => {
|
|
11
|
+
const rawTx =
|
|
12
|
+
'0100000001cc5988c346027ca1f6870422616d022caf216f537f3d4994f7a7d46a8bf0758a020000006b483045022100f1c0bfe5e7c9c5559ede2b1e2b98aeaac295218406df1d66af397f615350599202201ad5d39c6706e1cc5cdc297ee5cd5d5f79d237a1c4b16c5b4646c284f2eeeabe41210245c6e32afad67f6177b02cfc2878fce2a28e77ad9ecbc6356960c020c592d867ffffffff0302000000000000001976a914a4429da7462800dedc7b03a4fc77c363b8de40f588ac000000000000000020006a4c1c507573682d5468652d427574746f6e2e617070207c204c616d6264610a32f201000000001976a914296b03a4dd56b3b0fe5706c845f2edff22e84d7388ac00000000'
|
|
13
|
+
const lockingScript =
|
|
14
|
+
'76a914296b03a4dd56b3b0fe5706c845f2edff22e84d7388ac'
|
|
15
|
+
const ok = validateUnlockScript(rawTx, 0, lockingScript, 32649741)
|
|
16
|
+
expect(ok).toBe(true)
|
|
17
|
+
// preimage 182 byes
|
|
18
|
+
// "010000002987eea6ff44b0a0c38a4c81cc92c052f6bcb7e3cfa2f59e3af1f7a73433a6fc3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044cc5988c346027ca1f6870422616d022caf216f537f3d4994f7a7d46a8bf0758a020000001976a914296b03a4dd56b3b0fe5706c845f2edff22e84d7388ac0d32f20100000000ffffffffa4cd3e7fef24c9653d7a12c404e428b5bb9ac1c5d3a9ddc5a4b9331536df94d50000000041000000"
|
|
19
|
+
// sighash
|
|
20
|
+
// "f40a770ed6f1952973387579d7c7d14719d2bdce871fb449b6fa3d5cca35fbcf"
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('spend OTDA', () => {
|
|
24
|
+
const rawTx =
|
|
25
|
+
// block 300000, txid 7301b595279ece985f0c415e420e425451fcf7f684fcce087ba14d10ffec1121
|
|
26
|
+
'01000000014dff4050dcee16672e48d755c6dd25d324492b5ea306f85a3ab23b4df26e16e9000000008c493046022100cb6dc911ef0bae0ab0e6265a45f25e081fc7ea4975517c9f848f82bc2b80a909022100e30fb6bb4fb64f414c351ed3abaed7491b8f0b1b9bcd75286036df8bfabc3ea5014104b70574006425b61867d2cbb8de7c26095fbc00ba4041b061cf75b85699cb2b449c6758741f640adffa356406632610efb267cb1efa0442c207059dd7fd652eeaffffffff020049d971020000001976a91461cf5af7bb84348df3fd695672e53c7d5b3f3db988ac30601c0c060000001976a914fd4ed114ef85d350d6d40ed3f6dc23743f8f99c488ac00000000'
|
|
27
|
+
const lockingScript =
|
|
28
|
+
// input sourceTxid e9166ef24d3bb23a5af806a35e2b4924d325ddc655d7482e6716eedc5040ff4d vout 0
|
|
29
|
+
// 'OP_DUP OP_HASH160 5478d152bb557ac994c9793cece77d4295ed37e3 OP_EQUALVERIFY OP_CHECKSIG'
|
|
30
|
+
'76a9145478d152bb557ac994c9793cece77d4295ed37e388ac'
|
|
31
|
+
const ok = validateUnlockScript(rawTx, 0, lockingScript, 36473000000, true)
|
|
32
|
+
expect(ok).toBe(true)
|
|
33
|
+
// preimage 148 bytes
|
|
34
|
+
// "01000000014dff4050dcee16672e48d755c6dd25d324492b5ea306f85a3ab23b4df26e16e9000000001976a9145478d152bb557ac994c9793cece77d4295ed37e388acffffffff020049d971020000001976a91461cf5af7bb84348df3fd695672e53c7d5b3f3db988ac30601c0c060000001976a914fd4ed114ef85d350d6d40ed3f6dc23743f8f99c488ac0000000001000000"
|
|
35
|
+
// sighash
|
|
36
|
+
// "bdf9e0f5600d64bf3754919bd181f5e3848440ef7b351150abcb1ca3a54d3eb9",
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* At present only the first two test vectors added as real transaction (pre and post fork) compute a sighash known to match a valid signagure.
|
|
41
|
+
* The remaining test vectors come from bitcoin-sv-staging repo as of 2025-06-23, but appear to be at least somewhat randomly generated.
|
|
42
|
+
* The "scope" (SigHashType) values are all over the place.
|
|
43
|
+
* Working with Teranode team to determine correct preimage values...
|
|
44
|
+
*/
|
|
45
|
+
it('sighashTestData', () => {
|
|
46
|
+
let log = ''
|
|
47
|
+
let i = -1
|
|
48
|
+
for (const t of sighashTestData) {
|
|
49
|
+
i++
|
|
50
|
+
const tx = Transaction.fromHex(t.rawTxHex)
|
|
51
|
+
const script = Script.fromHex(t.scriptHex)
|
|
52
|
+
const input = tx.inputs[t.inputIndex]
|
|
53
|
+
if (input.unlockingScript?.chunks.length != 2)
|
|
54
|
+
continue;
|
|
55
|
+
const otherInputs = [...tx.inputs]
|
|
56
|
+
otherInputs.splice(t.inputIndex, 1)
|
|
57
|
+
const params = {
|
|
58
|
+
sourceTXID: input.sourceTXID!,
|
|
59
|
+
sourceOutputIndex: input.sourceOutputIndex,
|
|
60
|
+
sourceSatoshis: t.satoshis,
|
|
61
|
+
transactionVersion: tx.version,
|
|
62
|
+
otherInputs,
|
|
63
|
+
outputs: tx.outputs,
|
|
64
|
+
inputIndex: t.inputIndex,
|
|
65
|
+
subscript: Script.fromHex(t.scriptHex),
|
|
66
|
+
inputSequence: input.sequence ?? 0xffffffff, // Default to max sequence number
|
|
67
|
+
lockTime: tx.lockTime,
|
|
68
|
+
scope: t.hashType,
|
|
69
|
+
}
|
|
70
|
+
let ok = false
|
|
71
|
+
let okReg = false
|
|
72
|
+
let okOTDA = false
|
|
73
|
+
{
|
|
74
|
+
const sighash = t.sighashReg
|
|
75
|
+
const buf = TransactionSignature.format(params)
|
|
76
|
+
const ret = Utils.toHex(Hash.hash256(buf).reverse())
|
|
77
|
+
if (ret === sighash) {
|
|
78
|
+
ok = true
|
|
79
|
+
okReg = true
|
|
80
|
+
}
|
|
81
|
+
if (!okReg)
|
|
82
|
+
log += `${i+1} Reg ${okReg} ${!okReg ? ret : ''}\n`
|
|
83
|
+
}
|
|
84
|
+
{
|
|
85
|
+
const sighash = t.sighashOTDA
|
|
86
|
+
const buf = TransactionSignature.formatOTDA(params)
|
|
87
|
+
const ret = Utils.toHex(Hash.hash256(buf).reverse())
|
|
88
|
+
if (ret === sighash) {
|
|
89
|
+
ok = true
|
|
90
|
+
okOTDA = true
|
|
91
|
+
}
|
|
92
|
+
if (!okOTDA)
|
|
93
|
+
log += `${i+1} OTDA ${okOTDA} ${!okOTDA ? ret : ''}\n`
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//console.log(log)
|
|
97
|
+
//expect(log).toBe('')
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('wip sighashTestData', () => {
|
|
101
|
+
let log = ''
|
|
102
|
+
let i = -1
|
|
103
|
+
for (const t of sighashTestDataWip) {
|
|
104
|
+
i++
|
|
105
|
+
const tx = Transaction.fromHex(t.rawTxHex)
|
|
106
|
+
const script = Script.fromHex(t.scriptHex)
|
|
107
|
+
const input = tx.inputs[t.inputIndex]
|
|
108
|
+
const otherInputs = [...tx.inputs]
|
|
109
|
+
otherInputs.splice(t.inputIndex, 1)
|
|
110
|
+
const params = {
|
|
111
|
+
sourceTXID: input.sourceTXID!,
|
|
112
|
+
sourceOutputIndex: input.sourceOutputIndex,
|
|
113
|
+
sourceSatoshis: t.satoshis,
|
|
114
|
+
transactionVersion: tx.version,
|
|
115
|
+
otherInputs,
|
|
116
|
+
outputs: tx.outputs,
|
|
117
|
+
inputIndex: t.inputIndex,
|
|
118
|
+
subscript: Script.fromHex(t.scriptHex),
|
|
119
|
+
inputSequence: input.sequence ?? 0xffffffff, // Default to max sequence number
|
|
120
|
+
lockTime: tx.lockTime,
|
|
121
|
+
scope: t.hashType,
|
|
122
|
+
}
|
|
123
|
+
let ok = false
|
|
124
|
+
let okReg = false
|
|
125
|
+
let okOTDA = false
|
|
126
|
+
{
|
|
127
|
+
const sighash = t.sighashReg
|
|
128
|
+
const buf = TransactionSignature.format(params)
|
|
129
|
+
const ret = Utils.toHex(Hash.hash256(buf).reverse())
|
|
130
|
+
if (ret === sighash) {
|
|
131
|
+
ok = true
|
|
132
|
+
okReg = true
|
|
133
|
+
}
|
|
134
|
+
if (!okReg)
|
|
135
|
+
log += `${i+1} Reg ${okReg} ${!okReg ? ret : ''}\n`
|
|
136
|
+
}
|
|
137
|
+
{
|
|
138
|
+
const sighash = t.sighashOTDA
|
|
139
|
+
const buf = TransactionSignature.formatOTDA(params)
|
|
140
|
+
const ret = Utils.toHex(Hash.hash256(buf).reverse())
|
|
141
|
+
if (ret === sighash) {
|
|
142
|
+
ok = true
|
|
143
|
+
okOTDA = true
|
|
144
|
+
}
|
|
145
|
+
if (!okOTDA)
|
|
146
|
+
log += `${i+1} OTDA ${okOTDA} ${!okOTDA ? ret : ''}\n`
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
console.log(log)
|
|
150
|
+
expect(log).toBe('')
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
function verifyTruthy<T> (v: T | undefined): T {
|
|
155
|
+
if (v == null) throw new Error('must have value')
|
|
156
|
+
return v
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function validateUnlockScript (
|
|
160
|
+
spendingRawTx: string,
|
|
161
|
+
vin: number,
|
|
162
|
+
lockingScript: string,
|
|
163
|
+
amount: number,
|
|
164
|
+
isRelaxed?: boolean
|
|
165
|
+
): boolean {
|
|
166
|
+
const spendingTx = Transaction.fromHex(spendingRawTx)
|
|
167
|
+
const ls = Script.fromHex(lockingScript)
|
|
168
|
+
|
|
169
|
+
const spend = new Spend({
|
|
170
|
+
sourceTXID: verifyTruthy(spendingTx.inputs[vin].sourceTXID),
|
|
171
|
+
sourceOutputIndex: verifyTruthy(spendingTx.inputs[vin].sourceOutputIndex),
|
|
172
|
+
sourceSatoshis: amount,
|
|
173
|
+
lockingScript: ls,
|
|
174
|
+
transactionVersion: spendingTx.version,
|
|
175
|
+
otherInputs: spendingTx.inputs.filter((v, i) => i !== vin),
|
|
176
|
+
inputIndex: vin,
|
|
177
|
+
unlockingScript: verifyTruthy(spendingTx.inputs[vin].unlockingScript),
|
|
178
|
+
outputs: spendingTx.outputs,
|
|
179
|
+
inputSequence: verifyTruthy(spendingTx.inputs[vin].sequence),
|
|
180
|
+
lockTime: spendingTx.lockTime,
|
|
181
|
+
isRelaxed
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
const valid = spend.validate()
|
|
185
|
+
return valid
|
|
186
|
+
}
|
|
@@ -9,7 +9,7 @@ import LockingScript from '../../script/LockingScript'
|
|
|
9
9
|
import UnlockingScript from '../../script/UnlockingScript'
|
|
10
10
|
import MerklePath from '../../transaction/MerklePath'
|
|
11
11
|
import ChainTracker from '../../transaction/ChainTracker'
|
|
12
|
-
import spendValid from './spend.valid.vectors'
|
|
12
|
+
import { preChronicle as spendValid } from './spend.valid.vectors'
|
|
13
13
|
import Script from '../../script/Script'
|
|
14
14
|
import BigNumber from '../../primitives/BigNumber'
|
|
15
15
|
import ScriptChunk from '../../script/ScriptChunk'
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import PrivateKey from '../../primitives/PrivateKey'
|
|
2
|
+
import { hash160, hash256 } from '../../primitives/Hash'
|
|
3
|
+
import Curve from '../../primitives/Curve'
|
|
4
|
+
import Spend from '../Spend'
|
|
5
|
+
import P2PKH from '../templates/P2PKH'
|
|
6
|
+
import RPuzzle from '../templates/RPuzzle'
|
|
7
|
+
import Transaction from '../../transaction/Transaction'
|
|
8
|
+
import LockingScript from '../LockingScript'
|
|
9
|
+
import UnlockingScript from '../UnlockingScript'
|
|
10
|
+
|
|
11
|
+
import { preChronicle as spendValid1, chronicle as spendValid2 } from './spend.valid.vectors'
|
|
12
|
+
|
|
13
|
+
describe('Spend Valid Vectors 1', () => {
|
|
14
|
+
for (let i = 0; i < spendValid1.length; i++) {
|
|
15
|
+
const a = spendValid1[i]
|
|
16
|
+
if (a.length === 1) {
|
|
17
|
+
continue
|
|
18
|
+
}
|
|
19
|
+
it(`${i} ${a[2]}`, () => {
|
|
20
|
+
const spend = new Spend({
|
|
21
|
+
sourceTXID:
|
|
22
|
+
'0000000000000000000000000000000000000000000000000000000000000000',
|
|
23
|
+
sourceOutputIndex: 0,
|
|
24
|
+
sourceSatoshis: 1,
|
|
25
|
+
lockingScript: LockingScript.fromHex(a[1]),
|
|
26
|
+
transactionVersion: 1,
|
|
27
|
+
otherInputs: [],
|
|
28
|
+
outputs: [],
|
|
29
|
+
inputIndex: 0,
|
|
30
|
+
unlockingScript: UnlockingScript.fromHex(a[0]),
|
|
31
|
+
inputSequence: 0xffffffff,
|
|
32
|
+
lockTime: 0
|
|
33
|
+
})
|
|
34
|
+
expect(spend.validate()).toBe(true)
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
describe('Spend Valid Vectors 2', () => {
|
|
40
|
+
for (let i = 0; i < spendValid2.length; i++) {
|
|
41
|
+
const a = spendValid2[i]
|
|
42
|
+
if (a.length === 1) {
|
|
43
|
+
continue
|
|
44
|
+
}
|
|
45
|
+
it(`${i} ${a[2]}`, () => {
|
|
46
|
+
const spend = new Spend({
|
|
47
|
+
sourceTXID:
|
|
48
|
+
'0000000000000000000000000000000000000000000000000000000000000000',
|
|
49
|
+
sourceOutputIndex: 0,
|
|
50
|
+
sourceSatoshis: 1,
|
|
51
|
+
lockingScript: LockingScript.fromHex(a[1]),
|
|
52
|
+
transactionVersion: 1,
|
|
53
|
+
otherInputs: [],
|
|
54
|
+
outputs: [],
|
|
55
|
+
inputIndex: 0,
|
|
56
|
+
unlockingScript: UnlockingScript.fromHex(a[0]),
|
|
57
|
+
inputSequence: 0xffffffff,
|
|
58
|
+
lockTime: 0
|
|
59
|
+
})
|
|
60
|
+
expect(spend.validate()).toBe(true)
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
})
|