BTCGPU / bitcoinjs-lib

Bitcoin-related functions implemented in pure JavaScript
MIT License
1 stars 3 forks source link

Outdated example for BTG transaction building #12

Closed vladikus10 closed 3 years ago

vladikus10 commented 5 years ago

I'm trying to build a transaction and having trouble with it. The main problem is that I to need pass the previous output script when adding an input, but in the example it shows to generate it like so:

var spk = bscript.pubKeyHash.output.encode(pk)

The problem is that the script module does not have such methods. Am I missing something here?

For now I tried adding the script as a hex (example: 76a9149b8e198b50e72f4f00834db85cf0ef09f05a70a188ac) and converting it to Buffer :

tx.addInput(tx_id, index, Transaction.DEFAULT_SEQUENCE, Buffer.from(script, 'hex'));

But I still get:

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

FYI: I'm trying to build a BTG testnet tx.

Vutov commented 5 years ago

Could you please provide a link to the example in question? Since it is BTG testnet the full code for building the transaction will be useful to identify the issue. Looking at it, it seems the signature is bad.

If the example you are talking about is https://github.com/BTCGPU/bitcoinjs-lib/blob/master/test/bitcoingold.test.js#L12, then bitcoin.script is referred as bcrypto = require('../src/crypto'), so it should be something like this bitcoin.script.pubKeyHash.output.encode (https://www.screencast.com/t/lZ4IfYCmfv)

vladikus10 commented 5 years ago

Hi, thank you for the reply, yes I am talking about that example and I'm not sure if I'm looking at the wrong code, but not the src/script.js or the src/crypto.js has a pubKeyHash object. Weird thing, it actually works, even if VSCode says that pubKeyHash does not exist there. Anyway I did notice that I do get the same result if I simply use the hex version of the script from the explorer, but I guess it does simplify things a bit. Bad news, I still get the error.

So basically this is how I'm building and signing the transaction now:

const BTG = require('bgoldjs-lib');
const BigInteger = require('bigi');
const network = BTG.networks.bitcoingoldtestnet;

function transaction(options) {

    let { outputs, inputs, privateKey } = options;

    const d = BigInteger.fromHex(privateKey);
    const key = new ECPair(d, null, { network });

    const tx = new TransactionBuilder(network);
    tx.setVersion(2);
    tx.enableBitcoinGold(true);

    const pk = crypto.hash160(key.getPublicKeyBuffer())
    const spk = BTG.script.pubKeyHash.output.encode(pk);

    outputs.forEach(o => tx.addOutput(o.address, o.satoshis));

    let index = 0;
    inputs.forEach(i => {
        tx.addInput(i.txId, i.index, Transaction.DEFAULT_SEQUENCE, spk);
        tx.sign(index++, key, null, Transaction.SIGHASH_ALL | Transaction.SIGHASH_FORKID, i.satoshis);
    });

    console.log(tx.build().toHex());
}

transaction({
    inputs: [{
        txId: 'c16cd172425f316caf4eb6178c6e8ef588a9a9eeb638c13df6b5b70950f5ee27',
        index: 0,
        satoshis: 999000
    }],
    outputs: [{
        address: 'muhTG44qkccVHRyQR5r7QyWYUXiQv7KDng',
        satoshis: 998000
    }],
    privateKey: 'a8e4e0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxaf161e'
});

FYI: Yes, all of the variables, like tx id , private key are correct, as tried using coinbin and successfully signed and broadcasted the transaction there. I did notice the signatures, were slightly different. One other thing I noticed (based on the source code), coinbin only used SIGHASH_ALL without SIGHASH_FORKID (which I also tried, without success).

Vutov commented 5 years ago

I've took your code and changed a little to verify it works

const BTG = require('./src');
const BigInteger = require('bigi');
const network = BTG.networks.bitcoingoldregtest;

function transaction(options) {

    let { outputs, inputs, privateKey } = options;

    //const d = BigInteger.fromHex(privateKey);
    const key = BTG.ECPair.fromWIF(privateKey, network) //new ECPair(d, null, { network });

    const tx = new BTG.TransactionBuilder(network);
    tx.setVersion(2);
    tx.enableBitcoinGold(true);

    const pk = BTG.crypto.hash160(key.getPublicKeyBuffer())
    const spk = BTG.script.pubKeyHash.output.encode(pk);

    outputs.forEach(o => tx.addOutput(o.address, o.satoshis - 10000));  // fee of 10 000

    let index = 0;
    inputs.forEach(i => {
        tx.addInput(i.txId, i.index, BTG.Transaction.DEFAULT_SEQUENCE, spk);
        tx.sign(index++, key, null, BTG.Transaction.SIGHASH_ALL | BTG.Transaction.SIGHASH_FORKID, i.satoshis);
    });

    console.log(tx.build().toHex());
}

