Bitcoinjs-lib: Bitcoin Cash Support

Created on 8 Nov 2017  Â·  29Comments  Â·  Source: bitcoinjs/bitcoinjs-lib

Do you guys have any plans to merge the bitcoin cash support into the main branch? Currently, anybody trying to support both Segwit and BCH signing needs to require two separate library versions.

how to / question / docs

Most helpful comment

Hi Arik,

Unfortunately, the answer is no.

Segwit is merged because bitcoin supports segwit.

SIGHASH_FORKID is not used at all in bitcoin, so merging it would open the floodgates for "oh, why don't you merge all this extra code for altcoin-xyz? You did it for bitcoin cash!"

@afk11 could update his branch to rebase on master though.

All 29 comments

Hi Arik,

Unfortunately, the answer is no.

Segwit is merged because bitcoin supports segwit.

SIGHASH_FORKID is not used at all in bitcoin, so merging it would open the floodgates for "oh, why don't you merge all this extra code for altcoin-xyz? You did it for bitcoin cash!"

@afk11 could update his branch to rebase on master though.

As pointed our perfectly by @dabura667, if we support altcoins, we'd support altcoins.
At this time, we are striving to be generic enough to easily support the addition of altcoin changes, where practical and where it doesn't introduce extra complexity.

We do NOT intend to merge them out right, and it is merely a convenience of the past that networks used to contain many different alt coins.

Thanks, @dabura667! I really appreciate you rebasing 3.3.0 onto it.

Also, thanks to @dabura667 for rebasing. I think this effort will be well spent as bitcoin cash is gaining traction and momentum. I wouldn't outright characterize it as an "alt-coin" though, as it is not only the codebase that is forked, but the ledger, ecosystem, etc.

As this is so contentious, I don't want to open this can of worms, but rather just to comment and thank any support for neutrality.

I'm not really sure if this is a good place to raise a question but this seems to be the best one for now.

From what I understand, the way of generating Bitcoin and Bitcoin Cash addresses is same, which makes it safe to use the same keys and same addresses for both. (Am I right?) But I keep failing to create a simple transaction using that fork @dcousens made some commits to.

This is my sample code.

const bip39 = require('bip39')
const bitcoin = require('./lib/bitcoincashjs-lib/src')
const config = require('./config')[process.env.NODE_ENV || 'development']

const network = bitcoin.networks['testnet']

const mnemonic = config.app.mnemonic
const password = config.app.password
const seed = bip39.mnemonicToSeed(mnemonic, password)
const master = bitcoin.HDNode.fromSeedBuffer(seed, network)

const node = master.derivePath(`m/44'/1'/0'/0/1`)
const keyPair = node.keyPair

const pk = keyPair.getPublicKeyBuffer()
const spk = bitcoin.script.pubKey.output.encode(pk)

const txb = new bitcoin.TransactionBuilder(network)

const amount = 1290000000

txb.addInput(
  'aef0dd1660abe220c7ce458d0a71ed67442dbb7f9d0b98b83ce75557b1d98b06',
  0,
  bitcoin.Transaction.DEFAULT_SEQUENCE,
  spk
)
txb.addOutput('mgRoeWs2CeCEuqQmNfhJjnpX8YvtPACmCX', amount)
txb.enableBitcoinCash(true)
txb.setVersion(2)

const hashType =
  bitcoin.Transaction.SIGHASH_ALL |
  bitcoin.Transaction.SIGHASH_BITCOINCASHBIP143

txb.sign(0, keyPair, null, hashType, amount)

const tx = txb.build()
const hex = tx.toHex()
console.log(hex)

For creating mnemonic words (which is a constants in my config), converting them to seed and HDNode, I referred to Ian Coleman's repo, and for a signing part, I referred to the test from the forked repo. You can always refer my address and the transaction to the explorer.

