Bitcoinjs-lib: Getting keys.getPublicKeyBuffer is not a function

Created on 20 May 2019  路  19Comments  路  Source: bitcoinjs/bitcoinjs-lib

Im trying to sign a transaction for blockcypher described here, but I have run into this error and when searching around I cannot find a solution. Im trying to sign a transaction for the bitcoin testnet, here is the code im using, does anyone know what the problem could be?

var bitcoin = require("bitcoinjs-lib");
var buffer  = require('buffer');
var keys    = new bitcoin.ECPair.fromWIF('cMvPQZiG5mLARSjxbBwMxKwzhTHaxgpTsXB6ymx7SGAeYUqF8HAT', bitcoin.networks.testnet);

var newtx = {
  inputs: [{addresses: ['ms9ySK54aEC2ykDviet9jo4GZE6GxEZMzf']}],
  outputs: [{addresses: ['msWccFYm5PPCn6TNPbNEnprA4hydPGadBN'], value: 1000}]
};
// calling the new endpoint, same as above
$.post('https://api.blockcypher.com/v1/btc/test3/txs/new', JSON.stringify(newtx))
  .then(function(tmptx) {
    // signing each of the hex-encoded string required to finalize the transaction
    tmptx.pubkeys = [];
    tmptx.signatures = tmptx.tosign.map(function(tosign, n) {
      tmptx.pubkeys.push(keys.getPublicKeyBuffer().toString("hex"));
      return keys.sign(new buffer.Buffer(tosign, "hex")).toDER().toString("hex");
    });
    // sending back the transaction with all the signatures to broadcast
    $.post('https://api.blockcypher.com/v1/btc/test3/txs/send', tmptx).then(function(finaltx) {
      console.log(finaltx);
    }).catch(function (response) {
   console.log(response.responseText);
});
  }).catch(function (response) {
   console.log(response.responseText);
});

Edit: In fact it provided 'undefined' which I didnt notice before. So the full error i get is:

jQuery.Deferred exception: keys.getPublicKeyBuffer is not a function
undefined

Most helpful comment

@brandb12 How did you solve your last mentioned issue in this thread? Thanks in advance

All 19 comments

const publicKey = keys.publicKey;

It's not a function, just treat it like an attribute.

keys.getPublicKeyBuffer() is old code for v3.x.x the current version is v5.x.x

const publicKey = keys.publicKey;

It's not a function, just treat it like an attribute.

keys.getPublicKeyBuffer() is old code for v3.x.x the current version is v5.x.x

Thanks for your reply, that part seems to be working now but on the last bit it gives me this:
jQuery.Deferred exception: keys.sign(...).toDER is not a function
undefined

Is this old aswell and something I need to change?

ECPair.sign returns a Buffer now.

look at bitcoin.script.signature for some function about DER encoding.

it's called encode.

you need to pass 1 for the second arg for the sighash for SIGHASH_ALL

ECPair.sign returns a Buffer now.

look at bitcoin.script.signature for some function about DER encoding.

Would you be able to show me what I need to edit on that line? Im quite new to this a am not too clear on what I need to add. I keep getting the error {"error": "Couldn't deserialize request: invalid character 'x' in literal true (expecting 'r')"}

Im quite new to this

I hope no one puts a lot of money in your wallet then :-P

jk

This should work.

const SIGHASH_ALL = 0x01;
return bitcoin.script.signature.encode(
  keys.sign(new buffer.Buffer(tosign, "hex")),
  SIGHASH_ALL,
).toString("hex");

I hope no one puts a lot of money in your wallet then :-P

jk

Ha! I know but im learning as I go. But I still get that error {"error": "Couldn't deserialize request: invalid character 'x' in literal true (expecting 'r')"}

Here is the full updated code im using, can you see anything ive done wrong?

var bitcoin = require("bitcoinjs-lib");
var buffer  = require('buffer');
var keys    = new bitcoin.ECPair.fromWIF('cMvPQZiG5mLARSjxbBwMxKwzhTHaxgpTsXB6ymx7SGAeYUqF8HAT', bitcoin.networks.testnet);
const publicKey = keys.publicKey;

