bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.65k stars 2.09k forks source link

a transaction signed by bitcoinjs-lib can't been send to bitcoin testnet #1109

Closed gongxiaoze closed 6 years ago

gongxiaoze commented 6 years ago
var bitcoin = require("bitcoinjs-lib");

const net = bitcoin.networks.testnet;
var key = bitcoin.ECPair.fromWIF("cQe6x63QLxJUfLeTn68j9uH1WrbVNR95EBGmbKwE4i4FsTaguzhD", net);
var tx = new bitcoin.TransactionBuilder(net);

tx.setVersion(2);
tx.addInput("6a15923b65a0dbf1ff174596ba43aac04c2cf156b913f419b3eff7f2c90b4ec2", 1);
tx.addOutput("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF", 5000000);
tx.addOutput("2NC6Pf9BgVm6imomTzC5qBCEhYvc7YdprJZ", 1000000);

tx.sign(0, key);
console.log(tx.build().toHex());

16: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)

dcousens commented 6 years ago

Check that 6a15923b65a0dbf1ff174596ba43aac04c2cf156b913f419b3eff7f2c90b4ec2:1 is actually the previous transaction output you want.

If it is, you need to provide the txHex here for us to help you.

junderw commented 6 years ago

The utxo you are pulling in the input is 2NC6Pf9BgVm6imomTzC5qBCEhYvc7YdprJZ is a P2SH address.

  1. You should not reuse addresses, so sending the change 0.01 BTC to the same address is not good.
  2. It looks like your address is P2SH-P2WPKH... so to sign for it you need to do something like this:
var bitcoin = require("bitcoinjs-lib");

const net = bitcoin.networks.testnet;
var key = bitcoin.ECPair.fromWIF("cQe6x63QLxJUfLeTn68j9uH1WrbVNR95EBGmbKwE4i4FsTaguzhD", net);

// get pubkey hash for P2WPKH
var pubKeyHash = bitcoin.crypto.hash160(key.getPublicKeyBuffer());
// create P2WPKH for use as redeemScript
var redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(pubKeyHash);

var tx = new bitcoin.TransactionBuilder(net);

tx.setVersion(2);
tx.addInput("6a15923b65a0dbf1ff174596ba43aac04c2cf156b913f419b3eff7f2c90b4ec2", 1);
tx.addOutput("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF", 5000000);
// added more to the change, as "too big fee" warning was triggered
tx.addOutput("2NC6Pf9BgVm6imomTzC5qBCEhYvc7YdprJZ", 1800000);

// include the value of the input and the redeemScript
tx.sign(0, key, redeemScript, null, 6999668);

console.log(tx.build().toHex());
junderw commented 6 years ago

Here's a breakdown of the transaction (how it SHOULD look)

If you compare to your old broken transaction you will notice that all the witness info is missing.

Transaction breakdown

version
02000000
flag bytes for segwit
00
01

one input
01

txhash
c24e0bc9f2f7efb319f413b956f12c4cc0aa43ba964517fff1dba0653b92156a
vout
01000000
scriptSig length (23 bytes)
17
scriptSig (one 22 byte PUSHDATA, pushing the redeemScript on the stack)
1600145a37e361e3255a1398083a9dd583a4739fbefa93
nSequence (unused)
ffffffff

two outputs
02

Satoshi amount 5000000
404b4c0000000000
scriptPubkey length (23 bytes)
17
scriptPubkey (P2SH)
a914a9974100aeee974a20cda9a2f545704a0ab54fdc87
Satoshi amount 1800000
40771b0000000000
scriptPubkey length (23 bytes)
17
scriptPubkey (P2SH)
a914cebeb7e38de65672e6f58008f92988097435579c87

first input's witness stack is 2 pushes
02

First push is 71 bytes
47
ECDSA signature
30440220589c82a51fc6ff81c5ec8d1e9bb7a424546889bcca77b819443d871e60ee63550220665948d78b698409533d034be5ab83239e10111d8ad4de8980fb762170e8f8a101
Second push is 33 bytes
21
Compressed ECDSA public key
03e986f15a48df81c66725f52aa9d75f1c71130a3856ba8c2499d2d716eeb17ee1

nTimeLock (unused)
00000000
junderw commented 6 years ago

Here's your broken transaction... notice how it tries to spend as if the input you selected was a P2PKH. It is placing everything in the scriptSig.

version
02000000
one input
01
txhash
c24e0bc9f2f7efb319f413b956f12c4cc0aa43ba964517fff1dba0653b92156a
vout
01000000
scriptSig length (107 bytes)
6b
scriptSig (includes signature and public key)
483045022100eff0b354e8f6e77c7859bebfcfdd877a3ac6417b1c267bf304f012f6b22573820220557a29aa98558daded6664a7b4d71741156159a8d016151f3ca579b12ea531d8012103e986f15a48df81c66725f52aa9d75f1c71130a3856ba8c2499d2d716eeb17ee1
nSequence
ffffffff
two outputs
02
satoshi amount 1st output
404b4c0000000000
scriptPubkey length (23)
17
scriptPubkey
a914a9974100aeee974a20cda9a2f545704a0ab54fdc87
satoshi amount 2nd output
40420f0000000000
scriptPubkey length (23)
17
scriptPubkey
a914cebeb7e38de65672e6f58008f92988097435579c87
nLockTime
00000000
gongxiaoze commented 6 years ago

Thanks very much for your answer, very detaild, and it works. 2NC6Pf9BgVm6imomTzC5qBCEhYvc7YdprJZ is created by bitcoin-core. I just learned bitcoin, and I will work hard to learn.Thanks again. @junderw

bellaj commented 6 years ago

i've tried the code but i am getting the following error:

var pubKeyHash = bitcoin.crypto.hash160(key.getPublicKeyBuffer());
                                            ^

TypeError: key.getPublicKeyBuffer is not a function
dabura667 commented 6 years ago

@bellaj this is old code for v3.x.x

The latest version is v4.0.1 and is a different API

bellaj commented 6 years ago

Thanks @dabura667 for the clarification

ShangXoL commented 6 years ago

nice @junderw

ShangXoL commented 6 years ago

@junderw v4.0.1 have not this function "script.witnessPubKeyHash" ,can you help me?

takahser commented 5 years ago

@junderw 6999668 seems to be the witnessValue, can you elaborate on how you figured it out this value?

junderw commented 5 years ago

@takahser here:

tx.addInput("6a15923b65a0dbf1ff174596ba43aac04c2cf156b913f419b3eff7f2c90b4ec2", 1);
takahser commented 5 years ago

Ahh it's the value of the input, got it, thanks!