bitcoinjs / coinselect

An unspent transaction output (UTXO) selection module for bitcoin.
MIT License
178 stars 101 forks source link

p2sh(p2spkh) to p2sh(p2wsh)multi transaction error when using coinselect #31

Closed PeterGarner closed 6 years ago

PeterGarner commented 6 years ago

I've 'manually' tested a p2sh(p2wpkh) to p2sh(p2wsh)multi transaction push to an api which worked fine. The transaction can be seen on this multi address (should be the first of not only): 2NAYnkhAQ6ctSfsXf37McRo2T6ShUayEBhc

I then tried a slightly more complex transaction to the same address using coinselect which suppled multiple inputs and outputs as expected. The transaction decoded also looks good but I'm getting the following stack error and some apis are saying there are no inputs at all:

Possibly unhandled Error: Validation Error: BitcoindException(super=com.neemre.btcdcli4j.core.BitcoindException: Error #-26: 18: txn-mempool-conflict, code=-26) at Object.ensureErrorObject (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/util.js:261:20) at Promise._rejectCallback (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/promise.js:472:22) at Promise._settlePromiseFromHandler (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/promise.js:516:17) at Promise._settlePromiseAt (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/promise.js:584:18) at Promise._settlePromises (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/promise.js:700:14) at Async._drainQueue (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/async.js:123:16) at Async._drainQueues (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/async.js:133:10) at Immediate.Async.drainQueues (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/async.js:15:14) at runCallback (timers.js:810:20) at tryOnImmediate (timers.js:768:5) at processImmediate [as _immediateCallback] (timers.js:745:5) My hex is:

020000000001028fc38732d0b82585cdf4c75217609aaca03e2cc20f9ed9bed7d09491745fab7100000000171600143a7efe8788baac9747ba259e95987bdaf12bd469ffffffff69611aca749c8ff67dc425ca45e6b030741c41aa61eed9251fa429ee402e6b8101000000171600143a7efe8788baac9747ba259e95987bdaf12bd469ffffffff0250bb25010000000017a914bdcc8fa3456a212caa2c3b7ef8d0f8b24841a5e187d0cd4d000000000017a91436f6eb8e1f4d67d02aca3c96b334a320fda4bc328702483045022100d5d1147eb35d4ada7b8435b4b8088174fd45cb89cafcb5ccb36030c99f42228f022067827ec3f9f40ccc93897bf7f1ec95398995071af8fadb2d869511a68b3626700121036d3f74d39e6d4cb0695b99e134a207be9f980c0e4e24931a0be1403a40891da70247304402200f1b91f65b27f97c1817b62a18041caae95c85fc0e3ed1d72dc834d358f7dc2702206a0a3f7a833008cf8abaadc006f9de630b151cd12c7b6ff160be1802f3eb86e90121036d3f74d39e6d4cb0695b99e134a207be9f980c0e4e24931a0be1403a40891da700000000

My code is (the p2sh(p2wsh)multi process is below this):

function rng() { return Buffer.from('zzzzzzzzzzzzzzzzzwwwzzzzzzzzzzzz') } // sender
const keyPair_New = bitcoin.ECPair.makeRandom({ rng: rng, network: testnet })
// //2MxFrGxKtuqAYy8ZEsbBpD73L6eEz67Rrjp

const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: keyPair_New.publicKey, network: testnet })
const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh, network: testnet })

let feeRate = 70 // satoshis per byte from https://bitcoinfees.earn.com/api
let utxos = [{
        address: '2MxFrGxKtuqAYy8ZEsbBpD73L6eEz67Rrjp',
        txid: '01b106defc8c785676f4bdac194a49fb55a908146a660f0d9841b13e32dee5d3',
        vout: 0,
        scriptPubKey: 'a91436f6eb8e1f4d67d02aca3c96b334a320fda4bc3287',
        amount: 0.0203125,
        satoshis: 2031250,
        confirmations: 0,
        ts: 1534008290
    },
    {
        address: '2MxFrGxKtuqAYy8ZEsbBpD73L6eEz67Rrjp',
        txid: '085abb08e50c4225a282dbdccea778dd29c57ee46f0a0d49357e53381b8a42eb',
        vout: 1,
        scriptPubKey: 'a91436f6eb8e1f4d67d02aca3c96b334a320fda4bc3287',
        amount: 0.040625,
        satoshis: 4062500,
        confirmations: 0,
        ts: 1534008276
    },
    {
        address: '2MxFrGxKtuqAYy8ZEsbBpD73L6eEz67Rrjp',
        txid: '816b2e40ee29a41f25d9ee61aa411c7430b0e645ca25c47df68f9c74ca1a6169',
        vout: 1,
        scriptPubKey: 'a91436f6eb8e1f4d67d02aca3c96b334a320fda4bc3287',
        amount: 0.08125,
        satoshis: 8125000,
        confirmations: 0,
        ts: 1534008264
    },
    {
        address: '2MxFrGxKtuqAYy8ZEsbBpD73L6eEz67Rrjp',
        txid: '71ab5f749194d0d7bed99e0fc22c3ea0ac9a601752c7f4cd8525b8d03287c38f',
        vout: 0,
        scriptPubKey: 'a91436f6eb8e1f4d67d02aca3c96b334a320fda4bc3287',
        amount: 0.1625,
        satoshis: 16250000,
        confirmations: 0,
        ts: 1534007890
    }
]
let targets = [{
    address: '2NAYnkhAQ6ctSfsXf37McRo2T6ShUayEBhc',
    satoshis: 19250000

}]