transaction({
  inputs: [{
      txId: '82b100e14aabef6384658ed75b12d5171819488f355521aace2ebddb36935d4f',
      index: 0,
      satoshis: 10 * 1e8
  }],
  outputs: [{
      address: 'n4CfVKAHMq7w4sZENT3kZxMNyrfPaHCPLt',
      satoshis: 10 * 1e8
  }],
  privateKey: 'cV5B1ZdWc9z6krqM2XwJrPzWt6HhRgur2MKpAhEYvwGgrBCXyuwe' // WIF
});

I've changed to regtest, because I have fast setup on my pc with it. In addition changed privateKey to WIF for the same reasons (dumpprivkey) and included fee on the output transaction. The result is:


17:53:41

decoderawtransaction 02000000014f5d9336dbbd2eceaa2155358f48191817d5125bd78e658463efab4ae100b182000000006b483045022100a5e913fd1ae6cab60f22d1b5cb05f28ba59620ab46fffbc77c8ff1f82ad45fc202207f6da4ac210a1dddbd74254cf3a9248b498e97b6aac205ac37bb8951f24c5b2d412102d1aa992cd5fe4d60aa674e06494334421e71d1711f43e75545cd20f0ef3060d7ffffffff01f0a29a3b000000001976a914f8d5607b9af11337d371bdad7a2075372aa1277388ac00000000

17:53:41

{
  "txid": "fc4e29c051e6dd75f46f3f33b0dea17059a63435c89f007b00e38cca2f9997b7",
  "hash": "fc4e29c051e6dd75f46f3f33b0dea17059a63435c89f007b00e38cca2f9997b7",
  "version": 2,
  "size": 192,
  "vsize": 192,
  "locktime": 0,
  "vin": [
    {
      "txid": "82b100e14aabef6384658ed75b12d5171819488f355521aace2ebddb36935d4f",
      "vout": 0,
      "scriptSig": {
        "asm": "3045022100a5e913fd1ae6cab60f22d1b5cb05f28ba59620ab46fffbc77c8ff1f82ad45fc202207f6da4ac210a1dddbd74254cf3a9248b498e97b6aac205ac37bb8951f24c5b2d[ALL|FORKID] 02d1aa992cd5fe4d60aa674e06494334421e71d1711f43e75545cd20f0ef3060d7",
        "hex": "483045022100a5e913fd1ae6cab60f22d1b5cb05f28ba59620ab46fffbc77c8ff1f82ad45fc202207f6da4ac210a1dddbd74254cf3a9248b498e97b6aac205ac37bb8951f24c5b2d412102d1aa992cd5fe4d60aa674e06494334421e71d1711f43e75545cd20f0ef3060d7"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 9.99990000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 f8d5607b9af11337d371bdad7a2075372aa12773 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914f8d5607b9af11337d371bdad7a2075372aa1277388ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "n4CfVKAHMq7w4sZENT3kZxMNyrfPaHCPLt"
        ]
      }
    }
  ]
}

17:55:18

sendrawtransaction 02000000014f5d9336dbbd2eceaa2155358f48191817d5125bd78e658463efab4ae100b182000000006b483045022100a5e913fd1ae6cab60f22d1b5cb05f28ba59620ab46fffbc77c8ff1f82ad45fc202207f6da4ac210a1dddbd74254cf3a9248b498e97b6aac205ac37bb8951f24c5b2d412102d1aa992cd5fe4d60aa674e06494334421e71d1711f43e75545cd20f0ef3060d7ffffffff01f0a29a3b000000001976a914f8d5607b9af11337d371bdad7a2075372aa1277388ac00000000

17:55:18

fc4e29c051e6dd75f46f3f33b0dea17059a63435c89f007b00e38cca2f9997b7

I suspect the issue comes from the type of the address of your UTXO. At first I had

17:45:55

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

using some old UTXO (guessing p2sh) . Once I created new transaction and send it to the other node with p2wpkh it worked as shown above.

@h4x3rotab Can share more light on the addresses, I'm always confusing them around.

h4x3rotab commented 5 years ago

Have you checked if the outputs you wanted to spend are P2PKH?

vladikus10 commented 5 years ago

Hi, yes, here is the raw UTXO from the explorer (tx hash: c16cd172425f316caf4eb6178c6e8ef588a9a9eeb638c13df6b5b70950f5ee27):

n: 0
scriptPubKey: {
     addresses: ["mnwyf8eEHjvgoLa5kF5gH2hZQBiKDv3qRz"]
     asm: "OP_DUP OP_HASH160 51846aebbe0628700e8a8ae91d12881646eb3ff4 OP_EQUALVERIFY OP_CHECKSIG"
     hex: "76a91451846aebbe0628700e8a8ae91d12881646eb3ff488ac"
     type: "pubkeyhash"
}
spentHeight: null
spentIndex: null
spentTxId: null
value: "0.09990000"
vladikus10 commented 5 years ago

So I got a chance to try the code on the mainnet, and what do you know, it worked like a charm from the first attempt, so I'm not quite sure what went wrong on the testnet.

h4x3rotab commented 5 years ago

I would re-open the issue and leave it for future investigation