The result hex is as follows. (And I can't seem to find where to decode this transaction.)

0200000001068bd9b15755e73cb8980b9d7fbb2d4467ed710a8d45cec720e2ab6016ddf0ae0000000049483045022100ebd54c321ecc33c9153cf5f9bace6a93d83a4ef34156775f02c3dc1104d09c4702206e980c99f70a3143b06756f284cf3e2bae0568c396a707bbd5c78c6b38bdb42941ffffffff0180d6e34c000000001976a91409fed3e08e624b23dbbacc77f7b2a39998351a6888ac00000000

When I try to send my raw transaction to Bitcoin-ABC, it says this. And from what I googled on, this is the result of wrong signing.

error code: -26
error message:
16: mandatory-script-verify-flag-failed (Script failed an OP_EQUALVERIFY operation)

Not sure if this might help but when I lower my amount, the error says this.

error code: -26
error message:
256: absurdly-high-fee

For now I'm not quite sure what I am doing wrong. If there's any direct way to reach for help, I'd definitely do. Thanks.

txb.addOutput('mgRoeWs2CeCEuqQmNfhJjnpX8YvtPACmCX', amount)

This is how much you want to send to mgRoeWs2CeCEuqQmNfhJjnpX8YvtPACmCX.

txb.sign(0, keyPair, null, hashType, amount)

This is how much the input value is worth.

You should not be using the same value for both, as the amount you pass to sign is constant. The transaction aef0dd1660abe220c7ce458d0a71ed67442dbb7f9d0b98b83ce75557b1d98b06 is already in the blockchain and the value of output # 0 is already set in stone. You can't change it.

https://www.blocktrail.com/tBCC/tx/aef0dd1660abe220c7ce458d0a71ed67442dbb7f9d0b98b83ce75557b1d98b06

Looking here: it should be

txb.sign(0, keyPair, null, hashType, 13 * 1e8)

also, you are sending to a P2PK output... you want to send to P2PKH.

const pk = keyPair.getPublicKeyBuffer()
const pkh = bitcoin.crypto.hash160(pk)
const spk = bitcoin.script.pubKeyHash.output.encode(pkh)

@dabura667 Thanks a million. That totally generated a valid transaction and I could broadcast it to Bitcoin Cash testnet.

You should set a lower fee. Bitcoin Cash is fine with 1 satoshi/byte. 191 satoshis would have been a good enough fee.

You can easily estimate how large a transaction will be by knowing the number and types of inputs and outputs.

@leehankyeol
Here's what I use. It also supports coins with segwit in them.

Usage:
getByteCount({'MULTISIG-P2SH:2-4':45},{'P2PKH':1}) Means "45 inputs of P2SH Multisig and 1 output of P2PKH"
getByteCount({'P2PKH':1,'MULTISIG-P2SH:2-3':2},{'P2PKH':2}) means "1 P2PKH input and 2 Multisig P2SH (2 of 3) inputs along with 2 P2PKH outputs"

function getByteCount(inputs, outputs) {
    var totalWeight = 0
    var hasWitness = false
    // assumes compressed pubkeys in all cases.
    var types = {
        'inputs': {
            'MULTISIG-P2SH': 49 * 4,
            'MULTISIG-P2WSH': 6 + (41 * 4),
            'MULTISIG-P2SH-P2WSH': 6 + (76 * 4),
            'P2PKH': 148 * 4,
            'P2WPKH': 108 + (41 * 4),
            'P2SH-P2WPKH': 108 + (64 * 4)
        },
        'outputs': {
            'P2SH': 32 * 4,
            'P2PKH': 34 * 4,
            'P2WPKH': 31 * 4,
            'P2WSH': 43 * 4
        }
    }

    Object.keys(inputs).forEach(function(key) {
        if (key.slice(0,8) === 'MULTISIG') {
            // ex. "MULTISIG-P2SH:2-3" would mean 2 of 3 P2SH MULTISIG
            var keyParts = key.split(':')
            if (keyParts.length !== 2) throw new Error('invalid input: ' + key)
            var newKey = keyParts[0]
            var mAndN = keyParts[1].split('-').map(function (item) { return parseInt(item) })

            totalWeight += types.inputs[newKey] * inputs[key]
            var multiplyer = (newKey === 'MULTISIG-P2SH') ? 4 : 1
            totalWeight += ((73 * mAndN[0]) + (34 * mAndN[1])) * multiplyer
        } else {
            totalWeight += types.inputs[key] * inputs[key]
        }
        if (key.indexOf('W') >= 0) hasWitness = true
    })

    Object.keys(outputs).forEach(function(key) {
        totalWeight += types.outputs[key] * outputs[key]
    })

    if (hasWitness) totalWeight += 2

    totalWeight += 10 * 4

    return Math.ceil(totalWeight / 4)
}

@dabura667 Really appreciate your help. Thanks. Happy new year.

Hi, I'm trying to create simple 1-to-1 transaction as follows. But adding an output fails with has no matching Script. The issue I'm facing is similar to this issue , which is solved by adding the network parameter. Adding the network parameter as networks.bitcoincash doesnt work for me
I'm using the rebased library for bitcoin cash created by @dabura667.

Any help is much appreciated.

var bchlib = require('bitcoinjs-lib');

let txnBuilder = new bchlib.TransactionBuilder(bchlib.networks.bitcoincash);
txnBuilder.enableBitcoinCash(true);
txnBuilder.addInput(txid,vout);
txnBuilder.addOutput(legacyAddress,amount-fees);
txnBuilder.sign(0,keyPair);

@shravan-shandilya Using bitcoincash-js is probably the easiest way to go, pretty sure I saw someone fork it.

@dcousens @dabura667 would you guy say that the current policy of bitcoinjs-lib is to follow BitcoinCore ?

@rbndg Please refrain from attempting to start a flame war.

I'm sorry, I should have phrased it better.

@rbndg phrasing was fine?

And yes! We follow Bitcoin-Core in terms of policy.
If you are referring to consensus rules, we follow the "Bitcoin" consensus maintained by the general community (and as codified in Bitcoin Core).

To avoid a flame war, I'm simply going to suggest that we are probably following the consensus rules of a "Bitcoin" with the largest median market cap over 200 days. But, if that ever becomes controversial, I have no doubt there will be many discussions.

We don't hesitate to enable our datastructures to be generalized to support the other forks however.

Thanks, @dcousens !

It sounded like, from context, that he was referring to Bitcoin the currency as BitcoinCore. (Since we were talking about BitcoinCash and not Bitcoin ABC)

But yeah, everything @dcousens said, pretty much

@shravan-shandilya @rbndg and any BCH devs having compatibility issues,

If you're building exclusively on BCH, I'd recommend checking out https://www.bitbox.earth/bitboxcli/ and the associated repos in https://github.com/bigearth/ . I believe it's the fork of bitcoincash-js that @afk11 was referring to. They're building an entire suite of tools for BCH development. This includes replacements for a lot of the Bitpay tools. The'yve already started adding support for the new opcodes that were added/re-enabled during the most recent hard fork.

Also, thanks to the maintainers of this great library. It's hard to keep sanity when politics try to creep in.

@dabura667 Please i need help what am i missing here?

js const tx = new bitcoincashjs.TransactionBuilder(network) var path = var account = root.derivePath("m/44'/145'/0/0") const keyPair = path.keyPair const pk = keyPair.getPublicKeyBuffer() const pkh = bitcoincashjs.crypto.hash160(pk) const spk = bitcoincashjs.script.pubKeyHash.output.encode(pkh) tx.addInput(txid, vout, bitcoincashjs.Transaction.DEFAULT_SEQUENCE, spk) tx.addOutput(receivingAddress, sending_amount_sat) tx.addOutput(change_address, change_amount) const hashType = bitcoincashjs.Transaction.SIGHASH_ALL | bitcoincashjs.Transaction.SIGHASH_BITCOINCASHBIP143 tx.sign(0, keyPair, null, hashType, sending_amount_sat) const transact = tx.build().toHex()

I get this error message when i trying broadcasting through bch insight
bash 16: mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation). Code:-26