var newtx = {
  inputs: [{addresses: ['ms9ySK54aEC2ykDviet9jo4GZE6GxEZMzf']}],
  outputs: [{addresses: ['msWccFYm5PPCn6TNPbNEnprA4hydPGadBN'], value: 1000}]
};
// calling the new endpoint, same as above
$.post('https://api.blockcypher.com/v1/btc/test3/txs/new', JSON.stringify(newtx))
  .then(function(tmptx) {
    // signing each of the hex-encoded string required to finalize the transaction
    tmptx.pubkeys = [];
    tmptx.signatures = tmptx.tosign.map(function(tosign, n) {
      tmptx.pubkeys.push(publicKey.toString("hex"));

const SIGHASH_ALL = 0x01;
return bitcoin.script.signature.encode(
  keys.sign(new buffer.Buffer(tosign, "hex")),
  SIGHASH_ALL,
).toString("hex");

    });
    // sending back the transaction with all the signatures to broadcast
    $.post('https://api.blockcypher.com/v1/btc/test3/txs/send', tmptx).then(function(finaltx) {
      console.log(finaltx);
    }).catch(function (response) {
   console.log(response.responseText);
});
  }).catch(function (response) {
   console.log(response.responseText);
});

That's not an error on our end... looks like something on the API end...

That's not an error on our end... looks like something on the API end...

Ok thanks for all your help, ill give them an email.

Still no response from blockcypher, I guess they don't care about their users.

Finally I seemed to have solved the problem, but as usual that brings another problem. I now get the error when trying to send:

Error building input: Error generating scriptsig when building transaction: Invalid signature: Non-canonical signature: wrong length marker

Does this have something to do with this code?

const SIGHASH_ALL = 0x01;
return bitcoin.script.signature.encode(
  keys.sign(new buffer.Buffer(tosign, "hex")),
  SIGHASH_ALL,
).toString("hex");

I have no clue. I have never used blockcypher.

@brandb12 How did you solve your last mentioned issue in this thread? Thanks in advance

Finally I seemed to have solved the problem, but as usual that brings another problem. I now get the error when trying to send:

Error building input: Error generating scriptsig when building transaction: Invalid signature: Non-canonical signature: wrong length marker

Does this have something to do with this code?

const SIGHASH_ALL = 0x01;
return bitcoin.script.signature.encode(
  keys.sign(new buffer.Buffer(tosign, "hex")),
  SIGHASH_ALL,
).toString("hex");

I'm getting the same problem. Have you solved it? Any response from blockcypher?

Hi @fedecaccia, @vineettyagi28, @brandb12 apologies if no one answered you at BlockCypher.
The reason why it fails is because BlockCypher adds the SIGHASH_ALL automatically.
Here is a quick way to fix it.

                            return bitcoin.script.signature.encode(
                                keys.sign(new buffer.Buffer(tosign, "hex")),
                                0x01,
                                ).toString("hex").slice(0, -2);

I'll update the doc accordingly.

Hi @quentinlesceller thanks!

The final error that this produces as of 2020 is

Error: TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'ClientRequest'
    |     property 'socket' -> object with constructor 'TLSSocket'
    --- property '_httpMessage' closes the circle

here is my code:

const keyBuffer = Buffer.from(privKey, 'hex')
var keys = bitcoin.ECPair.fromPrivateKey(keyBuffer, currentNetwork)

axios.post('https://api.blockcypher.com/v1/bcy/test/txs/new', JSON.stringify(newtx))
    .then(function (tmptx) {
        console.log(tmptx.data)
        // signing each of the hex-encoded string required to finalize the transaction
        tmptx.pubkeys = [];
        tmptx.signatures = tmptx.data.tosign.map(function (tosign, n) {
            tmptx.pubkeys.push(keys.publicKey.toString('hex'));

            const SIGHASH_ALL = 0x01;

            return bitcoin.script.signature.encode(
                keys.sign(Buffer.from(tosign, "hex")),
                0x01,
            ).toString("hex").slice(0, -2);
        });
        // sending back the transaction with all the signatures to broadcast
        axios.post('https://api.blockcypher.com/v1/bcy/test/txs/send', tmptx).then(function (finaltx) {
            console.log(finaltx);
            res.end('Transaction has began')
        }).catch(err => {
            console.log('Error: ' + err)
        });
    }).catch(err => {
        console.log('Error: ' + err)
    });

tmptx contains a cyclical reference, so you can't stringify it. axios.post tries to stringify it in the background.

Remove the cyclical reference (the error tells you how) OR create a new object and only include the data you need.

I see, so include that property '_httpMessage'? @junderw
Now I just have to track it down in the object lol

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tuyennvtb picture tuyennvtb  路  3Comments

silence-may picture silence-may  路  3Comments

namnv04 picture namnv04  路  3Comments

dcousens picture dcousens  路  3Comments

Beardcoding picture Beardcoding  路  3Comments