diff --git a/src/transaction_builder.js b/src/transaction_builder.js index c299e29..e63bdd0 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -734,13 +734,20 @@ function checkSignArgs(inputs, signParams) { `Unknown prevOutScriptType "${signParams.prevOutScriptType}"`, ); } - typeforce( - typeforce.tuple( - typeforce.Number, - typeforce.maybe(typeforce.Number), - types.Signer, - ), - [signParams.vin, signParams.hashType, signParams.keyPair], + tfMessage( + typeforce.Number, + signParams.vin, + `sign must include vin parameter as Number (input index)`, + ); + tfMessage( + types.Signer, + signParams.keyPair, + `sign must include keyPair parameter as Signer interface`, + ); + tfMessage( + typeforce.maybe(typeforce.Number), + signParams.hashType, + `sign hashType parameter must be a number`, ); const prevOutType = (inputs[signParams.vin] || []).prevOutType; const posType = signParams.prevOutScriptType; diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 040104a..07226b0 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -2470,6 +2470,190 @@ } ] }, + { + "exception": "input #0 is not of type p2pk: nulldata", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "prevTxScript": "OP_RETURN deadbeef", + "signs": [ + { + "prevOutScriptType": "p2pk", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "throws": true + } + ] + } + ], + "outputs": [ + { + "script": "OP_RETURN deadbeef", + "value": 1000 + } + ] + }, + { + "exception": "input #0 is not of type p2wpkh: nulldata", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "prevTxScript": "OP_RETURN deadbeef", + "signs": [ + { + "prevOutScriptType": "p2wpkh", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "throws": true + } + ] + } + ], + "outputs": [ + { + "script": "OP_RETURN deadbeef", + "value": 1000 + } + ] + }, + { + "exception": "input #0 is not of type p2ms: nulldata", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "prevTxScript": "OP_RETURN deadbeef", + "signs": [ + { + "prevOutScriptType": "p2ms", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "throws": true + } + ] + } + ], + "outputs": [ + { + "script": "OP_RETURN deadbeef", + "value": 1000 + } + ] + }, + { + "exception": "input #0 is not of type p2sh-p2wpkh: nulldata", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "prevTxScript": "OP_RETURN deadbeef", + "signs": [ + { + "prevOutScriptType": "p2sh-p2wpkh", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "throws": true + } + ] + } + ], + "outputs": [ + { + "script": "OP_RETURN deadbeef", + "value": 1000 + } + ] + }, + { + "exception": "input #0 is not of type p2sh-p2pk: nulldata", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "prevTxScript": "OP_RETURN deadbeef", + "signs": [ + { + "prevOutScriptType": "p2sh-p2pk", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "throws": true + } + ] + } + ], + "outputs": [ + { + "script": "OP_RETURN deadbeef", + "value": 1000 + } + ] + }, + { + "exception": "input #0 is not of type p2wsh-p2pk: nulldata", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "prevTxScript": "OP_RETURN deadbeef", + "signs": [ + { + "prevOutScriptType": "p2wsh-p2pk", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "throws": true + } + ] + } + ], + "outputs": [ + { + "script": "OP_RETURN deadbeef", + "value": 1000 + } + ] + }, + { + "exception": "input #0 is not of type p2sh-p2wsh-p2pk: nulldata", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "prevTxScript": "OP_RETURN deadbeef", + "signs": [ + { + "prevOutScriptType": "p2sh-p2wsh-p2pk", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "throws": true + } + ] + } + ], + "outputs": [ + { + "script": "OP_RETURN deadbeef", + "value": 1000 + } + ] + }, + { + "exception": "Unknown prevOutScriptType \"notvalidtype\"", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "prevTxScript": "OP_RETURN deadbeef", + "signs": [ + { + "prevOutScriptType": "notvalidtype", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "throws": true + } + ] + } + ], + "outputs": [ + { + "script": "OP_RETURN deadbeef", + "value": 1000 + } + ] + }, { "description": "Transaction w/ no outputs (but 1 SIGHASH_NONE)", "exception": "Transaction needs outputs", diff --git a/test/transaction_builder.js b/test/transaction_builder.js index fd6efa1..a135cca 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -104,7 +104,7 @@ function construct (f, dontSign, useOldSignArgs) { // TODO: Remove loop in v6 for (const useOldSignArgs of [ false, true ]) { - // Search for "// TODO: Remove me in v6" + // Search for "useOldSignArgs" // to find the second part of this console.warn replace let consoleWarn; if (useOldSignArgs) { @@ -426,6 +426,49 @@ for (const useOldSignArgs of [ false, true ]) { assert.strictEqual(txb.build().toHex(), '0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a473044022012a601efa8756ebe83e9ac7a7db061c3147e3b49d8be67685799fe51a4c8c62f02204d568d301d5ce14af390d566d4fd50e7b8ee48e71ec67786c029e721194dae3601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff01a0860100000000001976a914000000000000000000000000000000000000000088ac00000000') }) + it('fails when missing required arguments', () => { + let txb = new TransactionBuilder() + txb.setVersion(1) + txb.addInput('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 1) + txb.addOutput('1111111111111111111114oLvT2', 100000) + assert.throws(() => { + txb.sign() + }, /TransactionBuilder sign first arg must be TxbSignArg or number/) + assert.throws(() => { + txb.sign({ + prevOutScriptType: 'p2pkh', + vin: 1, + keyPair, + }) + }, /No input at index: 1/) + assert.throws(() => { + txb.sign({ + prevOutScriptType: 'p2pkh', + keyPair, + }) + }, /sign must include vin parameter as Number \(input index\)/) + assert.throws(() => { + txb.sign({ + prevOutScriptType: 'p2pkh', + vin: 0, + keyPair: {}, + }) + }, /sign must include keyPair parameter as Signer interface/) + assert.throws(() => { + txb.sign({ + prevOutScriptType: 'p2pkh', + vin: 0, + keyPair, + hashType: 'string', + }) + }, /sign hashType parameter must be a number/) + if (useOldSignArgs) { + assert.throws(() => { + txb.sign(0) + }, /sign requires keypair/) + } + }) + fixtures.invalid.sign.forEach(f => { it('throws ' + f.exception + (f.description ? ' (' + f.description + ')' : ''), () => { const txb = construct(f, true) diff --git a/ts_src/transaction_builder.ts b/ts_src/transaction_builder.ts index 7d47ad3..c486285 100644 --- a/ts_src/transaction_builder.ts +++ b/ts_src/transaction_builder.ts @@ -958,13 +958,20 @@ function checkSignArgs(inputs: TxbInput[], signParams: TxbSignArg): void { `Unknown prevOutScriptType "${signParams.prevOutScriptType}"`, ); } - typeforce( - typeforce.tuple( - typeforce.Number, - typeforce.maybe(typeforce.Number), - types.Signer, - ), - [signParams.vin, signParams.hashType, signParams.keyPair], + tfMessage( + typeforce.Number, + signParams.vin, + `sign must include vin parameter as Number (input index)`, + ); + tfMessage( + types.Signer, + signParams.keyPair, + `sign must include keyPair parameter as Signer interface`, + ); + tfMessage( + typeforce.maybe(typeforce.Number), + signParams.hashType, + `sign hashType parameter must be a number`, ); const prevOutType = (inputs[signParams.vin] || []).prevOutType; const posType = signParams.prevOutScriptType;