let { inputs, outputs, fee } = coinSelect(utxos, targets, feeRate)

if (!inputs || !outputs) return

let txb = new bitcoin.TransactionBuilder(testnet)

inputs.forEach(input => txb.addInput(input.txid, input.vout))

 outputs.forEach(output => {
     if (!output.address) {
         output.address = '2MxFrGxKtuqAYy8ZEsbBpD73L6eEz67Rrjp'
     }
     txb.addOutput(output.address, output.satoshis)
     console.log(output.address, output.satoshis)
 }) 

var n = inputs.length;
 for (var i = 0; i < n ; i++) {
     console.log(i)
      txb.sign(i, keyPair_New, p2sh.redeem.output, null, inputs[i].satoshis)
 }
const tx = txb.build()
const txt = tx.toHex()
pushtx.pushtx(txt)

// ==================
// create multi address (not part of the above script):

function gnr() { return Buffer.from('zzzzzzzzzzzzzzzzzyyyzzzzzzzzzzzz') } // signer
const keyPairR = bitcoin.ECPair.makeRandom({ rng: gnr, network: testnet })

function rng() { return Buffer.from('zzzzzzzzzzzzzzzzzxxxzzzzzzzzzzzz') } // co-signer 
const keyPairCR = bitcoin.ECPair.makeRandom({ rng: rng, network: testnet })

const pubkeys = [keyPairR.publicKey, keyPairCR.publicKey];
 const { address } = bitcoin.payments.p2sh({
     redeem: bitcoin.payments.p2wsh({
         redeem: bitcoin.payments.p2ms({ m: 2, pubkeys, network: bitcoin.networks.testnet }),
         network: bitcoin.networks.testnet
     }), network: bitcoin.networks.testnet
})
// save address for creating transaction 
PeterGarner commented 6 years ago

please hold off on this - this is the wrong stack trance. I will reproduce the correct one and update. The trace is like this but I'll get one associated to its trans hex and post:

Possibly unhandled Error: Validation Error: BitcoindException(super=com.neemre.btcdcli4j.core.BitcoindException: Error #-26: 16: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element), code=-26) at Object.ensureErrorObject (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/util.js:261:20) at Promise._rejectCallback (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/promise.js:472:22) at Promise._settlePromiseFromHandler (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/promise.js:516:17) at Promise._settlePromiseAt (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/promise.js:584:18) at Promise._settlePromises (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/promise.js:700:14) at Async._drainQueue (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/async.js:123:16) at Async._drainQueues (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/async.js:133:10) at Immediate.Async.drainQueues (/Users/peter/Desktop/MSC_Project_writeup/script_files/back-end/node_modules/request-promise/node_modules/bluebird/js/main/async.js:15:14) at runCallback (timers.js:810:20) at tryOnImmediate (timers.js:768:5) at processImmediate [as _immediateCallback] (timers.js:745:5)

PeterGarner commented 6 years ago

ok. confirmations.. works when I form transactions only from confimed txids.
So you can't spend money you don't own? Who would have thought.. Is there a config option to have conselect only select txids with min conf 1?

dcousens commented 6 years ago

@PeterGarner there isn't an option, but, is there any reason you feel you can't pre-filter them yourself?

works when I form transactions only from confimed txids.

That shouldn't necessarily be the case, and specifically isn't the error provided above (bad script).

PeterGarner commented 6 years ago

@dcousens, none at all, for your first point. For you second, I haven't seen any errors since filtering zeros but the errors I did see were probably due to issues with the addresses I was trying to use at the time (or just bad scripting). Regarding my bad script, if you were just referring to my amateur syntax, then sorry but I'm as new to nodejs as I am to your libraries and have just been focusses on getting things working. However, if there is a specific programatic step which looks bad please let me know. The only problem I have now with coinselect is that I need to explain how it works in my thesis..

dcousens commented 6 years ago

core.BitcoindException: Error #-26: 16: mandatory-script-verify-flag-failed

That means the script (an input) that you provided bitcoind is bad, aka, invalid. I don't know what part is wrong though. It may be that you were providing an unknown/invalid txId.

PeterGarner commented 6 years ago

You can close this if you wish. I'm not seeing that error anymore and cannot recreate it.