bitcore-lib icon indicating copy to clipboard operation
bitcore-lib copied to clipboard

Signing error when installed via yarn

Open federicobond opened this issue 9 years ago • 8 comments

Steps to reproduce:

Install bitcore-lib from yarn:

yarn add bitcore-lib

Run this code:

const bitcore = require('bitcore-lib')                                                                                                                                          

bitcore.Networks.defaultNetwork = bitcore.Networks.testnet                                                                                                                      

var pk = new bitcore.PrivateKey('cT6FmfFKhNYCmM6142G4CT6dEATHevSuk6p5Pg7phvKDtEK1AXY7')                                                                                         
var utxo = new bitcore.Transaction.UnspentOutput({                                                                                                                              
  address: 'mzkL7cMyA2rCUZYLpsuifFiFfw1hEhxgTY',                                                                                                                                
  txid: '2da788f7e564c3250e6e82575a6a2d3617b146fabd10541572459471930b91ea',                                                                                                     
  vout: 0,                                                                                                                                                                      
  scriptPubKey: '76a914d2f20302e764140d39616b1c6e5eca8c1d99d02388ac',                                                                                                           
  amount: 1.3                                                                                                                                                                   
})                                                                                                                                                                              

var tx = new bitcore.Transaction()                                                                                                                                              
  .from([utxo])                                                                                                                                                                 
  .to(new bitcore.PrivateKey().toAddress(), 1000)                                                                                                                               
  .sign(pk)

And you get this error:

./node_modules/bitcore-lib/lib/crypto/ecdsa.js:168
  if (!(r.gt(BN.Zero) && r.lt(Point.getN())) || !(s.gt(BN.Zero) && s.lt(Point.getN()))) {
          ^

TypeError: r.gt is not a function
    at ECDSA.sigError (./node_modules/bitcore-lib/lib/crypto/ecdsa.js:168:11)
    at ECDSA.verify (./node_modules/bitcore-lib/lib/crypto/ecdsa.js:271:13)
    at Function.ECDSA.verify (./node_modules/bitcore-lib/lib/crypto/ecdsa.js:293:6)
    at Object.verify (./node_modules/bitcore-lib/lib/transaction/sighash.js:126:16)
    at PublicKeyHashInput.Input.isValidSignature (./node_modules/bitcore-lib/lib/transaction/input/input.js:175:18)
    at PublicKeyHashInput.addSignature (./node_modules/bitcore-lib/lib/transaction/input/publickeyhash.js:63:21)
    at Transaction.applySignature (./node_modules/bitcore-lib/lib/transaction/transaction.js:1092:37)
    at ./node_modules/bitcore-lib/lib/transaction/transaction.js:1062:10
    at arrayEach (./node_modules/lodash/index.js:1289:13)
    at Function.<anonymous> (./node_modules/lodash/index.js:3345:13)

It looks like some packaging problem with the bn.js dependency, but I didn't have time to investigate more.

federicobond avatar Oct 20 '16 14:10 federicobond

What does yarn do differently than say, npm for a given set of dependencies? Should this be a yarn issue and not a bitcore-lib or BN issue?

kleetus avatar Feb 07 '17 18:02 kleetus

yarn generates a npm-shrinkwrap like file, that also includes hashes. This is likely related to yarn not recognizing the npm-shrinkwrap file.

braydonf avatar Feb 07 '17 18:02 braydonf

I could not reproduce this anymore.

federicobond avatar Feb 11 '17 23:02 federicobond

This is a real thing. Tried yarn cache clean and then yarn install again. Likely one of the dependencies got corrupt as it was downloading. cleaning cache and rebuilding might solve it but it does not for me. Going back to using npm to deploy was the only way I could fix it.

hortonelectric avatar Aug 24 '17 10:08 hortonelectric

I got this too, same as @hortonelectric. Had to switch to NPM.

soolaimon avatar Nov 01 '17 03:11 soolaimon

Hey @hortonelectric actually this particular lib where we're commenting, (bitcore-lib), is working with yarn. I didn't realized this was bitcore-lib and not bitcore (https://github.com/bitpay/bitcore).

To sum up: This particular issue happens for me with bitcore, but not bitcore-lib. I switched to bitcore-lib and am good to go.

soolaimon avatar Nov 01 '17 04:11 soolaimon

The issue with bitcore is stemming from the fact that they're monkeypatching bn.js's prototype with a few convenience methods, instead of forking the module (or implementing upstream).

For example, using the following package.json and the code in OP:

{
  "private": true,
  "dependencies": {
    "bitcore-lib": "0.14.0",
    "bn.js": "4.11.8"
  }
}

With yarn, [email protected], a dependency of bitcore, is installed locally in bitcore-lib/node_modules, but [email protected], another dependency of bitcore, is installed in the root node_modules, with its own copy of bn.js@^2.0.0 (because it clashes with [email protected] in root node_modules).

But npm installs elliptic inside of bitcore's dependencies instead of storing [email protected] in the root like yarn does (yarn likes to keep things flat).

Since npm's bitcore->elliptic dependency tree is local (i.e. under bitcore-lib/node_modules, not root node_modules), both bitcore and elliptic share the same bn.js version (bitcore-lib/node_modules/bn.js), but the same can't be said for yarn's tree (i.e. node_modules/elliptic and node_modules/bitcore-lib each have their own copy of bn.js); with yarn's tree, bitcore is only monkeypatching their bn.js, not elliptic's bn.js, which is causing the issue you see1, but with npm's tree, bitcore is monkeypatching the shared bn.js.

The fact that it works with npm is honestly just luck, because if you e.g. run npm install elliptic@=3.0.3 --save && npm dedupe (to put [email protected] into the root node_modules like yarn chooses to do, and get rid of the shared bn.js module), the issue shows up with npm as well.

To fix it, you can yarn add elliptic@^6.4.0 (or some other version that isn't what bitcore or elliptic need), so elliptic gets stored under bitcore-lib/node_modules, and then to force all bn.js resolutions under bitcore's dependency tree to use [email protected], you can add this to the package.json:

"resolutions": {
  "bitcore-lib/**/bn.js": "=2.0.4"
}

Then yarn's tree should (roughly) match npm's tree, allowing bitcore's monkeypatch to apply to elliptic's bn.js dependency as well. (Or, of course, bitcore could stop the monkeypatching and just fork the module—this isn't Ruby. 🙃)

TLDR: monkeypatching a node module is a bad idea, especially when you're expecting said monkeypatch to apply to a dependency's version of the module (which has no guarantee of actually being the "same" module even if the versions are the same since it depends on tree/folder structure).

¹ r in the case of the error stack trace is a BN (actually a BN-R) from elliptic's bn.js, not bitcore's bn.js. See: this line from escjda.js, which is a Point, which uses BN from the elliptic module.

And that's how it's done.

ezekg avatar Dec 02 '17 02:12 ezekg

Soon 2019 and not fixed for yarn, bad support. I choose yarn over bitcore-lib and npm, thanks

ghost avatar Dec 14 '18 14:12 ghost