Just FYI for anyone following this thread:

I "rebased" (actually, re-implemented... since 5.1.2 is so different.) on v5.1.2

TypeScript support, PSBT support, all sorts of goodies for BCH and BTG.

https://github.com/junderw/bitcoinjs-lib/tree/cashv5

See the bitcoincash and bitcoingold test files for Psbt usage.

Rather than have a method to mess with sighashtype on Psbt... since the Psbt natively holds a 32 bit hashtype, I made the default accepted sighashes to include SIGHASH_ALL for BCH and BTG.

And also had to do some messing around with the fact that BCH and BTG both sign the value, so they can always use witnessUtxo instead of nonWitnessUtxo. (I originally had the assumption that using witnessUtxo === isSegwit. But with BCH and BTG that isn't the case...

BTG does support segwit though... but I haven't tested it yet.

Any tests are welcome if you'd like to write them, make a PR to my branch up there.

I will go ahead and keep cashv5 branch updated to the latest patch.

cash512 is already old and cash515 is latest... but I'll just point cashv5 to the latest patch I have rebased to.

https://github.com/junderw/bitcoinjs-lib/tree/cashv5

@naro-code-lab I see the same error now

16: mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation). Code:-26

was ok several days ago. Using https://blockdozer.com/insight-api/
Found a solution?

As I see, there was a Bitcoin Cash Hardfork several days ago, so that's maybe related...

No, false alarm. Just switched to rest.bitcoin.com without updating bitcoinjs-lib — all's working now. https://bitcoin-message.com/ 😎

https://github.com/BitGo/BitGoJS/tree/master/modules/utxo-lib is still maintained - a fork of BitcoinJS Cash-compatible

Was this page helpful?
0 / 5 - 0 ratings

Related issues

thrastarson picture thrastarson  Â·  3Comments

namnv04 picture namnv04  Â·  3Comments

itsMikeLowrey picture itsMikeLowrey  Â·  3Comments

LeonYanghaha picture LeonYanghaha  Â·  3Comments

rbndg picture rbndg  Â·  3Comments