From bfab1b4750044bab243927b3492d8ffd338b2323 Mon Sep 17 00:00:00 2001
From: Andreas Brekken
Date: Sun, 22 Jun 2014 16:59:59 +0200
Subject: [PATCH 001/291] Cleanup readme status icons.
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 3b9b29a79..9e9c768e9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# bitcoinjs-lib
-[](https://travis-ci.org/bitcoinjs/bitcoinjs-lib) [](https://coveralls.io/r/bitcoinjs/bitcoinjs-lib)
+[](https://travis-ci.org/bitcoinjs/bitcoinjs-lib)
+[](https://coveralls.io/r/bitcoinjs/bitcoinjs-lib)
[](https://ci.testling.com/bitcoinjs/bitcoinjs-lib)
From 7f9356c6c874a6bbe0c4445146396039dab55d69 Mon Sep 17 00:00:00 2001
From: Andreas Brekken
Date: Sun, 22 Jun 2014 17:07:26 +0200
Subject: [PATCH 002/291] Add tip4commit embed to readme.
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 9e9c768e9..f01f99cf8 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@
[](https://travis-ci.org/bitcoinjs/bitcoinjs-lib)
[](https://coveralls.io/r/bitcoinjs/bitcoinjs-lib)
+[](http://tip4commit.com/projects/735)
[](https://ci.testling.com/bitcoinjs/bitcoinjs-lib)
From 750101a69b2d053e43cc50bd48a4779466c04821 Mon Sep 17 00:00:00 2001
From: Uwe Cerron
Date: Thu, 3 Jul 2014 03:41:13 -0400
Subject: [PATCH 003/291] Updated README.md
added project Decentral Bank.
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e5ad3e14d..0eba47789 100644
--- a/README.md
+++ b/README.md
@@ -119,7 +119,8 @@ console.log(tx.toHex())
- [Dark Wallet](https://darkwallet.unsystem.net)
- [Dogechain Wallet](https://dogechain.info)
- [GreenAddress](https://greenaddress.it)
-
+- [DecentralBank](https://decentralbank.com)
+
## Contributors
Stefan Thomas is the inventor and creator of this project. His pioneering work made Bitcoin web wallets possible.
From d168bbda43970be9e3c5cba2dbba08ec5b914ed0 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 15 Jul 2014 17:42:04 +1000
Subject: [PATCH 004/291] HDNode: missing space in assertion message
---
src/hdnode.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/hdnode.js b/src/hdnode.js
index 627b67dcf..0b2399cb2 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -51,7 +51,7 @@ HDNode.HIGHEST_BIT = 0x80000000
HDNode.LENGTH = 78
HDNode.fromSeedBuffer = function(seed, network) {
- assert(Buffer.isBuffer(seed), 'Expected Buffer, got' + seed)
+ assert(Buffer.isBuffer(seed), 'Expected Buffer, got ' + seed)
assert(seed.length >= 16, 'Seed should be at least 128 bits')
assert(seed.length <= 64, 'Seed should be at most 512 bits')
From 6dbf00f7acb08ed8d6b5450d0154803df616a179 Mon Sep 17 00:00:00 2001
From: Wei Lu
Date: Wed, 16 Jul 2014 01:33:31 +0800
Subject: [PATCH 005/291] upgrade browserify
per security advisory: https://nodesecurity.io/advisories/syntax-error-potential-script-injection
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 6a5bb83df..071680e75 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,7 @@
"url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
},
"devDependencies": {
- "browserify": "4.1.11",
+ "browserify": "^4.2.1",
"coveralls": "~2.10.0",
"helloblock-js": "^0.2.1",
"istanbul": "0.1.30",
From 0e0e97c011ed2df5b986c31d33dff45834b00a5f Mon Sep 17 00:00:00 2001
From: Wei Lu
Date: Wed, 16 Jul 2014 01:35:05 +0800
Subject: [PATCH 006/291] drop unnecessary binary paths
---
package.json | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index 071680e75..fbbbe2e8b 100644
--- a/package.json
+++ b/package.json
@@ -60,13 +60,13 @@
"files": "test/*.js"
},
"scripts": {
- "compile": "./node_modules/.bin/browserify ./src/index.js -s Bitcoin | ./node_modules/.bin/uglifyjs > bitcoinjs-min.js",
- "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- --reporter list test/*.js",
- "coveralls": "npm run-script coverage && node ./node_modules/.bin/coveralls < coverage/lcov.info",
- "integration": "./node_modules/.bin/_mocha --reporter list test/integration/*.js",
- "jshint": "./node_modules/.bin/jshint --config jshint.json src/*.js ; true",
+ "compile": "browserify ./src/index.js -s Bitcoin | uglifyjs > bitcoinjs-min.js",
+ "coverage": "istanbul cover mocha -- --reporter list test/*.js",
+ "coveralls": "npm run-script coverage && node coveralls < coverage/lcov.info",
+ "integration": "mocha --reporter list test/integration/*.js",
+ "jshint": "jshint --config jshint.json src/*.js ; true",
"test": "npm run-script unit",
- "unit": "./node_modules/.bin/istanbul test ./node_modules/.bin/_mocha -- --reporter list `find test -maxdepth 1 -not -type d`"
+ "unit": "istanbul test mocha -- --reporter list `find test -maxdepth 1 -not -type d`"
},
"browser": {
"crypto": "crypto-browserify"
From 4dd3b003ef606fe3ddc477d5e70d24082d2d1eeb Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 16 Jul 2014 03:53:22 +1000
Subject: [PATCH 007/291] package: consistent path finding
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index fbbbe2e8b..aed9d470e 100644
--- a/package.json
+++ b/package.json
@@ -66,7 +66,7 @@
"integration": "mocha --reporter list test/integration/*.js",
"jshint": "jshint --config jshint.json src/*.js ; true",
"test": "npm run-script unit",
- "unit": "istanbul test mocha -- --reporter list `find test -maxdepth 1 -not -type d`"
+ "unit": "istanbul test mocha -- --reporter list test/*.js"
},
"browser": {
"crypto": "crypto-browserify"
From 5cbb4af7b42d97520b703bd6e0c6878a9018f6a1 Mon Sep 17 00:00:00 2001
From: Wei Lu
Date: Wed, 16 Jul 2014 09:55:24 +0800
Subject: [PATCH 008/291] package: fix coveralls scripts
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index aed9d470e..3e6515dc4 100644
--- a/package.json
+++ b/package.json
@@ -61,8 +61,8 @@
},
"scripts": {
"compile": "browserify ./src/index.js -s Bitcoin | uglifyjs > bitcoinjs-min.js",
- "coverage": "istanbul cover mocha -- --reporter list test/*.js",
- "coveralls": "npm run-script coverage && node coveralls < coverage/lcov.info",
+ "coverage": "istanbul cover _mocha -- test/*.js",
+ "coveralls": "npm run-script coverage && coveralls < coverage/lcov.info",
"integration": "mocha --reporter list test/integration/*.js",
"jshint": "jshint --config jshint.json src/*.js ; true",
"test": "npm run-script unit",
From faa128ce568dcbb656a5a0d458a15c4d530fded5 Mon Sep 17 00:00:00 2001
From: Uwe Cerron
Date: Wed, 16 Jul 2014 00:36:58 -0400
Subject: [PATCH 009/291] updated url to http.
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 0eba47789..f7b1cb8dc 100644
--- a/README.md
+++ b/README.md
@@ -119,7 +119,7 @@ console.log(tx.toHex())
- [Dark Wallet](https://darkwallet.unsystem.net)
- [Dogechain Wallet](https://dogechain.info)
- [GreenAddress](https://greenaddress.it)
-- [DecentralBank](https://decentralbank.com)
+- [DecentralBank](http://decentralbank.com)
## Contributors
From c2e7840c4fac908b02ad154fbd1b50a8d25c93af Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 16 Jul 2014 17:53:38 +1000
Subject: [PATCH 010/291] Transaction: adds assert for invalid value type
---
src/transaction.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/transaction.js b/src/transaction.js
index 80393b974..72e72f6c1 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -85,6 +85,7 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) {
}
assert(scriptPubKey instanceof Script, 'Expected Address or Script, got ' + scriptPubKey)
+ assert.equal(typeof value, 'number', 'Expected number value, got ' + value)
return (this.outs.push({
script: scriptPubKey,
From 99db4ab1ce1d97a1b88393bbc0d86f01496b766e Mon Sep 17 00:00:00 2001
From: Kyle Drake
Date: Wed, 16 Jul 2014 10:07:46 -0700
Subject: [PATCH 011/291] 1.0.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 3e6515dc4..cc07c9f43 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.0.0",
+ "version": "1.0.1",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 8e0c835919b4e00de2aa721d9806d32a08e97cee Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 28 Jul 2014 13:46:34 +1000
Subject: [PATCH 012/291] package: use crypto-browserify 3.0.0
---
package.json | 1 +
src/eckey.js | 4 ++--
src/wallet.js | 4 ++--
test/eckey.js | 13 ++++++-------
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/package.json b/package.json
index cc07c9f43..765495d52 100644
--- a/package.json
+++ b/package.json
@@ -75,6 +75,7 @@
"bigi": "1.1.0",
"bs58": "1.1.0",
"bs58check": "1.0.0",
+ "crypto-browserify": "3.0.0",
"crypto-js": "3.1.2-3",
"crypto-browserify": "2.1.8",
"ecurve": "0.10.0",
diff --git a/src/eckey.js b/src/eckey.js
index 87a93677a..a3073ec33 100644
--- a/src/eckey.js
+++ b/src/eckey.js
@@ -1,8 +1,8 @@
var assert = require('assert')
var base58check = require('bs58check')
+var crypto = require('crypto')
var ecdsa = require('./ecdsa')
var networks = require('./networks')
-var secureRandom = require('secure-random')
var BigInteger = require('bigi')
var ECPubKey = require('./ecpubkey')
@@ -43,7 +43,7 @@ ECKey.fromWIF = function(string) {
}
ECKey.makeRandom = function(compressed, rng) {
- rng = rng || secureRandom.randomBuffer
+ rng = rng || crypto.randomBytes
var buffer = rng(32)
assert(Buffer.isBuffer(buffer), 'Expected Buffer, got ' + buffer)
diff --git a/src/wallet.js b/src/wallet.js
index da1408002..c056c9531 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -1,6 +1,6 @@
var assert = require('assert')
+var crypto = require('crypto')
var networks = require('./networks')
-var rng = require('secure-random')
var Address = require('./address')
var HDNode = require('./hdnode')
@@ -25,7 +25,7 @@ function Wallet(seed, network) {
// Make a new master key
this.newMasterKey = function(seed) {
- seed = seed || new Buffer(rng(32))
+ seed = seed || crypto.randomBytes(32)
masterkey = HDNode.fromSeedBuffer(seed, network)
// HD first-level child derivation method should be hardened
diff --git a/test/eckey.js b/test/eckey.js
index 7694a1bff..a5ce6205b 100644
--- a/test/eckey.js
+++ b/test/eckey.js
@@ -1,8 +1,7 @@
var assert = require('assert')
-var crypto = require('../src/crypto')
+var crypto = require('crypto')
+var crypto2 = require('../src/crypto')
var networks = require('../src/networks')
-
-var secureRandom = require('secure-random')
var sinon = require('sinon')
var BigInteger = require('bigi')
@@ -84,13 +83,13 @@ describe('ECKey', function() {
var exPrivKey = ECKey.fromWIF(exWIF)
var exBuffer = exPrivKey.d.toBuffer(32)
- describe('using default RNG', function() {
+ describe('uses default crypto RNG', function() {
beforeEach(function() {
- sinon.stub(secureRandom, 'randomBuffer').returns(exBuffer)
+ sinon.stub(crypto, 'randomBytes').returns(exBuffer)
})
afterEach(function() {
- secureRandom.randomBuffer.restore()
+ crypto.randomBytes.restore()
})
it('generates a ECKey', function() {
@@ -116,7 +115,7 @@ describe('ECKey', function() {
})
describe('signing', function() {
- var hash = crypto.sha256('Vires in numeris')
+ var hash = crypto2.sha256('Vires in numeris')
var priv = ECKey.makeRandom()
var signature = priv.sign(hash)
From 75b51995e5299ac1f5fb7e9b159055cf1ece9cb9 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 25 Jul 2014 11:20:23 +1000
Subject: [PATCH 013/291] package: use bs58 1.2.1
---
package.json | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index 765495d52..3947bbd13 100644
--- a/package.json
+++ b/package.json
@@ -73,12 +73,10 @@
},
"dependencies": {
"bigi": "1.1.0",
- "bs58": "1.1.0",
- "bs58check": "1.0.0",
- "crypto-browserify": "3.0.0",
+ "bs58": "1.2.1",
+ "bs58check": "1.0.1",
"crypto-js": "3.1.2-3",
- "crypto-browserify": "2.1.8",
- "ecurve": "0.10.0",
- "secure-random": "1.1.1"
+ "crypto-browserify": "3.0.0",
+ "ecurve": "0.10.0"
}
}
From a8d1a525e5230683762c51054191580189cdf1bd Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 28 Jul 2014 13:48:00 +1000
Subject: [PATCH 014/291] package: use ecurve 1.0.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 3947bbd13..4b3bbe83b 100644
--- a/package.json
+++ b/package.json
@@ -77,6 +77,6 @@
"bs58check": "1.0.1",
"crypto-js": "3.1.2-3",
"crypto-browserify": "3.0.0",
- "ecurve": "0.10.0"
+ "ecurve": "1.0.0"
}
}
From 2920bb2ee1a1eb3208d97f30b1bed41142c97a10 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 16 Jul 2014 03:58:08 +1000
Subject: [PATCH 015/291] tests: remove outdated FIXME in wallet
---
test/wallet.js | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/test/wallet.js b/test/wallet.js
index 76d830f5b..e85096e33 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -308,13 +308,9 @@ describe('Wallet', function() {
var pubKey = wallet.getPrivateKey(0).pub
var script = scripts.pubKeyOutput(pubKey)
var tx2 = new Transaction()
- tx2.addInput(fakeTxId(1), 0)
- // FIXME: Transaction doesn't support custom ScriptPubKeys... yet
- // So for now, we hijack the script with our own, and undefine the cached address
- tx2.addOutput(addresses[0], 10000)
- tx2.outs[0].script = script
- tx2.outs[0].address = undefined
+ tx2.addInput(fakeTxHash(1), 0)
+ tx2.addOutput(script, 10000)
wallet.processConfirmedTx(tx2)
})
From eaf8cf85af2155b12d0d5bda649d8e942498706a Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 28 Jul 2014 18:13:00 +1000
Subject: [PATCH 016/291] test: rephrase fail -> throw
---
test/wallet.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/wallet.js b/test/wallet.js
index e85096e33..80fd7a8a8 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -304,7 +304,7 @@ describe('Wallet', function() {
})
describe('processConfirmedTx', function(){
- it('does not fail on scripts with no corresponding Address', function() {
+ it('does not throw on scripts with no corresponding Address', function() {
var pubKey = wallet.getPrivateKey(0).pub
var script = scripts.pubKeyOutput(pubKey)
var tx2 = new Transaction()
From a8c6f5284d8e9ef76f36628ecabffb8d0f99db31 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 29 Jul 2014 01:01:11 +1000
Subject: [PATCH 017/291] tests: avoid unnecessary sha256 for hash
---
test/eckey.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/test/eckey.js b/test/eckey.js
index a5ce6205b..849dd7ed1 100644
--- a/test/eckey.js
+++ b/test/eckey.js
@@ -1,6 +1,5 @@
var assert = require('assert')
var crypto = require('crypto')
-var crypto2 = require('../src/crypto')
var networks = require('../src/networks')
var sinon = require('sinon')
@@ -115,7 +114,7 @@ describe('ECKey', function() {
})
describe('signing', function() {
- var hash = crypto2.sha256('Vires in numeris')
+ var hash = crypto.randomBytes(32)
var priv = ECKey.makeRandom()
var signature = priv.sign(hash)
From 04bcbadc77475495cff50e641ed62ceb75ce5947 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 29 Jul 2014 02:06:17 +1000
Subject: [PATCH 018/291] transaction/ecdsa: remove unused imports
---
src/ecdsa.js | 1 -
src/transaction.js | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/ecdsa.js b/src/ecdsa.js
index aeba1de4e..96c5351ae 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -3,7 +3,6 @@ var crypto = require('./crypto')
var BigInteger = require('bigi')
var ECSignature = require('./ecsignature')
-var Point = require('ecurve').Point
// https://tools.ietf.org/html/rfc6979#section-3.2
function deterministicGenerateK(curve, hash, d) {
diff --git a/src/transaction.js b/src/transaction.js
index 72e72f6c1..1bfff5d1e 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -5,7 +5,6 @@ var opcodes = require('./opcodes')
var scripts = require('./scripts')
var Address = require('./address')
-var ECKey = require('./eckey')
var ECSignature = require('./ecsignature')
var Script = require('./script')
From eda94d4fe3508256a903930b6a0078d956d7a3e3 Mon Sep 17 00:00:00 2001
From: Rich Apodaca
Date: Mon, 28 Jul 2014 21:59:42 -0700
Subject: [PATCH 019/291] Fixed, added console.log output on README
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 1689f0969..76bccd6fc 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,7 @@ key = bitcoin.ECKey.makeRandom()
// Print your private key (in WIF format)
console.log(key.toWIF())
-// => 8c112cf628362ecf4d482f68af2dbb50c8a2cb90d226215de925417aa9336a48
+// => Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct
// Print your public key (toString defaults to a Bitcoin address)
console.log(key.pub.getAddress().toString())
@@ -120,6 +120,7 @@ var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
var multisigAddress = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
console.log("multisigP2SH:", multisigAddress)
+// => multisigP2SH: 35k9EWv2F1X5JKXHSF1DhTm7Ybdiwx4RkD
```
From be3ce88a3ae8cff791107a09286a8bf407cfdbbd Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 29 Jul 2014 23:45:10 +1000
Subject: [PATCH 020/291] ecdsa: enforce positive integers
---
src/ecdsa.js | 13 ++++++++-----
test/fixtures/ecdsa.json | 18 ++++++++++++++++++
2 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/ecdsa.js b/src/ecdsa.js
index 96c5351ae..5d57525cf 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -86,8 +86,8 @@ function verifyRaw(curve, e, signature, Q) {
var r = signature.r
var s = signature.s
- if (r.signum() === 0 || r.compareTo(n) >= 0) return false
- if (s.signum() === 0 || s.compareTo(n) >= 0) return false
+ if (r.signum() <= 0 || r.compareTo(n) >= 0) return false
+ if (s.signum() <= 0 || s.compareTo(n) >= 0) return false
var c = s.modInverse(n)
@@ -111,9 +111,15 @@ function verifyRaw(curve, e, signature, Q) {
function recoverPubKey(curve, e, signature, i) {
assert.strictEqual(i & 3, i, 'Recovery param is more than two bits')
+ var n = curve.n
+ var G = curve.G
+
var r = signature.r
var s = signature.s
+ assert(r.signum() > 0 && r.compareTo(n) < 0, 'Invalid r value')
+ assert(s.signum() > 0 && s.compareTo(n) < 0, 'Invalid s value')
+
// A set LSB signifies that the y-coordinate is odd
var isYOdd = i & 1
@@ -121,9 +127,6 @@ function recoverPubKey(curve, e, signature, i) {
// first or second candidate key.
var isSecondKey = i >> 1
- var n = curve.n
- var G = curve.G
-
// 1.1 Let x = r + jn
var x = isSecondKey ? r.add(n) : r
var R = curve.pointFromX(isYOdd, x)
diff --git a/test/fixtures/ecdsa.json b/test/fixtures/ecdsa.json
index 3f1421f07..8d2adf05a 100644
--- a/test/fixtures/ecdsa.json
+++ b/test/fixtures/ecdsa.json
@@ -104,6 +104,15 @@
"s": "3180566392414476763164587487324397066658063772201694230600609996154610926757"
}
},
+ {
+ "description": "Invalid r value (< 0)",
+ "d": "01",
+ "e": "01",
+ "signature": {
+ "r": "-01",
+ "s": "02"
+ }
+ },
{
"description": "Invalid r value (== 0)",
"d": "01",
@@ -122,6 +131,15 @@
"s": "02"
}
},
+ {
+ "description": "Invalid s value (< 0)",
+ "d": "01",
+ "e": "01",
+ "signature": {
+ "r": "02",
+ "s": "-01"
+ }
+ },
{
"description": "Invalid s value (== 0)",
"d": "01",
From 5657dcf2aa0372b43985b4af6ccebae2e4bc4ebb Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 29 Jul 2014 23:45:50 +1000
Subject: [PATCH 021/291] ecdsa: add improved test coverage for recoverPubKey
---
test/fixtures/ecdsa.json | 52 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 51 insertions(+), 1 deletion(-)
diff --git a/test/fixtures/ecdsa.json b/test/fixtures/ecdsa.json
index 8d2adf05a..03a2687b9 100644
--- a/test/fixtures/ecdsa.json
+++ b/test/fixtures/ecdsa.json
@@ -73,9 +73,19 @@
],
"invalid": {
"recoverPubKey": [
+ {
+ "description": "Invalid r value (< 0)",
+ "exception": "Invalid r value",
+ "e": "01",
+ "signature": {
+ "r": "-01",
+ "s": "02"
+ },
+ "i": 0
+ },
{
"description": "Invalid r value (== 0)",
- "exception": "nR is not a valid curve point",
+ "exception": "Invalid r value",
"e": "01",
"signature": {
"r": "00",
@@ -83,6 +93,46 @@
},
"i": 0
},
+ {
+ "description": "Invalid s value (< 0)",
+ "exception": "Invalid s value",
+ "e": "01",
+ "signature": {
+ "r": "02",
+ "s": "-01"
+ },
+ "i": 0
+ },
+ {
+ "description": "Invalid s value (== 0)",
+ "exception": "Invalid s value",
+ "e": "01",
+ "signature": {
+ "r": "02",
+ "s": "00"
+ },
+ "i": 0
+ },
+ {
+ "description": "Invalid r value (nR is infinity)",
+ "exception": "nR is not a valid curve point",
+ "e": "01",
+ "signature": {
+ "r": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ "s": "01"
+ },
+ "i": 0
+ },
+ {
+ "description": "Invalid curve point",
+ "exception": "Point is not on the curve",
+ "e": "01",
+ "signature": {
+ "r": "99999999999999999999999999999999999999",
+ "s": "01"
+ },
+ "i": 0
+ },
{
"description": "Invalid i value (> 3)",
"exception": "Recovery param is more than two bits",
From 52689fc98b0d9d00821a802229adc1e810121a1c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 30 Jul 2014 14:47:21 +1000
Subject: [PATCH 022/291] tests: adds r = s = -n ecdsa verify test case
---
test/fixtures/ecdsa.json | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/test/fixtures/ecdsa.json b/test/fixtures/ecdsa.json
index 03a2687b9..ea53d7c00 100644
--- a/test/fixtures/ecdsa.json
+++ b/test/fixtures/ecdsa.json
@@ -207,6 +207,15 @@
"r": "02",
"s": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
}
+ },
+ {
+ "description": "Invalid r, s values (r = s = -n)",
+ "d": "01",
+ "e": "01",
+ "signature": {
+ "r": "-115792089237316195423570985008687907852837564279074904382605163141518161494337",
+ "s": "-115792089237316195423570985008687907852837564279074904382605163141518161494337"
+ }
}
]
}
From 804c542c40ae474297cd0441bc764cb9f5015c6a Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 30 Jul 2014 15:01:43 +1000
Subject: [PATCH 023/291] ecdsa: add SEC annotations for verify
---
src/ecdsa.js | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/ecdsa.js b/src/ecdsa.js
index 5d57525cf..98c238ff0 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -86,17 +86,26 @@ function verifyRaw(curve, e, signature, Q) {
var r = signature.r
var s = signature.s
+ // 1.4.1 Enforce r and s are both integers in the interval [1, n − 1]
if (r.signum() <= 0 || r.compareTo(n) >= 0) return false
if (s.signum() <= 0 || s.compareTo(n) >= 0) return false
+ // c = s^-1 mod n
var c = s.modInverse(n)
+ // 1.4.4 Compute u1 = es^−1 mod n
+ // u2 = rs^−1 mod n
var u1 = e.multiply(c).mod(n)
var u2 = r.multiply(c).mod(n)
- var point = G.multiplyTwo(u1, Q, u2)
- var v = point.affineX.mod(n)
+ // 1.4.5 Compute R = (xR, yR) = u1G + u2Q
+ var R = G.multiplyTwo(u1, Q, u2)
+ var v = R.affineX.mod(n)
+ // 1.4.5 (cont.) Enforce R is not at infinity
+ if (curve.isInfinity(R)) return false
+
+ // 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
return v.equals(r)
}
From 8297e1b0fcbcdc83bcdc8011783ce7cec1d0797b Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 30 Jul 2014 15:10:38 +1000
Subject: [PATCH 024/291] ecdsa: add further (missing) annotations from 1.4.x
---
src/ecdsa.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/ecdsa.js b/src/ecdsa.js
index 98c238ff0..dabcd0566 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -74,6 +74,8 @@ function sign(curve, hash, d) {
}
function verify(curve, hash, signature, Q) {
+ // 1.4.2 H = Hash(M), already done by the user
+ // 1.4.3 e = H
var e = BigInteger.fromBuffer(hash)
return verifyRaw(curve, e, signature, Q)
From 5888ca5730ed33fc4b2f3b9a35c37ce3ee33328b Mon Sep 17 00:00:00 2001
From: Kyle Drake
Date: Wed, 30 Jul 2014 00:11:46 -0700
Subject: [PATCH 025/291] 1.0.2
Signed-off-by: Kyle Drake
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 4b3bbe83b..78523bfba 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.0.1",
+ "version": "1.0.2",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From e69ba7ce764fa1db566cada06c7b502c802344cc Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 29 Jul 2014 01:30:51 +1000
Subject: [PATCH 026/291] HDNode: assert chain code length
---
src/hdnode.js | 1 +
test/hdnode.js | 8 +++++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/hdnode.js b/src/hdnode.js
index 0b2399cb2..8c8a41dd6 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -31,6 +31,7 @@ function HDNode(K, chainCode, network) {
network = network || networks.bitcoin
assert(Buffer.isBuffer(chainCode), 'Expected Buffer, got ' + chainCode)
+ assert.equal(chainCode.length, 32, 'Expected chainCode length of 32, got ' + chainCode.length)
assert(network.bip32, 'Unknown BIP32 constants for network')
this.chainCode = chainCode
diff --git a/test/hdnode.js b/test/hdnode.js
index bc951a288..265b5d6f1 100644
--- a/test/hdnode.js
+++ b/test/hdnode.js
@@ -49,7 +49,13 @@ describe('HDNode', function() {
assert.equal(hd.network, networks.testnet)
})
- it('throws an exception when an unknown network is given', function() {
+ it('throws when an invalid length chain code is given', function() {
+ assert.throws(function() {
+ new HDNode(d, chainCode.slice(0, 20), networks.testnet)
+ }, /Expected chainCode length of 32, got 20/)
+ })
+
+ it('throws when an unknown network is given', function() {
assert.throws(function() {
new HDNode(d, chainCode, {})
}, /Unknown BIP32 constants for network/)
From 9d92b6a1a8adbe247444a198bce54920c92562cb Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 29 Jul 2014 01:34:46 +1000
Subject: [PATCH 027/291] HDNode: add neuter functionality
---
src/hdnode.js | 9 +++++++++
test/hdnode.js | 15 +++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/src/hdnode.js b/src/hdnode.js
index 8c8a41dd6..560866ed0 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -143,6 +143,15 @@ HDNode.prototype.getAddress = function() {
return this.pubKey.getAddress(this.network)
}
+HDNode.prototype.neutered = function() {
+ var neutered = new HDNode(this.pubKey.Q, this.chainCode, this.network)
+ neutered.depth = this.depth
+ neutered.index = this.index
+ neutered.parentFingerprint = this.parentFingerprint
+
+ return neutered
+}
+
HDNode.prototype.toBase58 = function(isPrivate) {
return base58check.encode(this.toBuffer(isPrivate))
}
diff --git a/test/hdnode.js b/test/hdnode.js
index 265b5d6f1..794abe046 100644
--- a/test/hdnode.js
+++ b/test/hdnode.js
@@ -226,6 +226,21 @@ describe('HDNode', function() {
})
})
+ describe('neutered', function() {
+ var f = fixtures.valid[0]
+
+ it('strips all private information', function() {
+ var hd = HDNode.fromBase58(f.master.base58)
+ var hdn = hd.neutered()
+
+ assert.equal(hdn.privKey, undefined)
+ assert.equal(hdn.pubKey.toHex(), hd.pubKey.toHex())
+ assert.equal(hdn.chainCode, hd.chainCode)
+ assert.equal(hdn.depth, hd.depth)
+ assert.equal(hdn.index, hd.index)
+ })
+ })
+
describe('derive', function() {
function verifyVector(hd, v, depth) {
assert.equal(hd.privKey.toWIF(), v.wif)
From 2fbd9449f5e15daa2bfe20a868468486184a6ca8 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 29 Jul 2014 01:34:56 +1000
Subject: [PATCH 028/291] tests: use neutered rather than import/export
---
test/hdnode.js | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/test/hdnode.js b/test/hdnode.js
index 794abe046..465f09bff 100644
--- a/test/hdnode.js
+++ b/test/hdnode.js
@@ -277,32 +277,28 @@ describe('HDNode', function() {
var f = fixtures.valid[1]
var c = f.children[0]
- var parentNode = HDNode.fromBase58(f.master.base58Priv)
- var child = parentNode.derive(c.m)
+ var master = HDNode.fromBase58(f.master.base58Priv)
+ var child = master.derive(c.m).neutered()
- // FIXME: N(CKDpriv((kpar, cpar), i)), could be done better...
- var childNeutered = HDNode.fromBase58(child.toBase58(false)) // neuter
- assert.equal(childNeutered.toBase58(), c.base58)
+ assert.equal(child.toBase58(), c.base58)
})
it('works for Private -> public (neutered, hardened)', function() {
var f = fixtures.valid[0]
var c = f.children[0]
- var parentNode = HDNode.fromBase58(f.master.base58Priv)
- var child = parentNode.deriveHardened(c.m)
+ var master = HDNode.fromBase58(f.master.base58Priv)
+ var child = master.deriveHardened(c.m).neutered()
- // FIXME: N(CKDpriv((kpar, cpar), i)), could be done better...
- var childNeutered = HDNode.fromBase58(child.toBase58(false)) // neuter
- assert.equal(childNeutered.toBase58(), c.base58)
+ assert.equal(child.toBase58(), c.base58)
})
it('works for Public -> public', function() {
var f = fixtures.valid[1]
var c = f.children[0]
- var parentNode = HDNode.fromBase58(f.master.base58)
- var child = parentNode.derive(c.m)
+ var master = HDNode.fromBase58(f.master.base58)
+ var child = master.derive(c.m)
assert.equal(child.toBase58(), c.base58)
})
@@ -311,10 +307,10 @@ describe('HDNode', function() {
var f = fixtures.valid[0]
var c = f.children[0]
- var parentNode = HDNode.fromBase58(f.master.base58)
+ var master = HDNode.fromBase58(f.master.base58)
assert.throws(function() {
- parentNode.deriveHardened(c.m)
+ master.deriveHardened(c.m)
}, /Could not derive hardened child key/)
})
})
From 6b429493f80ce6b3fe83d5223634562900a6c73f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 30 Jul 2014 18:00:20 +1000
Subject: [PATCH 029/291] hdnode: add deprecation message for isPrivate
---
src/hdnode.js | 9 ++++++++-
test/hdnode.js | 14 ++++++++------
2 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/src/hdnode.js b/src/hdnode.js
index 560866ed0..3a7f86079 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -157,7 +157,13 @@ HDNode.prototype.toBase58 = function(isPrivate) {
}
HDNode.prototype.toBuffer = function(isPrivate) {
- if (isPrivate == undefined) isPrivate = !!this.privKey
+ if (isPrivate == undefined) {
+ isPrivate = !!this.privKey
+
+ // FIXME: remove in 2.x.y
+ } else {
+ console.warn('isPrivate flag is deprecated, please use the .neutered() method instead')
+ }
// Version
var version = isPrivate ? this.network.bip32.private : this.network.bip32.public
@@ -183,6 +189,7 @@ HDNode.prototype.toBuffer = function(isPrivate) {
// 33 bytes: the public key or private key data
if (isPrivate) {
+ // FIXME: remove in 2.x.y
assert(this.privKey, 'Missing private key')
// 0x00 + k for private keys
diff --git a/test/hdnode.js b/test/hdnode.js
index 465f09bff..617261d6b 100644
--- a/test/hdnode.js
+++ b/test/hdnode.js
@@ -88,9 +88,9 @@ describe('HDNode', function() {
describe('toBase58', function() {
fixtures.valid.forEach(function(f) {
it('exports ' + f.master.base58 + ' (public) correctly', function() {
- var hd = HDNode.fromSeedHex(f.master.seed)
+ var hd = HDNode.fromSeedHex(f.master.seed).neutered()
- assert.equal(hd.toBase58(false), f.master.base58)
+ assert.equal(hd.toBase58(), f.master.base58)
})
})
@@ -98,10 +98,11 @@ describe('HDNode', function() {
it('exports ' + f.master.base58Priv + ' (private) correctly', function() {
var hd = HDNode.fromSeedHex(f.master.seed)
- assert.equal(hd.toBase58(true), f.master.base58Priv)
+ assert.equal(hd.toBase58(), f.master.base58Priv)
})
})
+ // FIXME: remove in 2.x.y
it('fails when there is no private key', function() {
var hd = HDNode.fromBase58(fixtures.valid[0].master.base58)
@@ -166,9 +167,9 @@ describe('HDNode', function() {
describe('toBuffer/toHex', function() {
fixtures.valid.forEach(function(f) {
it('exports ' + f.master.hex + ' (public) correctly', function() {
- var hd = HDNode.fromSeedHex(f.master.seed)
+ var hd = HDNode.fromSeedHex(f.master.seed).neutered()
- assert.equal(hd.toHex(false), f.master.hex)
+ assert.equal(hd.toHex(), f.master.hex)
})
})
@@ -176,10 +177,11 @@ describe('HDNode', function() {
it('exports ' + f.master.hexPriv + ' (private) correctly', function() {
var hd = HDNode.fromSeedHex(f.master.seed)
- assert.equal(hd.toHex(true), f.master.hexPriv)
+ assert.equal(hd.toHex(), f.master.hexPriv)
})
})
+ // FIXME: remove in 2.x.y
it('fails when there is no private key', function() {
var hd = HDNode.fromHex(fixtures.valid[0].master.hex)
From d618aa9822fbdb1bb887e6f62d44e383518fd5be Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 14 Aug 2014 11:00:18 +1000
Subject: [PATCH 030/291] Wallet: deprecates newMasterKey
---
src/wallet.js | 50 +++++++++++++++++++++++++++-----------------------
1 file changed, 27 insertions(+), 23 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index c056c9531..dd492ba55 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -7,14 +7,18 @@ var HDNode = require('./hdnode')
var Transaction = require('./transaction')
function Wallet(seed, network) {
+ seed = seed || crypto.randomBytes(32)
network = network || networks.bitcoin
// Stored in a closure to make accidental serialization less likely
- var masterkey = null
+ var masterkey = HDNode.fromSeedBuffer(seed, network)
var me = this
- var accountZero = null
- var internalAccount = null
- var externalAccount = null
+
+ // HD first-level child derivation method should be hardened
+ // See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
+ var accountZero = masterkey.deriveHardened(0)
+ var externalAccount = accountZero.derive(0)
+ var internalAccount = accountZero.derive(1)
// Addresses
this.addresses = []
@@ -23,25 +27,6 @@ function Wallet(seed, network) {
// Transaction output data
this.outputs = {}
- // Make a new master key
- this.newMasterKey = function(seed) {
- seed = seed || crypto.randomBytes(32)
- masterkey = HDNode.fromSeedBuffer(seed, network)
-
- // HD first-level child derivation method should be hardened
- // See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
- accountZero = masterkey.deriveHardened(0)
- externalAccount = accountZero.derive(0)
- internalAccount = accountZero.derive(1)
-
- me.addresses = []
- me.changeAddresses = []
-
- me.outputs = {}
- }
-
- this.newMasterKey(seed)
-
this.generateAddress = function() {
var key = externalAccount.derive(this.addresses.length)
this.addresses.push(key.getAddress().toString())
@@ -71,6 +56,25 @@ function Wallet(seed, network) {
return utxo
}
+ // FIXME: remove in 2.x.y
+ this.newMasterKey = function(seed) {
+ console.warn('newMasterKey is deprecated, please make a new Wallet instance instead')
+
+ seed = seed || crypto.randomBytes(32)
+ masterkey = HDNode.fromSeedBuffer(seed, network)
+
+ // HD first-level child derivation method should be hardened
+ // See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
+ accountZero = masterkey.deriveHardened(0)
+ externalAccount = accountZero.derive(0)
+ internalAccount = accountZero.derive(1)
+
+ me.addresses = []
+ me.changeAddresses = []
+
+ me.outputs = {}
+ }
+
this.setUnspentOutputs = function(utxo) {
var outputs = {}
From 8b3470e8cabe982f6fe40faac35e88271d33b9fc Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 13 Aug 2014 12:03:53 +1000
Subject: [PATCH 031/291] Wallet: move all free functions out of Wallet scope
---
src/wallet.js | 137 +++++++++++++++++++++++++-------------------------
1 file changed, 68 insertions(+), 69 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index dd492ba55..b18880842 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -86,59 +86,6 @@ function Wallet(seed, network) {
this.outputs = outputs
}
-
- function outputToUnspentOutput(output){
- var hashAndIndex = output.from.split(":")
-
- return {
- hash: hashAndIndex[0],
- outputIndex: parseInt(hashAndIndex[1]),
- address: output.address,
- value: output.value,
- pending: output.pending
- }
- }
-
- function unspentOutputToOutput(o) {
- var hash = o.hash
- var key = hash + ":" + o.outputIndex
- return {
- from: key,
- address: o.address,
- value: o.value,
- pending: o.pending
- }
- }
-
- function validateUnspentOutput(uo) {
- var missingField
-
- if (isNullOrUndefined(uo.hash)) {
- missingField = "hash"
- }
-
- var requiredKeys = ['outputIndex', 'address', 'value']
- requiredKeys.forEach(function (key) {
- if (isNullOrUndefined(uo[key])){
- missingField = key
- }
- })
-
- if (missingField) {
- var message = [
- 'Invalid unspent output: key', missingField, 'is missing.',
- 'A valid unspent output must contain'
- ]
- message.push(requiredKeys.join(', '))
- message.push("and hash")
- throw new Error(message.join(' '))
- }
- }
-
- function isNullOrUndefined(value) {
- return value == undefined
- }
-
this.processPendingTx = function(tx){
processTx(tx, true)
}
@@ -193,7 +140,7 @@ function Wallet(seed, network) {
this.createTx = function(to, value, fixedFee, changeAddress) {
assert(value > network.dustThreshold, value + ' must be above dust threshold (' + network.dustThreshold + ' Satoshis)')
- var utxos = getCandidateOutputs(value)
+ var utxos = getCandidateOutputs(this.outputs, value)
var accum = 0
var subTotal = value
var addresses = []
@@ -229,21 +176,6 @@ function Wallet(seed, network) {
return tx
}
- function getCandidateOutputs() {
- var unspent = []
-
- for (var key in me.outputs) {
- var output = me.outputs[key]
- if (!output.pending) unspent.push(output)
- }
-
- var sortByValueDesc = unspent.sort(function(o1, o2){
- return o2.value - o1.value
- })
-
- return sortByValueDesc
- }
-
function estimateFeePadChangeOutput(tx) {
var tmpTx = tx.clone()
tmpTx.addOutput(getChangeAddress(), network.dustSoftThreshold || 0)
@@ -305,4 +237,71 @@ function Wallet(seed, network) {
}
}
+function outputToUnspentOutput(output){
+ var hashAndIndex = output.from.split(":")
+
+ return {
+ hash: hashAndIndex[0],
+ outputIndex: parseInt(hashAndIndex[1]),
+ address: output.address,
+ value: output.value,
+ pending: output.pending
+ }
+}
+
+function unspentOutputToOutput(o) {
+ var hash = o.hash
+ var key = hash + ":" + o.outputIndex
+ return {
+ from: key,
+ address: o.address,
+ value: o.value,
+ pending: o.pending
+ }
+}
+
+function validateUnspentOutput(uo) {
+ var missingField
+
+ if (isNullOrUndefined(uo.hash)) {
+ missingField = "hash"
+ }
+
+ var requiredKeys = ['outputIndex', 'address', 'value']
+ requiredKeys.forEach(function (key) {
+ if (isNullOrUndefined(uo[key])){
+ missingField = key
+ }
+ })
+
+ if (missingField) {
+ var message = [
+ 'Invalid unspent output: key', missingField, 'is missing.',
+ 'A valid unspent output must contain'
+ ]
+ message.push(requiredKeys.join(', '))
+ message.push("and hash")
+ throw new Error(message.join(' '))
+ }
+}
+
+function isNullOrUndefined(value) {
+ return value == undefined
+}
+
+function getCandidateOutputs(outputs/*, value*/) {
+ var unspent = []
+
+ for (var key in outputs) {
+ var output = outputs[key]
+ if (!output.pending) unspent.push(output)
+ }
+
+ var sortByValueDesc = unspent.sort(function(o1, o2){
+ return o2.value - o1.value
+ })
+
+ return sortByValueDesc
+}
+
module.exports = Wallet
From abc3e6c71584c7b6c5311f7eab91e18bf5c0d083 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 13 Aug 2014 12:17:12 +1000
Subject: [PATCH 032/291] Wallet: move estimatePaddedTxFee out of Wallet scope
---
src/wallet.js | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index b18880842..b2d9a058c 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -5,6 +5,7 @@ var networks = require('./networks')
var Address = require('./address')
var HDNode = require('./hdnode')
var Transaction = require('./transaction')
+var Script = require('./script')
function Wallet(seed, network) {
seed = seed || crypto.randomBytes(32)
@@ -155,7 +156,7 @@ function Wallet(seed, network) {
var outpoint = utxo.from.split(':')
tx.addInput(outpoint[0], parseInt(outpoint[1]))
- var fee = fixedFee == undefined ? estimateFeePadChangeOutput(tx) : fixedFee
+ var fee = fixedFee == undefined ? estimatePaddedFee(tx, network) : fixedFee
accum += utxo.value
subTotal = value + fee
@@ -176,13 +177,6 @@ function Wallet(seed, network) {
return tx
}
- function estimateFeePadChangeOutput(tx) {
- var tmpTx = tx.clone()
- tmpTx.addOutput(getChangeAddress(), network.dustSoftThreshold || 0)
-
- return network.estimateFee(tmpTx)
- }
-
function getChangeAddress() {
if(me.changeAddresses.length === 0) me.generateChangeAddress();
return me.changeAddresses[me.changeAddresses.length - 1]
@@ -285,6 +279,13 @@ function validateUnspentOutput(uo) {
}
}
+function estimatePaddedFee(tx, network) {
+ var tmpTx = tx.clone()
+ tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0)
+
+ return network.estimateFee(tmpTx)
+}
+
function isNullOrUndefined(value) {
return value == undefined
}
From 7c22067f6934abe254fba9b51d9cccf00b657173 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 13 Aug 2014 13:56:17 +1000
Subject: [PATCH 033/291] Wallet: clarify getPrivateKeyForAddress method
structure
This does repeat the O(n) lookup several times, but that can be fixed by
using an O(1) lookup instead (and will be later).
Clarity first.
---
src/wallet.js | 15 ++++++++++-----
test/wallet.js | 2 +-
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index b2d9a058c..f37737702 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -208,13 +208,18 @@ function Wallet(seed, network) {
}
this.getPrivateKeyForAddress = function(address) {
- var index
- if((index = this.addresses.indexOf(address)) > -1) {
+ assert(isMyAddress(address), 'Unknown address. Make sure the address is from the keychain and has been generated')
+
+ if (isReceiveAddress(address)) {
+ var index = this.addresses.indexOf(address)
+
return this.getPrivateKey(index)
- } else if((index = this.changeAddresses.indexOf(address)) > -1) {
+ }
+
+ if (isChangeAddress(address)) {
+ var index = this.changeAddresses.indexOf(address)
+
return this.getInternalPrivateKey(index)
- } else {
- throw new Error('Unknown address. Make sure the address is from the keychain and has been generated.')
}
}
diff --git a/test/wallet.js b/test/wallet.js
index 80fd7a8a8..456775d26 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -164,7 +164,7 @@ describe('Wallet', function() {
var wallet = new Wallet(seed, networks.testnet)
assert.throws(function() {
wallet.getPrivateKeyForAddress("n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X")
- }, /Unknown address. Make sure the address is from the keychain and has been generated./)
+ }, /Unknown address. Make sure the address is from the keychain and has been generated/)
})
})
From 2f00c9ab353a5fac49c882d65433a6a737d3534b Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 14 Aug 2014 11:03:54 +1000
Subject: [PATCH 034/291] Wallet: rework unspents to primarily work on
initialization
The RegExp for the UTXO validation was removed as the errors are now
more verbose and specific to each case.
---
src/wallet.js | 83 +++++++---------
test/wallet.js | 257 ++++++++++++++++++++++++++-----------------------
2 files changed, 173 insertions(+), 167 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index f37737702..8dd2ca2b2 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -7,7 +7,7 @@ var HDNode = require('./hdnode')
var Transaction = require('./transaction')
var Script = require('./script')
-function Wallet(seed, network) {
+function Wallet(seed, network, unspents) {
seed = seed || crypto.randomBytes(32)
network = network || networks.bitcoin
@@ -26,7 +26,7 @@ function Wallet(seed, network) {
this.changeAddresses = []
// Transaction output data
- this.outputs = {}
+ this.outputs = unspents ? processUnspentOutputs(unspents) : {}
this.generateAddress = function() {
var key = externalAccount.derive(this.addresses.length)
@@ -77,16 +77,11 @@ function Wallet(seed, network) {
}
this.setUnspentOutputs = function(utxo) {
- var outputs = {}
+ console.warn('setUnspentOutputs is deprecated, please use the constructor option instead')
- utxo.forEach(function(uo){
- validateUnspentOutput(uo)
- var o = unspentOutputToOutput(uo)
- outputs[o.from] = o
- })
-
- this.outputs = outputs
+ this.outputs = processUnspentOutputs(utxo)
}
+
this.processPendingTx = function(tx){
processTx(tx, true)
}
@@ -95,6 +90,8 @@ function Wallet(seed, network) {
processTx(tx, false)
}
+ var me = this
+
function processTx(tx, isPending) {
var txid = tx.getId()
@@ -241,58 +238,48 @@ function outputToUnspentOutput(output){
return {
hash: hashAndIndex[0],
- outputIndex: parseInt(hashAndIndex[1]),
+ index: parseInt(hashAndIndex[1]),
address: output.address,
value: output.value,
pending: output.pending
}
}
-function unspentOutputToOutput(o) {
- var hash = o.hash
- var key = hash + ":" + o.outputIndex
- return {
- from: key,
- address: o.address,
- value: o.value,
- pending: o.pending
- }
+function estimatePaddedFee(tx, network) {
+ var tmpTx = tx.clone()
+ tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0)
+
+ return network.estimateFee(tmpTx)
}
-function validateUnspentOutput(uo) {
- var missingField
+function processUnspentOutputs(utxos) {
+ var outputs = {}
- if (isNullOrUndefined(uo.hash)) {
- missingField = "hash"
- }
+ utxos.forEach(function(utxo){
+ var hash = new Buffer(utxo.hash, 'hex')
+ var index = utxo.index
+ var address = utxo.address
+ var value = utxo.value
- var requiredKeys = ['outputIndex', 'address', 'value']
- requiredKeys.forEach(function (key) {
- if (isNullOrUndefined(uo[key])){
- missingField = key
- }
- })
+ // FIXME: remove alternative in 2.x.y
+ if (index === undefined) index = utxo.outputIndex
- if (missingField) {
- var message = [
- 'Invalid unspent output: key', missingField, 'is missing.',
- 'A valid unspent output must contain'
- ]
- message.push(requiredKeys.join(', '))
- message.push("and hash")
- throw new Error(message.join(' '))
- }
-}
+ assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
+ assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
+ assert.doesNotThrow(function() { Address.fromBase58Check(address) }, 'Expected Base58 Address, got ' + address)
+ assert.equal(typeof value, 'number', 'Expected number value, got ' + value)
-function estimatePaddedFee(tx, network) {
- var tmpTx = tx.clone()
- tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0)
+ var key = utxo.hash + ':' + utxo.index
- return network.estimateFee(tmpTx)
-}
+ outputs[key] = {
+ from: key,
+ address: address,
+ value: value,
+ pending: utxo.pending
+ }
+ })
-function isNullOrUndefined(value) {
- return value == undefined
+ return outputs
}
function getCandidateOutputs(outputs/*, value*/) {
diff --git a/test/wallet.js b/test/wallet.js
index 456775d26..c08ae2fe8 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -26,13 +26,17 @@ function fakeTxId(i) {
}
describe('Wallet', function() {
- var seed, wallet
+ var seed
beforeEach(function(){
seed = crypto.sha256("don't use a string seed like this in real life")
- wallet = new Wallet(seed)
})
describe('constructor', function() {
+ var wallet
+ beforeEach(function(){
+ wallet = new Wallet(seed)
+ })
+
it('defaults to Bitcoin network', function() {
assert.equal(wallet.getMasterKey().network, networks.bitcoin)
})
@@ -116,6 +120,11 @@ describe('Wallet', function() {
})
describe('generateChangeAddress', function(){
+ var wallet
+ beforeEach(function(){
+ wallet = new Wallet(seed)
+ })
+
it('generates change addresses', function(){
var wallet = new Wallet(seed, networks.testnet)
var expectedAddresses = ["mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn"]
@@ -126,6 +135,11 @@ describe('Wallet', function() {
})
describe('getPrivateKey', function(){
+ var wallet
+ beforeEach(function(){
+ wallet = new Wallet(seed)
+ })
+
it('returns the private key at the given index of external account', function(){
var wallet = new Wallet(seed, networks.testnet)
@@ -135,6 +149,11 @@ describe('Wallet', function() {
})
describe('getInternalPrivateKey', function(){
+ var wallet
+ beforeEach(function(){
+ wallet = new Wallet(seed)
+ })
+
it('returns the private key at the given index of internal account', function(){
var wallet = new Wallet(seed, networks.testnet)
@@ -144,6 +163,11 @@ describe('Wallet', function() {
})
describe('getPrivateKeyForAddress', function(){
+ var wallet
+ beforeEach(function(){
+ wallet = new Wallet(seed)
+ })
+
it('returns the private key for the given address', function(){
var wallet = new Wallet(seed, networks.testnet)
wallet.generateChangeAddress()
@@ -162,6 +186,7 @@ describe('Wallet', function() {
it('raises an error when address is not found', function(){
var wallet = new Wallet(seed, networks.testnet)
+
assert.throws(function() {
wallet.getPrivateKeyForAddress("n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X")
}, /Unknown address. Make sure the address is from the keychain and has been generated/)
@@ -169,51 +194,55 @@ describe('Wallet', function() {
})
describe('Unspent Outputs', function(){
- var expectedUtxo, expectedOutputKey
+ var utxo, expectedOutputKey
+ var wallet
+
beforeEach(function(){
- expectedUtxo = {
- "hash":"6a4062273ac4f9ea4ffca52d9fd102b08f6c32faa0a4d1318e3a7b2e437bb9c7",
- "outputIndex": 0,
+ utxo = {
"address" : "1AZpKpcfCzKDUeTFBQUL4MokQai3m3HMXv",
- "value": 20000,
- "pending": true
+ "hash": fakeTxId(6),
+ "index": 0,
+ "pending": true,
+ "value": 20000
}
- expectedOutputKey = expectedUtxo.hash + ":" + expectedUtxo.outputIndex
+
+ expectedOutputKey = utxo.hash + ":" + utxo.index
})
- function addUtxoToOutput(utxo){
- var key = utxo.hash + ":" + utxo.outputIndex
- wallet.outputs[key] = {
- from: key,
- address: utxo.address,
- value: utxo.value,
- pending: utxo.pending
- }
- }
+ describe('on construction', function(){
+ beforeEach(function(){
+ wallet = new Wallet(seed, networks.bitcoin, [utxo])
+ })
- describe('getBalance', function(){
- var utxo1
+ it('matches the expected behaviour', function(){
+ var output = wallet.outputs[expectedOutputKey]
+ assert(output)
+ assert.equal(output.value, utxo.value)
+ assert.equal(output.address, utxo.address)
+ })
+ })
+
+ describe('getBalance', function(){
beforeEach(function(){
- utxo1 = cloneObject(expectedUtxo)
- utxo1.hash = utxo1.hash.replace('7', 'l')
+ var utxo1 = cloneObject(utxo)
+ utxo1.hash = fakeTxId(5)
+
+ wallet = new Wallet(seed, networks.bitcoin, [utxo, utxo1])
})
it('sums over utxo values', function(){
- addUtxoToOutput(expectedUtxo)
- addUtxoToOutput(utxo1)
-
assert.equal(wallet.getBalance(), 40000)
})
})
describe('getUnspentOutputs', function(){
beforeEach(function(){
- addUtxoToOutput(expectedUtxo)
+ wallet = new Wallet(seed, networks.bitcoin, [utxo])
})
it('parses wallet outputs to the expect format', function(){
- assert.deepEqual(wallet.getUnspentOutputs(), [expectedUtxo])
+ assert.deepEqual(wallet.getUnspentOutputs(), [utxo])
})
it("ignores pending spending outputs (outputs with 'to' property)", function(){
@@ -223,40 +252,54 @@ describe('Wallet', function() {
assert.deepEqual(wallet.getUnspentOutputs(), [])
})
})
+ })
- describe('setUnspentOutputs', function(){
- var utxo
- beforeEach(function(){
- utxo = cloneObject([expectedUtxo])
- })
+ // FIXME: remove in 2.x.y
+ describe('setUnspentOutputs', function(){
+ var utxo
+ var expectedOutputKey
- it('matches the expected behaviour', function(){
- wallet.setUnspentOutputs(utxo)
- verifyOutputs()
- })
+ beforeEach(function(){
+ utxo = {
+ hash: fakeTxId(0),
+ index: 0,
+ address: '115qa7iPZqn6as57hxLL8E9VUnhmGQxKWi',
+ value: 500000
+ }
- describe('required fields', function(){
- ['outputIndex', 'address', 'hash', 'value'].forEach(function(field){
- it("throws an error when " + field + " is missing", function(){
- delete utxo[0][field]
+ expectedOutputKey = utxo.hash + ":" + utxo.index
- assert.throws(function() {
- wallet.setUnspentOutputs(utxo)
- }, new RegExp('Invalid unspent output: key ' + field + ' is missing'))
+ wallet = new Wallet(seed, networks.bitcoin)
+ })
+
+ it('matches the expected behaviour', function(){
+ wallet.setUnspentOutputs([utxo])
+
+ var output = wallet.outputs[expectedOutputKey]
+ assert(output)
+ assert.equal(output.value, utxo.value)
+ assert.equal(output.address, utxo.address)
+ })
+
+ describe('required fields', function(){
+ ['index', 'address', 'hash', 'value'].forEach(function(field){
+ it("throws an error when " + field + " is missing", function(){
+ delete utxo[field]
+
+ assert.throws(function() {
+ wallet.setUnspentOutputs([utxo])
})
})
})
-
- function verifyOutputs() {
- var output = wallet.outputs[expectedOutputKey]
- assert(output)
- assert.equal(output.value, utxo[0].value)
- assert.equal(output.address, utxo[0].address)
- }
})
})
describe('Process transaction', function(){
+ var wallet
+ beforeEach(function(){
+ wallet = new Wallet(seed)
+ })
+
var addresses
var tx
@@ -389,39 +432,42 @@ describe('Wallet', function() {
})
describe('createTx', function(){
- var to, value
+ var wallet
var address1, address2
+ var to, value
beforeEach(function(){
- to = '15mMHKL96tWAUtqF3tbVf99Z8arcmnJrr3'
+ to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue'
value = 500000
- // generate 2 addresses
- address1 = wallet.generateAddress()
- address2 = wallet.generateAddress()
+ address1 = "n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa"
+ address2 = "n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X"
- // set up 3 utxo
- utxo = [
+ // set up 3 utxos
+ var utxos = [
{
"hash": fakeTxId(1),
- "outputIndex": 0,
- "address" : address1,
+ "index": 0,
+ "address": address1,
"value": 400000 // not enough for value
},
{
"hash": fakeTxId(2),
- "outputIndex": 1,
- "address" : address1,
+ "index": 1,
+ "address": address1,
"value": 500000 // enough for only value
},
{
"hash": fakeTxId(3),
- "outputIndex": 0,
+ "index": 0,
"address" : address2,
"value": 510000 // enough for value and fee
}
]
- wallet.setUnspentOutputs(utxo)
+
+ wallet = new Wallet(seed, networks.testnet, utxos)
+ wallet.generateAddress()
+ wallet.generateAddress()
})
describe('transaction fee', function(){
@@ -441,17 +487,18 @@ describe('Wallet', function() {
})
it('does not overestimate fees when network has dustSoftThreshold', function(){
- var wallet = new Wallet(seed, networks.litecoin)
- var address = wallet.generateAddress()
- wallet.setUnspentOutputs([{
+ var utxo = {
hash: fakeTxId(0),
- outputIndex: 0,
- address: address,
+ index: 0,
+ address: "LeyySKbQrRRwodKEj1W4a8y3YQupPLw5os",
value: 500000
- }])
+ }
+
+ var wallet = new Wallet(seed, networks.litecoin, [utxo])
+ wallet.generateAddress()
value = 200000
- var tx = wallet.createTx(address, value)
+ var tx = wallet.createTx(utxo.address, value)
assert.equal(getFee(wallet, tx), 100000)
})
@@ -477,66 +524,38 @@ describe('Wallet', function() {
assert.equal(tx.ins[0].index, 0)
})
- it('ignores pending outputs', function(){
- utxo.push(
- {
- "hash": fakeTxId(4),
- "outputIndex": 0,
- "address" : address2,
- "value": 530000,
- "pending": true
- }
- )
- wallet.setUnspentOutputs(utxo)
+ it('uses confirmed outputs', function(){
+ var tx2 = new Transaction()
+ tx2.addInput(fakeTxId(4), 0)
+ tx2.addOutput(address2, 530000)
+ wallet.processConfirmedTx(tx2)
var tx = wallet.createTx(to, value)
assert.equal(tx.ins.length, 1)
- assert.deepEqual(tx.ins[0].hash, fakeTxHash(3))
+ assert.deepEqual(tx.ins[0].hash, tx2.getHash())
assert.equal(tx.ins[0].index, 0)
})
- })
-
- describe('works for testnet', function(){
- it('should create transaction', function(){
- var wallet = new Wallet(seed, networks.testnet)
- var address = wallet.generateAddress()
- wallet.setUnspentOutputs([{
- hash: fakeTxId(0),
- outputIndex: 0,
- address: address,
- value: value
- }])
-
- var to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue'
- var toValue = value - 10000
+ it('ignores pending outputs', function(){
+ var tx2 = new Transaction()
+ tx2.addInput(fakeTxId(4), 0)
+ tx2.addOutput(address2, 530000)
- var tx = wallet.createTx(to, toValue)
- assert.equal(tx.outs.length, 1)
+ wallet.processPendingTx(tx2)
+ var tx = wallet.createTx(to, value)
- var outAddress = Address.fromOutputScript(tx.outs[0].script, networks.testnet)
- assert.equal(outAddress.toString(), to)
- assert.equal(tx.outs[0].value, toValue)
+ assert.equal(tx.ins.length, 1)
+ assert.deepEqual(tx.ins[0].hash, fakeTxHash(3))
+ assert.equal(tx.ins[0].index, 0)
})
})
describe('changeAddress', function(){
it('should allow custom changeAddress', function(){
- var wallet = new Wallet(seed, networks.testnet)
- var address = wallet.generateAddress()
-
- wallet.setUnspentOutputs([{
- hash: fakeTxId(0),
- outputIndex: 0,
- address: address,
- value: value
- }])
- assert.equal(wallet.getBalance(), value)
-
var changeAddress = 'mfrFjnKZUvTcvdAK2fUX5D8v1Epu5H8JCk'
- var to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue'
- var toValue = value / 2
+ var fromValue = 510000
+ var toValue = fromValue / 2
var fee = 1e3
var tx = wallet.createTx(to, toValue, fee, changeAddress)
@@ -549,7 +568,7 @@ describe('Wallet', function() {
assert.equal(tx.outs[0].value, toValue)
assert.equal(outAddress1.toString(), changeAddress)
- assert.equal(tx.outs[1].value, value - (toValue + fee))
+ assert.equal(tx.outs[1].value, fromValue - (toValue + fee))
})
})
@@ -559,7 +578,7 @@ describe('Wallet', function() {
assert.equal(tx.outs.length, 1)
var out = tx.outs[0]
- var outAddress = Address.fromOutputScript(out.script)
+ var outAddress = Address.fromOutputScript(out.script, networks.testnet)
assert.equal(outAddress.toString(), to)
assert.equal(out.value, value)
@@ -574,7 +593,7 @@ describe('Wallet', function() {
assert.equal(tx.outs.length, 2)
var out = tx.outs[1]
- var outAddress = Address.fromOutputScript(out.script)
+ var outAddress = Address.fromOutputScript(out.script, networks.testnet)
assert.equal(outAddress.toString(), wallet.changeAddresses[1])
assert.equal(out.value, 10000)
@@ -588,7 +607,7 @@ describe('Wallet', function() {
assert.equal(wallet.changeAddresses.length, 1)
var out = tx.outs[1]
- var outAddress = Address.fromOutputScript(out.script)
+ var outAddress = Address.fromOutputScript(out.script, networks.testnet)
assert.equal(outAddress.toString(), wallet.changeAddresses[0])
assert.equal(out.value, 10000)
From 7fd41fae4ae8022de3fbf9fb9ff4335d28ee1c31 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 14 Aug 2014 10:27:14 +1000
Subject: [PATCH 035/291] Wallet: move most instance methods to prototype
---
src/wallet.js | 123 ++++++++++++++++++++++++++++----------------------
1 file changed, 70 insertions(+), 53 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index 8dd2ca2b2..d904360f8 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -28,35 +28,6 @@ function Wallet(seed, network, unspents) {
// Transaction output data
this.outputs = unspents ? processUnspentOutputs(unspents) : {}
- this.generateAddress = function() {
- var key = externalAccount.derive(this.addresses.length)
- this.addresses.push(key.getAddress().toString())
- return this.addresses[this.addresses.length - 1]
- }
-
- this.generateChangeAddress = function() {
- var key = internalAccount.derive(this.changeAddresses.length)
- this.changeAddresses.push(key.getAddress().toString())
- return this.changeAddresses[this.changeAddresses.length - 1]
- }
-
- this.getBalance = function() {
- return this.getUnspentOutputs().reduce(function(memo, output){
- return memo + output.value
- }, 0)
- }
-
- this.getUnspentOutputs = function() {
- var utxo = []
-
- for(var key in this.outputs){
- var output = this.outputs[key]
- if(!output.to) utxo.push(outputToUnspentOutput(output))
- }
-
- return utxo
- }
-
// FIXME: remove in 2.x.y
this.newMasterKey = function(seed) {
console.warn('newMasterKey is deprecated, please make a new Wallet instance instead')
@@ -76,12 +47,6 @@ function Wallet(seed, network, unspents) {
me.outputs = {}
}
- this.setUnspentOutputs = function(utxo) {
- console.warn('setUnspentOutputs is deprecated, please use the constructor option instead')
-
- this.outputs = processUnspentOutputs(utxo)
- }
-
this.processPendingTx = function(tx){
processTx(tx, true)
}
@@ -161,7 +126,7 @@ function Wallet(seed, network, unspents) {
var change = accum - subTotal
if (change > network.dustThreshold) {
- tx.addOutput(changeAddress || getChangeAddress(), change)
+ tx.addOutput(changeAddress || this.getChangeAddress(), change)
}
break
@@ -174,23 +139,6 @@ function Wallet(seed, network, unspents) {
return tx
}
- function getChangeAddress() {
- if(me.changeAddresses.length === 0) me.generateChangeAddress();
- return me.changeAddresses[me.changeAddresses.length - 1]
- }
-
- this.signWith = function(tx, addresses) {
- assert.equal(tx.ins.length, addresses.length, 'Number of addresses must match number of transaction inputs')
-
- addresses.forEach(function(address, i) {
- var key = me.getPrivateKeyForAddress(address)
-
- tx.sign(i, key)
- })
-
- return tx
- }
-
this.getMasterKey = function() { return masterkey }
this.getAccountZero = function() { return accountZero }
this.getInternalAccount = function() { return internalAccount }
@@ -233,6 +181,75 @@ function Wallet(seed, network, unspents) {
}
}
+Wallet.prototype.generateAddress = function() {
+ var k = this.addresses.length
+ var address = this.getExternalAccount().derive(k).getAddress()
+
+ this.addresses.push(address.toString())
+
+ return this.getReceiveAddress()
+}
+
+Wallet.prototype.generateChangeAddress = function() {
+ var k = this.changeAddresses.length
+ var address = this.getInternalAccount().derive(k).getAddress()
+
+ this.changeAddresses.push(address.toString())
+
+ return this.getChangeAddress()
+}
+
+Wallet.prototype.getBalance = function() {
+ return this.getUnspentOutputs().reduce(function(accum, output) {
+ return accum + output.value
+ }, 0)
+}
+
+Wallet.prototype.getChangeAddress = function() {
+ if (this.changeAddresses.length === 0) {
+ this.generateChangeAddress()
+ }
+
+ return this.changeAddresses[this.changeAddresses.length - 1]
+}
+
+Wallet.prototype.getReceiveAddress = function() {
+ if (this.addresses.length === 0) {
+ this.generateAddress()
+ }
+
+ return this.addresses[this.addresses.length - 1]
+}
+
+Wallet.prototype.getUnspentOutputs = function() {
+ var utxo = []
+
+ for(var key in this.outputs){
+ var output = this.outputs[key]
+ if(!output.to) utxo.push(outputToUnspentOutput(output))
+ }
+
+ return utxo
+}
+
+Wallet.prototype.setUnspentOutputs = function(utxo) {
+ console.warn('setUnspentOutputs is deprecated, please use the constructor option instead')
+
+ this.outputs = processUnspentOutputs(utxo)
+}
+
+Wallet.prototype.signWith = function(tx, addresses) {
+ assert.equal(tx.ins.length, addresses.length, 'Number of addresses must match number of transaction inputs')
+
+ addresses.forEach(function(address, i) {
+ var key = this.getPrivateKeyForAddress(address)
+
+ tx.sign(i, key)
+ }, this)
+
+ return tx
+}
+
function outputToUnspentOutput(output){
var hashAndIndex = output.from.split(":")
From 6df785bb6591bf15e2b0fcc2d784c81ecd7fa008 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 14 Aug 2014 10:39:14 +1000
Subject: [PATCH 036/291] Wallet: move createTx to prototype
---
src/wallet.js | 96 ++++++++++++++++++++++++++-------------------------
1 file changed, 49 insertions(+), 47 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index d904360f8..ced3ac5e5 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -25,6 +25,8 @@ function Wallet(seed, network, unspents) {
this.addresses = []
this.changeAddresses = []
+ this.network = network
+
// Transaction output data
this.outputs = unspents ? processUnspentOutputs(unspents) : {}
@@ -100,58 +102,11 @@ function Wallet(seed, network, unspents) {
})
}
- this.createTx = function(to, value, fixedFee, changeAddress) {
- assert(value > network.dustThreshold, value + ' must be above dust threshold (' + network.dustThreshold + ' Satoshis)')
-
- var utxos = getCandidateOutputs(this.outputs, value)
- var accum = 0
- var subTotal = value
- var addresses = []
-
- var tx = new Transaction()
- tx.addOutput(to, value)
-
- for (var i = 0; i < utxos.length; ++i) {
- var utxo = utxos[i]
- addresses.push(utxo.address)
-
- var outpoint = utxo.from.split(':')
- tx.addInput(outpoint[0], parseInt(outpoint[1]))
-
- var fee = fixedFee == undefined ? estimatePaddedFee(tx, network) : fixedFee
-
- accum += utxo.value
- subTotal = value + fee
- if (accum >= subTotal) {
- var change = accum - subTotal
-
- if (change > network.dustThreshold) {
- tx.addOutput(changeAddress || this.getChangeAddress(), change)
- }
-
- break
- }
- }
-
- assert(accum >= subTotal, 'Not enough funds (incl. fee): ' + accum + ' < ' + subTotal)
-
- this.signWith(tx, addresses)
- return tx
- }
-
this.getMasterKey = function() { return masterkey }
this.getAccountZero = function() { return accountZero }
this.getInternalAccount = function() { return internalAccount }
this.getExternalAccount = function() { return externalAccount }
- this.getPrivateKey = function(index) {
- return externalAccount.derive(index).privKey
- }
-
- this.getInternalPrivateKey = function(index) {
- return internalAccount.derive(index).privKey
- }
-
this.getPrivateKeyForAddress = function(address) {
assert(isMyAddress(address), 'Unknown address. Make sure the address is from the keychain and has been generated')
@@ -181,6 +136,45 @@ function Wallet(seed, network, unspents) {
}
}
+Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
+ assert(value > this.network.dustThreshold, value + ' must be above dust threshold (' + this.network.dustThreshold + ' Satoshis)')
+
+ var utxos = getCandidateOutputs(this.outputs, value)
+ var accum = 0
+ var subTotal = value
+ var addresses = []
+
+ var tx = new Transaction()
+ tx.addOutput(to, value)
+
+ for (var i = 0; i < utxos.length; ++i) {
+ var utxo = utxos[i]
+ addresses.push(utxo.address)
+
+ var outpoint = utxo.from.split(':')
+ tx.addInput(outpoint[0], parseInt(outpoint[1]))
+
+ var fee = fixedFee == undefined ? estimatePaddedFee(tx, this.network) : fixedFee
+
+ accum += utxo.value
+ subTotal = value + fee
+ if (accum >= subTotal) {
+ var change = accum - subTotal
+
+ if (change > this.network.dustThreshold) {
+ tx.addOutput(changeAddress || this.getChangeAddress(), change)
+ }
+
+ break
+ }
+ }
+
+ assert(accum >= subTotal, 'Not enough funds (incl. fee): ' + accum + ' < ' + subTotal)
+
+ this.signWith(tx, addresses)
+ return tx
+}
+
Wallet.prototype.generateAddress = function() {
var k = this.addresses.length
var address = this.getExternalAccount().derive(k).getAddress()
@@ -213,6 +207,14 @@ Wallet.prototype.getChangeAddress = function() {
return this.changeAddresses[this.changeAddresses.length - 1]
}
+Wallet.prototype.getInternalPrivateKey = function(index) {
+ return this.getInternalAccount().derive(index).privKey
+}
+
+Wallet.prototype.getPrivateKey = function(index) {
+ return this.getExternalAccount().derive(index).privKey
+}
+
Wallet.prototype.getReceiveAddress = function() {
if (this.addresses.length === 0) {
this.generateAddress()
From c13177bb29acc7d3ab85d726190802722d05a4a6 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 14 Aug 2014 17:29:14 +1000
Subject: [PATCH 037/291] Wallet: rename masterkey to masterKey
---
src/wallet.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index ced3ac5e5..ad7ccbdc7 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -12,12 +12,12 @@ function Wallet(seed, network, unspents) {
network = network || networks.bitcoin
// Stored in a closure to make accidental serialization less likely
- var masterkey = HDNode.fromSeedBuffer(seed, network)
+ var masterKey = HDNode.fromSeedBuffer(seed, network)
var me = this
// HD first-level child derivation method should be hardened
// See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
- var accountZero = masterkey.deriveHardened(0)
+ var accountZero = masterKey.deriveHardened(0)
var externalAccount = accountZero.derive(0)
var internalAccount = accountZero.derive(1)
@@ -35,11 +35,11 @@ function Wallet(seed, network, unspents) {
console.warn('newMasterKey is deprecated, please make a new Wallet instance instead')
seed = seed || crypto.randomBytes(32)
- masterkey = HDNode.fromSeedBuffer(seed, network)
+ masterKey = HDNode.fromSeedBuffer(seed, network)
// HD first-level child derivation method should be hardened
// See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
- accountZero = masterkey.deriveHardened(0)
+ accountZero = masterKey.deriveHardened(0)
externalAccount = accountZero.derive(0)
internalAccount = accountZero.derive(1)
@@ -102,10 +102,10 @@ function Wallet(seed, network, unspents) {
})
}
- this.getMasterKey = function() { return masterkey }
+ this.getMasterKey = function() { return masterKey }
this.getAccountZero = function() { return accountZero }
- this.getInternalAccount = function() { return internalAccount }
this.getExternalAccount = function() { return externalAccount }
+ this.getInternalAccount = function() { return internalAccount }
this.getPrivateKeyForAddress = function(address) {
assert(isMyAddress(address), 'Unknown address. Make sure the address is from the keychain and has been generated')
From 2b4d94cd92495992ce27425acf40440c6e025dc5 Mon Sep 17 00:00:00 2001
From: Wei Lu
Date: Sat, 16 Aug 2014 14:19:19 +0800
Subject: [PATCH 038/291] Wallet: move processPendingTx & processConfirmedTx to
prototype
also, move processTx out of Wallet scope
---
src/wallet.js | 129 ++++++++++++++++++++++++--------------------------
1 file changed, 61 insertions(+), 68 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index ad7ccbdc7..23142d519 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -49,91 +49,28 @@ function Wallet(seed, network, unspents) {
me.outputs = {}
}
- this.processPendingTx = function(tx){
- processTx(tx, true)
- }
-
- this.processConfirmedTx = function(tx){
- processTx(tx, false)
- }
-
- var me = this
-
- function processTx(tx, isPending) {
- var txid = tx.getId()
-
- tx.outs.forEach(function(txOut, i) {
- var address
-
- try {
- address = Address.fromOutputScript(txOut.script, network).toString()
- } catch(e) {
- if (!(e.message.match(/has no matching Address/))) throw e
- }
-
- if (isMyAddress(address)) {
- var output = txid + ':' + i
-
- me.outputs[output] = {
- from: output,
- value: txOut.value,
- address: address,
- pending: isPending
- }
- }
- })
-
- tx.ins.forEach(function(txIn, i) {
- // copy and convert to big-endian hex
- var txinId = new Buffer(txIn.hash)
- Array.prototype.reverse.call(txinId)
- txinId = txinId.toString('hex')
-
- var output = txinId + ':' + txIn.index
-
- if (!(output in me.outputs)) return
-
- if (isPending) {
- me.outputs[output].to = txid + ':' + i
- me.outputs[output].pending = true
- } else {
- delete me.outputs[output]
- }
- })
- }
-
this.getMasterKey = function() { return masterKey }
this.getAccountZero = function() { return accountZero }
this.getExternalAccount = function() { return externalAccount }
this.getInternalAccount = function() { return internalAccount }
this.getPrivateKeyForAddress = function(address) {
- assert(isMyAddress(address), 'Unknown address. Make sure the address is from the keychain and has been generated')
+ var myAddresses = this.addresses.concat(this.changeAddresses)
+ assert(includeAddress(myAddresses, address),
+ 'Unknown address. Make sure the address is from the keychain and has been generated')
- if (isReceiveAddress(address)) {
+ if (includeAddress(this.addresses, address)) {
var index = this.addresses.indexOf(address)
return this.getPrivateKey(index)
}
- if (isChangeAddress(address)) {
+ if (includeAddress(this.changeAddresses, address)) {
var index = this.changeAddresses.indexOf(address)
return this.getInternalPrivateKey(index)
}
}
-
- function isReceiveAddress(address){
- return me.addresses.indexOf(address) > -1
- }
-
- function isChangeAddress(address){
- return me.changeAddresses.indexOf(address) > -1
- }
-
- function isMyAddress(address) {
- return isReceiveAddress(address) || isChangeAddress(address)
- }
}
Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
@@ -175,6 +112,14 @@ Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
return tx
}
+Wallet.prototype.processPendingTx = function(tx){
+ processTx.bind(this)(tx, true)
+}
+
+Wallet.prototype.processConfirmedTx = function(tx){
+ processTx.bind(this)(tx, false)
+}
+
Wallet.prototype.generateAddress = function() {
var k = this.addresses.length
var address = this.getExternalAccount().derive(k).getAddress()
@@ -316,4 +261,52 @@ function getCandidateOutputs(outputs/*, value*/) {
return sortByValueDesc
}
+function processTx(tx, isPending) {
+ var txid = tx.getId()
+
+ tx.outs.forEach(function(txOut, i) {
+ var address
+
+ try {
+ address = Address.fromOutputScript(txOut.script, this.network).toString()
+ } catch(e) {
+ if (!(e.message.match(/has no matching Address/))) throw e
+ }
+
+ var myAddresses = this.addresses.concat(this.changeAddresses)
+ if (includeAddress(myAddresses, address)) {
+ var output = txid + ':' + i
+
+ this.outputs[output] = {
+ from: output,
+ value: txOut.value,
+ address: address,
+ pending: isPending
+ }
+ }
+ }, this)
+
+ tx.ins.forEach(function(txIn, i) {
+ // copy and convert to big-endian hex
+ var txinId = new Buffer(txIn.hash)
+ Array.prototype.reverse.call(txinId)
+ txinId = txinId.toString('hex')
+
+ var output = txinId + ':' + txIn.index
+
+ if (!(output in this.outputs)) return
+
+ if (isPending) {
+ this.outputs[output].to = txid + ':' + i
+ this.outputs[output].pending = true
+ } else {
+ delete this.outputs[output]
+ }
+ }, this)
+}
+
+function includeAddress(addresses, address) {
+ return addresses.indexOf(address) > -1
+}
+
module.exports = Wallet
From 00d58604a47ecbe169c991ddc4f7e5fb247f7d57 Mon Sep 17 00:00:00 2001
From: Wei Lu
Date: Sat, 16 Aug 2014 14:24:24 +0800
Subject: [PATCH 039/291] Wallet: move getPrivateKeyForAddress to prototype
also, move the assert to the end to simplify the logic
---
src/wallet.js | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index 23142d519..137ec8691 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -53,24 +53,6 @@ function Wallet(seed, network, unspents) {
this.getAccountZero = function() { return accountZero }
this.getExternalAccount = function() { return externalAccount }
this.getInternalAccount = function() { return internalAccount }
-
- this.getPrivateKeyForAddress = function(address) {
- var myAddresses = this.addresses.concat(this.changeAddresses)
- assert(includeAddress(myAddresses, address),
- 'Unknown address. Make sure the address is from the keychain and has been generated')
-
- if (includeAddress(this.addresses, address)) {
- var index = this.addresses.indexOf(address)
-
- return this.getPrivateKey(index)
- }
-
- if (includeAddress(this.changeAddresses, address)) {
- var index = this.changeAddresses.indexOf(address)
-
- return this.getInternalPrivateKey(index)
- }
- }
}
Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
@@ -160,6 +142,22 @@ Wallet.prototype.getPrivateKey = function(index) {
return this.getExternalAccount().derive(index).privKey
}
+Wallet.prototype.getPrivateKeyForAddress = function(address) {
+ if (includeAddress(this.addresses, address)) {
+ var index = this.addresses.indexOf(address)
+
+ return this.getPrivateKey(index)
+ }
+
+ if (includeAddress(this.changeAddresses, address)) {
+ var index = this.changeAddresses.indexOf(address)
+
+ return this.getInternalPrivateKey(index)
+ }
+
+ assert(false, 'Unknown address. Make sure the address is from the keychain and has been generated')
+}
+
Wallet.prototype.getReceiveAddress = function() {
if (this.addresses.length === 0) {
this.generateAddress()
From e55676cf8e6b441dad5d747ea5da062338971c9d Mon Sep 17 00:00:00 2001
From: Wei Lu
Date: Sat, 16 Aug 2014 14:27:12 +0800
Subject: [PATCH 040/291] Wallet: remove unncessary comments
---
src/wallet.js | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index 137ec8691..6e2661204 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -13,7 +13,6 @@ function Wallet(seed, network, unspents) {
// Stored in a closure to make accidental serialization less likely
var masterKey = HDNode.fromSeedBuffer(seed, network)
- var me = this
// HD first-level child derivation method should be hardened
// See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
@@ -21,24 +20,19 @@ function Wallet(seed, network, unspents) {
var externalAccount = accountZero.derive(0)
var internalAccount = accountZero.derive(1)
- // Addresses
this.addresses = []
this.changeAddresses = []
-
this.network = network
-
- // Transaction output data
this.outputs = unspents ? processUnspentOutputs(unspents) : {}
// FIXME: remove in 2.x.y
+ var me = this
this.newMasterKey = function(seed) {
console.warn('newMasterKey is deprecated, please make a new Wallet instance instead')
seed = seed || crypto.randomBytes(32)
masterKey = HDNode.fromSeedBuffer(seed, network)
- // HD first-level child derivation method should be hardened
- // See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
accountZero = masterKey.deriveHardened(0)
externalAccount = accountZero.derive(0)
internalAccount = accountZero.derive(1)
From 4bb7f5b56d940d0f3936c80219f01560febaafc0 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 16 Aug 2014 17:15:13 +1000
Subject: [PATCH 041/291] Wallet: use indexOf explicitly over include*
---
src/wallet.js | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index 6e2661204..3b3daebd9 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -137,13 +137,13 @@ Wallet.prototype.getPrivateKey = function(index) {
}
Wallet.prototype.getPrivateKeyForAddress = function(address) {
- if (includeAddress(this.addresses, address)) {
+ if (this.addresses.indexOf(address) > -1) {
var index = this.addresses.indexOf(address)
return this.getPrivateKey(index)
}
- if (includeAddress(this.changeAddresses, address)) {
+ if (this.changeAddresses.indexOf(address) > -1) {
var index = this.changeAddresses.indexOf(address)
return this.getInternalPrivateKey(index)
@@ -266,7 +266,7 @@ function processTx(tx, isPending) {
}
var myAddresses = this.addresses.concat(this.changeAddresses)
- if (includeAddress(myAddresses, address)) {
+ if (myAddresses.indexOf(address) > -1) {
var output = txid + ':' + i
this.outputs[output] = {
@@ -297,8 +297,4 @@ function processTx(tx, isPending) {
}, this)
}
-function includeAddress(addresses, address) {
- return addresses.indexOf(address) > -1
-}
-
module.exports = Wallet
From 300facf7aa2dfe8a32e451e99ab1756af4b8e9ae Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 16 Aug 2014 17:22:34 +1000
Subject: [PATCH 042/291] Wallet: use === when comparing with undefined
---
src/wallet.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/wallet.js b/src/wallet.js
index 3b3daebd9..270b27001 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -67,7 +67,7 @@ Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
var outpoint = utxo.from.split(':')
tx.addInput(outpoint[0], parseInt(outpoint[1]))
- var fee = fixedFee == undefined ? estimatePaddedFee(tx, this.network) : fixedFee
+ var fee = fixedFee === undefined ? estimatePaddedFee(tx, this.network) : fixedFee
accum += utxo.value
subTotal = value + fee
From 9620b68fe2009d9bb9bb646e005804168e018a32 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 16 Aug 2014 17:22:56 +1000
Subject: [PATCH 043/291] Wallet: use __processTx over a free function
The use of bind in this case wasn't idiomatic.
---
src/wallet.js | 92 +++++++++++++++++++++++++--------------------------
1 file changed, 46 insertions(+), 46 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index 270b27001..e596b6698 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -89,11 +89,55 @@ Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
}
Wallet.prototype.processPendingTx = function(tx){
- processTx.bind(this)(tx, true)
+ this.__processTx(tx, true)
}
Wallet.prototype.processConfirmedTx = function(tx){
- processTx.bind(this)(tx, false)
+ this.__processTx(tx, false)
+}
+
+Wallet.prototype.__processTx = function(tx, isPending) {
+ var txid = tx.getId()
+
+ tx.outs.forEach(function(txOut, i) {
+ var address
+
+ try {
+ address = Address.fromOutputScript(txOut.script, this.network).toString()
+ } catch(e) {
+ if (!(e.message.match(/has no matching Address/))) throw e
+ }
+
+ var myAddresses = this.addresses.concat(this.changeAddresses)
+ if (myAddresses.indexOf(address) > -1) {
+ var output = txid + ':' + i
+
+ this.outputs[output] = {
+ from: output,
+ value: txOut.value,
+ address: address,
+ pending: isPending
+ }
+ }
+ }, this)
+
+ tx.ins.forEach(function(txIn, i) {
+ // copy and convert to big-endian hex
+ var txinId = new Buffer(txIn.hash)
+ Array.prototype.reverse.call(txinId)
+ txinId = txinId.toString('hex')
+
+ var output = txinId + ':' + txIn.index
+
+ if (!(output in this.outputs)) return
+
+ if (isPending) {
+ this.outputs[output].to = txid + ':' + i
+ this.outputs[output].pending = true
+ } else {
+ delete this.outputs[output]
+ }
+ }, this)
}
Wallet.prototype.generateAddress = function() {
@@ -253,48 +297,4 @@ function getCandidateOutputs(outputs/*, value*/) {
return sortByValueDesc
}
-function processTx(tx, isPending) {
- var txid = tx.getId()
-
- tx.outs.forEach(function(txOut, i) {
- var address
-
- try {
- address = Address.fromOutputScript(txOut.script, this.network).toString()
- } catch(e) {
- if (!(e.message.match(/has no matching Address/))) throw e
- }
-
- var myAddresses = this.addresses.concat(this.changeAddresses)
- if (myAddresses.indexOf(address) > -1) {
- var output = txid + ':' + i
-
- this.outputs[output] = {
- from: output,
- value: txOut.value,
- address: address,
- pending: isPending
- }
- }
- }, this)
-
- tx.ins.forEach(function(txIn, i) {
- // copy and convert to big-endian hex
- var txinId = new Buffer(txIn.hash)
- Array.prototype.reverse.call(txinId)
- txinId = txinId.toString('hex')
-
- var output = txinId + ':' + txIn.index
-
- if (!(output in this.outputs)) return
-
- if (isPending) {
- this.outputs[output].to = txid + ':' + i
- this.outputs[output].pending = true
- } else {
- delete this.outputs[output]
- }
- }, this)
-}
-
module.exports = Wallet
From 897bbf4eb4defb20f005880e0104fd8e6aa0005e Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 16 Aug 2014 17:23:24 +1000
Subject: [PATCH 044/291] Wallet: assign indexOf in the same step
---
src/wallet.js | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index e596b6698..29f124bd9 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -181,15 +181,13 @@ Wallet.prototype.getPrivateKey = function(index) {
}
Wallet.prototype.getPrivateKeyForAddress = function(address) {
- if (this.addresses.indexOf(address) > -1) {
- var index = this.addresses.indexOf(address)
+ var index
+ if ((index = this.addresses.indexOf(address)) > -1) {
return this.getPrivateKey(index)
}
- if (this.changeAddresses.indexOf(address) > -1) {
- var index = this.changeAddresses.indexOf(address)
-
+ if ((index = this.changeAddresses.indexOf(address)) > -1) {
return this.getInternalPrivateKey(index)
}
From 884fd542fec61fc23794b204280416558883d55f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 25 Jul 2014 16:11:45 +1000
Subject: [PATCH 045/291] Transaction: deprecate Tx signing methods
---
src/transaction.js | 38 ++++++++++++++++++++++++++------------
test/bitcoin.core.js | 2 +-
test/transaction.js | 2 +-
3 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index 1bfff5d1e..d8a0fc47b 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -162,7 +162,17 @@ Transaction.prototype.toHex = function() {
* hashType, serializes and finally hashes the result. This hash can then be
* used to sign the transaction input in question.
*/
-Transaction.prototype.hashForSignature = function(prevOutScript, inIndex, hashType) {
+Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashType) {
+ // FIXME: remove in 2.x.y
+ if (arguments[0] instanceof Script) {
+ console.warn('hashForSignature(prevOutScript, inIndex, ...) has been deprecated. Use hashForSignature(inIndex, prevOutScript, ...)')
+
+ // swap the arguments (must be stored in tmp, arguments is special)
+ var tmp = arguments[0]
+ inIndex = arguments[1]
+ prevOutScript = tmp
+ }
+
assert(inIndex >= 0, 'Invalid vin index')
assert(inIndex < this.ins.length, 'Invalid vin index')
assert(prevOutScript instanceof Script, 'Invalid Script object')
@@ -296,35 +306,39 @@ Transaction.fromHex = function(hex) {
return Transaction.fromBuffer(new Buffer(hex, 'hex'))
}
-/**
- * Signs a pubKeyHash output at some index with the given key
- */
+Transaction.prototype.setInputScript = function(index, script) {
+ this.ins[index].script = script
+}
+
+// FIXME: remove in 2.x.y
Transaction.prototype.sign = function(index, privKey, hashType) {
+ console.warn("Transaction.prototype.sign is deprecated. Use TransactionBuilder instead.")
+
var prevOutScript = privKey.pub.getAddress().toOutputScript()
var signature = this.signInput(index, prevOutScript, privKey, hashType)
- // FIXME: Assumed prior TX was pay-to-pubkey-hash
var scriptSig = scripts.pubKeyHashInput(signature, privKey.pub)
this.setInputScript(index, scriptSig)
}
+// FIXME: remove in 2.x.y
Transaction.prototype.signInput = function(index, prevOutScript, privKey, hashType) {
+ console.warn("Transaction.prototype.signInput is deprecated. Use TransactionBuilder instead.")
+
hashType = hashType || Transaction.SIGHASH_ALL
- var hash = this.hashForSignature(prevOutScript, index, hashType)
+ var hash = this.hashForSignature(index, prevOutScript, hashType)
var signature = privKey.sign(hash)
return signature.toScriptSignature(hashType)
}
-Transaction.prototype.setInputScript = function(index, script) {
- this.ins[index].script = script
-}
-
-// FIXME: could be validateInput(index, prevTxOut, pub)
+// FIXME: remove in 2.x.y
Transaction.prototype.validateInput = function(index, prevOutScript, pubKey, buffer) {
+ console.warn("Transaction.prototype.validateInput is deprecated. Use TransactionBuilder instead.")
+
var parsed = ECSignature.parseScriptSignature(buffer)
- var hash = this.hashForSignature(prevOutScript, index, parsed.hashType)
+ var hash = this.hashForSignature(index, prevOutScript, parsed.hashType)
return pubKey.verify(hash, parsed.signature)
}
diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js
index 71bd7e6f9..5cf004b2c 100644
--- a/test/bitcoin.core.js
+++ b/test/bitcoin.core.js
@@ -183,7 +183,7 @@ describe('Bitcoin-core', function() {
var actualHash
try {
- actualHash = transaction.hashForSignature(script, inIndex, hashType)
+ actualHash = transaction.hashForSignature(inIndex, script, hashType)
} catch (e) {
// don't fail if we don't support it yet, TODO
if (!e.message.match(/not yet supported/)) throw e
diff --git a/test/transaction.js b/test/transaction.js
index a8aa1d79c..fc2711d39 100644
--- a/test/transaction.js
+++ b/test/transaction.js
@@ -221,7 +221,7 @@ describe('Transaction', function() {
// TODO:
// hashForSignature: [Function],
- // FIXME: could be better
+ // FIXME: remove in 2.x.y
describe('signInput/validateInput', function() {
it('works for multi-sig redeem script', function() {
var tx = new Transaction()
From 15dc92049cfb2289b413a2de92724ae53bc4566c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 16 Aug 2014 16:53:15 +1000
Subject: [PATCH 046/291] LICENSE: Updated date and copyright notice
---
LICENSE | 22 ++++++++++++++++++----
README.md | 11 ++++++-----
2 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/LICENSE b/LICENSE
index a9c891371..2b07c4258 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,21 @@
-Copyright (c) 2011 Stefan Thomas
+The MIT License (MIT)
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+Copyright (c) 2011-2014 Bitcoinjs-lib contributors
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 76bccd6fc..3c2c54583 100644
--- a/README.md
+++ b/README.md
@@ -110,13 +110,13 @@ console.log(tx.toHex())
``` javascript
var bitcoin = require('bitcoinjs-lib')
-
+
var privKeys = [bitcoin.ECKey.makeRandom(), bitcoin.ECKey.makeRandom(), bitcoin.ECKey.makeRandom()]
var pubKeys = privKeys.map(function(x) { return x.pub })
-
+
var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3
var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
-
+
var multisigAddress = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
console.log("multisigP2SH:", multisigAddress)
@@ -138,7 +138,7 @@ console.log("multisigP2SH:", multisigAddress)
- [Dogechain Wallet](https://dogechain.info)
- [GreenAddress](https://greenaddress.it)
- [DecentralBank](http://decentralbank.com)
-
+
## Contributors
Stefan Thomas is the inventor and creator of this project. His pioneering work made Bitcoin web wallets possible.
@@ -174,6 +174,7 @@ Please make your best effort to adhere to these when contributing to save on tri
- [Bitcore](https://github.com/bitpay/bitcore)
- [Cryptocoin](https://github.com/cryptocoinjs/cryptocoin)
+
## License
This library is free and open-source software released under the MIT license.
@@ -181,5 +182,5 @@ This library is free and open-source software released under the MIT license.
## Copyright
-BitcoinJS (c) 2011-2012 Stefan Thomas
+BitcoinJS (c) 2011-2014 Bitcoinjs-lib contributors
Released under MIT license
From bcbcd58964a8124bae20f504ab1975bf6d490e52 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 16 Jun 2014 16:05:31 +1000
Subject: [PATCH 047/291] TxBuilder: Initial commit and tests
---
src/transaction_builder.js | 159 +++++++++++++++++
test/fixtures/transaction_builder.json | 113 ++++++++++++
test/transaction_builder.js | 228 +++++++++++++++++++++++++
3 files changed, 500 insertions(+)
create mode 100644 src/transaction_builder.js
create mode 100644 test/fixtures/transaction_builder.json
create mode 100644 test/transaction_builder.js
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
new file mode 100644
index 000000000..e284d6346
--- /dev/null
+++ b/src/transaction_builder.js
@@ -0,0 +1,159 @@
+var assert = require('assert')
+var scripts = require('./scripts')
+
+var ECKey = require('./eckey')
+var Transaction = require('./transaction')
+var Script = require('./script')
+
+function TransactionBuilder() {
+ this.prevOutMap = {}
+ this.prevOutScripts = {}
+ this.prevOutTypes = {}
+
+ this.signatures = []
+ this.tx = new Transaction()
+}
+
+TransactionBuilder.prototype.addInput = function(prevTx, index, prevOutScript) {
+ var prevOutHash
+
+ if (typeof prevTx === 'string') {
+ prevOutHash = new Buffer(prevTx, 'hex')
+
+ // TxId hex is big-endian, we want little-endian hash
+ Array.prototype.reverse.call(prevOutHash)
+
+ } else if (prevTx instanceof Transaction) {
+ assert(prevOutScript === undefined, 'Unnecessary Script provided')
+
+ prevOutHash = prevTx.getHash()
+ prevOutScript = prevTx.outs[index].script
+
+ } else {
+ prevOutHash = prevTx
+
+ }
+
+ var prevOutType
+ if (prevOutScript !== undefined) {
+ prevOutType = scripts.classifyOutput(prevOutScript)
+
+ assert.notEqual(prevOutType, 'nonstandard', 'PrevOutScript not supported (nonstandard)')
+ }
+
+ assert(this.signatures.every(function(input) {
+ return input.hashType & Transaction.SIGHASH_ANYONECANPAY
+ }), 'No, this would invalidate signatures')
+
+ var prevOut = prevOutHash.toString('hex') + ':' + index
+ assert(!(prevOut in this.prevOutMap), 'Transaction is already an input')
+
+ var vout = this.tx.addInput(prevOutHash, index)
+ this.prevOutMap[prevOut] = true
+ this.prevOutScripts[vout] = prevOutScript
+ this.prevOutTypes[vout] = prevOutType
+
+ return vout
+}
+
+TransactionBuilder.prototype.addOutput = function(scriptPubKey, value) {
+ assert(this.signatures.every(function(signature) {
+ return (signature.hashType & 0x1f) === Transaction.SIGHASH_SINGLE
+ }), 'No, this would invalidate signatures')
+
+ return this.tx.addOutput(scriptPubKey, value)
+}
+
+TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashType) {
+ assert(this.tx.ins.length >= index, 'No input at index: ' + index)
+ hashType = hashType || Transaction.SIGHASH_ALL
+
+ var prevOutScript = this.prevOutScripts[index]
+ var prevOutType = this.prevOutTypes[index]
+
+ var scriptType, hash
+ if (redeemScript) {
+ prevOutScript = prevOutScript || scripts.scriptHashOutput(redeemScript.getHash())
+ prevOutType = prevOutType || 'scripthash'
+
+ assert.equal(prevOutType, 'scripthash', 'PrevOutScript must be P2SH')
+
+ scriptType = scripts.classifyOutput(redeemScript)
+
+ assert.notEqual(scriptType, 'scripthash', 'RedeemScript can\'t be P2SH')
+ assert.notEqual(scriptType, 'nonstandard', 'RedeemScript not supported (nonstandard)')
+
+ hash = this.tx.hashForSignature(index, redeemScript, hashType)
+
+ } else {
+ prevOutScript = prevOutScript || privKey.pub.getAddress().toOutputScript()
+ scriptType = prevOutType || 'pubkeyhash'
+
+ assert.notEqual(scriptType, 'scripthash', 'PrevOutScript requires redeemScript')
+
+ hash = this.tx.hashForSignature(index, prevOutScript, hashType)
+ }
+
+ var signature = privKey.sign(hash)
+
+ if (!(index in this.signatures)) {
+ this.signatures[index] = {
+ hashType: hashType,
+ pubKeys: [],
+ redeemScript: redeemScript,
+ scriptType: scriptType,
+ signatures: []
+ }
+ }
+
+ var input = this.signatures[index]
+ input.pubKeys.push(privKey.pub)
+ input.signatures.push(signature)
+
+ assert.equal(input.hashType, hashType, 'Inconsistent hashType')
+ assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
+}
+
+TransactionBuilder.prototype.build = function(allowIncomplete) {
+ if (!allowIncomplete) {
+ assert(this.tx.ins.length > 0, 'Transaction has no inputs')
+ assert(this.tx.outs.length > 0, 'Transaction has no outputs')
+ assert.equal(this.signatures.length, this.tx.ins.length, 'Transaction is missing signatures')
+ }
+
+ var tx = this.tx.clone()
+
+ this.signatures.forEach(function(input, index) {
+ var scriptSig
+
+ if (input.scriptType === 'pubkeyhash') {
+ var signature = input.signatures[0].toScriptSignature(input.hashType)
+ var publicKey = input.pubKeys[0]
+ scriptSig = scripts.pubKeyHashInput(signature, publicKey)
+
+ } else if (input.scriptType === 'multisig') {
+ var redeemScript = allowIncomplete ? undefined : input.redeemScript
+ var signatures = input.signatures.map(function(signature) {
+ return signature.toScriptSignature(input.hashType)
+ })
+ scriptSig = scripts.multisigInput(signatures, redeemScript)
+
+ } else if (input.scriptType === 'pubkey') {
+ var signature = input.signatures[0]
+ scriptSig = scripts.pubKeyInput(signature)
+
+ } else {
+ assert(false, input.scriptType + ' not supported')
+ }
+
+ if (input.redeemScript) {
+ scriptSig = scripts.scriptHashInput(scriptSig, input.redeemScript)
+ }
+
+ tx.setInputScript(index, scriptSig)
+ })
+
+ return tx
+}
+
+module.exports = TransactionBuilder
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
new file mode 100644
index 000000000..69c1fea3d
--- /dev/null
+++ b/test/fixtures/transaction_builder.json
@@ -0,0 +1,113 @@
+{
+ "valid": {
+ "build": [
+ {
+ "description": "pubKeyHash 1:1 transaction",
+ "txid": "bd641f4b0aa8bd70189ab45e935c4762f0e1c49f294b4779d79887937b7cf42e",
+ "inputs": [
+ {
+ "index": 0,
+ "prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "privKeys": ["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]
+ }
+ ],
+ "outputs": [
+ {
+ "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+ "value": 10000
+ }
+ ]
+ },
+ {
+ "description": "2-of-2 P2SH multisig Transaction",
+ "txid": "8c500ce6eef6c78a10de923b68394cf31120151bdc4600e4b12de865defa9d24",
+ "inputs": [
+ {
+ "index": 0,
+ "prevTx": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+ "privKeys": ["91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"],
+ "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG"
+ }
+ ],
+ "outputs": [
+ {
+ "script": "OP_DUP OP_HASH160 faf1d99bf040ea9c7f8cc9f14ac6733ad75ce246 OP_EQUALVERIFY OP_CHECKSIG",
+ "value": 10000
+ }
+ ]
+ }
+ ]
+ },
+ "invalid": {
+ "build": [
+ {
+ "exception": "Transaction has no inputs",
+ "hex": "",
+ "outputs": [
+ {
+ "script": "",
+ "value": 1000
+ }
+ ]
+ },
+ {
+ "exception": "Transaction has no outputs",
+ "hex": "",
+ "inputs": [
+ {
+ "hash": "",
+ "index": 0
+ }
+ ]
+ },
+ {
+ "exception": "Transaction has no signatures",
+ "hex": "",
+ "inputs": [
+ {
+ "hash": "",
+ "index": 0
+ }
+ ],
+ "outputs": [
+ {
+ "script": "",
+ "value": 1000
+ }
+ ]
+ },
+ {
+ "exception": "Transaction is missing signatures",
+ "hex": "",
+ "inputs": [
+ {
+ "hash": "",
+ "index": 0
+ },
+ {
+ "hash": "",
+ "index": 1
+ }
+ ],
+ "outputs": [
+ {
+ "script": "",
+ "value": 1000
+ }
+ ],
+ "signatures": [
+ {
+ "wif": "",
+ "index": 0
+ }
+ ]
+ }
+ ],
+ "fromTransaction": [
+ {
+ "exception": "Transaction contains unsupported script types",
+ "hex": ""
+ }
+ ]
+ }
+}
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
new file mode 100644
index 000000000..4a7f0eacb
--- /dev/null
+++ b/test/transaction_builder.js
@@ -0,0 +1,228 @@
+var assert = require('assert')
+var ecdsa = require('../src/ecdsa')
+var scripts = require('../src/scripts')
+
+var Address = require('../src/address')
+var BigInteger = require('bigi')
+var ECKey = require('../src/eckey')
+var Script = require('../src/script')
+var Transaction = require('../src/transaction')
+var TransactionBuilder = require('../src/transaction_builder')
+
+var fixtures = require('./fixtures/transaction_builder')
+
+describe('TransactionBuilder', function() {
+ var privAddress, privScript
+ var prevTx, prevTxHash
+ var privKey
+ var txb
+
+ beforeEach(function() {
+ txb = new TransactionBuilder()
+
+ prevTx = new Transaction()
+ prevTx.addOutput('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH', 0)
+ prevTx.addOutput('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP', 1)
+ prevTxHash = prevTx.getHash()
+ prevTxId = prevTx.getId()
+
+ privKey = new ECKey(BigInteger.ONE, false)
+ privAddress = privKey.pub.getAddress()
+ privScript = privAddress.toOutputScript()
+ value = 10000
+ })
+
+ describe('addInput', function() {
+ it('accepts a txHash and index', function() {
+ var vin = txb.addInput(prevTxHash, 1)
+ assert.equal(vin, 0)
+
+ var txin = txb.tx.ins[0]
+ assert.equal(txin.hash, prevTxHash)
+ assert.equal(txin.index, 1)
+ assert.equal(txb.prevOutScripts[0], undefined)
+ })
+
+ it('accepts a txHash, index and scriptPubKey', function() {
+ var vin = txb.addInput(prevTxHash, 1, prevTx.outs[1].script)
+ assert.equal(vin, 0)
+
+ var txin = txb.tx.ins[0]
+ assert.equal(txin.hash, prevTxHash)
+ assert.equal(txin.index, 1)
+ assert.equal(txb.prevOutScripts[0], prevTx.outs[1].script)
+ })
+
+ it('accepts a prevTx and index', function() {
+ var vin = txb.addInput(prevTx, 1)
+ assert.equal(vin, 0)
+
+ var txin = txb.tx.ins[0]
+ assert.deepEqual(txin.hash, prevTxHash)
+ assert.equal(txin.index, 1)
+ assert.equal(txb.prevOutScripts[0], prevTx.outs[1].script)
+ })
+
+ it('returns the input index', function() {
+ assert.equal(txb.addInput(prevTxHash, 0), 0)
+ assert.equal(txb.addInput(prevTxHash, 1), 1)
+ })
+
+ it('throws if a Tx and prevOutScript is given', function() {
+ assert.throws(function() {
+ txb.addInput(prevTx, 0, privScript)
+ }, /Unnecessary Script provided/)
+ })
+
+ it('throws if prevOutScript is not supported', function() {
+ assert.throws(function() {
+ txb.addInput(prevTxHash, 0, Script.EMPTY)
+ }, /PrevOutScript not supported \(nonstandard\)/)
+ })
+
+ it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function() {
+ txb.addInput(prevTxHash, 0)
+ txb.sign(0, privKey)
+
+ assert.throws(function() {
+ txb.addInput(prevTxHash, 0)
+ }, /No, this would invalidate signatures/)
+ })
+ })
+
+ describe('addOutput', function() {
+ it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function() {
+ txb.addInput(prevTxHash, 0)
+ txb.addOutput(privScript, value)
+ txb.sign(0, privKey)
+
+ assert.throws(function() {
+ txb.addOutput(privScript, 9000)
+ }, /No, this would invalidate signatures/)
+ })
+ })
+
+ describe('sign', function() {
+ describe('when prevOutScript is undefined', function() {
+ it('assumes pubKeyHash', function() {
+ txb.addInput(prevTxHash, 0)
+ txb.sign(0, privKey)
+
+ assert.strictEqual(txb.signatures[0].redeemScript, undefined)
+ assert.equal(txb.signatures[0].scriptType, 'pubkeyhash')
+ })
+ })
+
+ describe('when redeemScript is defined', function() {
+ it('assumes scriptHash', function() {
+ txb.addInput(prevTxHash, 0)
+ txb.sign(0, privKey, privScript)
+
+ assert.equal(txb.signatures[0].redeemScript, privScript)
+ })
+
+ it('throws if prevOutScript is not P2SH', function() {
+ txb.addInput(prevTx, 0)
+
+ assert.throws(function() {
+ txb.sign(0, privKey, privScript)
+ }, /PrevOutScript must be P2SH/)
+ })
+
+ it('throws if redeemScript is P2SH', function() {
+ txb.addInput(prevTxHash, 0)
+
+ var privScriptP2SH = scripts.scriptHashOutput(privScript.getHash())
+
+ assert.throws(function() {
+ txb.sign(0, privKey, privScriptP2SH)
+ }, /RedeemScript can\'t be P2SH/)
+ })
+
+ it('throws if redeemScript not supported', function() {
+ txb.addInput(prevTxHash, 0)
+
+ assert.throws(function() {
+ txb.sign(0, privKey, Script.EMPTY)
+ }, /RedeemScript not supported \(nonstandard\)/)
+ })
+ })
+ })
+
+ describe('build', function() {
+ fixtures.valid.build.forEach(function(f) {
+ it('builds the correct transaction', function() {
+ f.inputs.forEach(function(input) {
+ var prevTx
+ if (input.prevTx.length === 64) {
+ prevTx = input.prevTx
+ } else {
+ prevTx = Transaction.fromHex(input.prevTx)
+ }
+
+ txb.addInput(prevTx, input.index)
+ })
+
+ f.outputs.forEach(function(output) {
+ var script = Script.fromASM(output.script)
+
+ txb.addOutput(script, output.value)
+ })
+
+ f.inputs.forEach(function(input, index) {
+ var redeemScript
+
+ if (input.redeemScript) {
+ redeemScript = Script.fromASM(input.redeemScript)
+ }
+
+ input.privKeys.forEach(function(wif) {
+ var privKey = ECKey.fromWIF(wif)
+
+ txb.sign(index, privKey, redeemScript)
+ })
+ })
+
+ var tx = txb.build()
+
+ assert.equal(tx.getId(), f.txid)
+ })
+ })
+
+ it('throws if Transaction has no inputs', function() {
+ txb.addOutput(privScript, value)
+
+ assert.throws(function() {
+ txb.build()
+ }, /Transaction has no inputs/)
+ })
+
+ it('throws if Transaction has no outputs', function() {
+ txb.addInput(prevTxHash, 0)
+
+ assert.throws(function() {
+ txb.build()
+ }, /Transaction has no outputs/)
+ })
+
+ it('throws if Transaction has no signatures', function() {
+ txb.addInput(prevTxHash, 0)
+ txb.addOutput(privScript, value)
+
+ assert.throws(function() {
+ txb.build()
+ }, /Transaction is missing signatures/)
+ })
+
+ it('throws if Transaction has not enough signatures', function() {
+ txb.addInput(prevTxHash, 0)
+ txb.addInput(prevTxHash, 1)
+ txb.addOutput(privScript, value)
+ txb.sign(0, privKey)
+
+ assert.throws(function() {
+ txb.build()
+ }, /Transaction is missing signatures/)
+ })
+ })
+})
From 36b225a3df9a0f58774bbf2090828ded9dd1be72 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 16 Jul 2014 22:24:10 +1000
Subject: [PATCH 048/291] TxBuilder: use data fixtures for invalid tests
---
src/transaction_builder.js | 1 +
test/fixtures/transaction_builder.json | 46 ++++++++-------------
test/transaction_builder.js | 57 ++++++++++++++------------
3 files changed, 49 insertions(+), 55 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index e284d6346..6611bca5e 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -118,6 +118,7 @@ TransactionBuilder.prototype.build = function(allowIncomplete) {
if (!allowIncomplete) {
assert(this.tx.ins.length > 0, 'Transaction has no inputs')
assert(this.tx.outs.length > 0, 'Transaction has no outputs')
+ assert(this.signatures.length > 0, 'Transaction has no signatures')
assert.equal(this.signatures.length, this.tx.ins.length, 'Transaction is missing signatures')
}
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index 69c1fea3d..894680508 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -42,72 +42,62 @@
"build": [
{
"exception": "Transaction has no inputs",
- "hex": "",
+ "inputs": [],
"outputs": [
{
- "script": "",
+ "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
"value": 1000
}
]
},
{
"exception": "Transaction has no outputs",
- "hex": "",
"inputs": [
{
- "hash": "",
- "index": 0
+ "index": 0,
+ "prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "privKeys": []
}
- ]
+ ],
+ "outputs": []
},
{
"exception": "Transaction has no signatures",
- "hex": "",
"inputs": [
{
- "hash": "",
- "index": 0
+ "index": 0,
+ "prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "privKeys": []
}
],
"outputs": [
{
- "script": "",
+ "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
"value": 1000
}
]
},
{
"exception": "Transaction is missing signatures",
- "hex": "",
"inputs": [
{
- "hash": "",
- "index": 0
+ "index": 0,
+ "prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "privKeys": ["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]
},
{
- "hash": "",
- "index": 1
+ "index": 1,
+ "prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "privKeys": []
}
],
"outputs": [
{
- "script": "",
+ "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
"value": 1000
}
- ],
- "signatures": [
- {
- "wif": "",
- "index": 0
- }
]
}
- ],
- "fromTransaction": [
- {
- "exception": "Transaction contains unsupported script types",
- "hex": ""
- }
]
}
}
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 4a7f0eacb..36ad20cfb 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -189,40 +189,43 @@ describe('TransactionBuilder', function() {
})
})
- it('throws if Transaction has no inputs', function() {
- txb.addOutput(privScript, value)
+ fixtures.invalid.build.forEach(function(f) {
+ it('throws on ' + f.exception, function() {
+ f.inputs.forEach(function(input) {
+ var prevTx
+ if (input.prevTx.length === 64) {
+ prevTx = input.prevTx
+ } else {
+ prevTx = Transaction.fromHex(input.prevTx)
+ }
- assert.throws(function() {
- txb.build()
- }, /Transaction has no inputs/)
- })
+ txb.addInput(prevTx, input.index)
+ })
- it('throws if Transaction has no outputs', function() {
- txb.addInput(prevTxHash, 0)
+ f.outputs.forEach(function(output) {
+ var script = Script.fromASM(output.script)
- assert.throws(function() {
- txb.build()
- }, /Transaction has no outputs/)
- })
+ txb.addOutput(script, output.value)
+ })
- it('throws if Transaction has no signatures', function() {
- txb.addInput(prevTxHash, 0)
- txb.addOutput(privScript, value)
+ f.inputs.forEach(function(input, index) {
+ var redeemScript
- assert.throws(function() {
- txb.build()
- }, /Transaction is missing signatures/)
- })
+ if (input.redeemScript) {
+ redeemScript = Script.fromASM(input.redeemScript)
+ }
- it('throws if Transaction has not enough signatures', function() {
- txb.addInput(prevTxHash, 0)
- txb.addInput(prevTxHash, 1)
- txb.addOutput(privScript, value)
- txb.sign(0, privKey)
+ input.privKeys.forEach(function(wif) {
+ var privKey = ECKey.fromWIF(wif)
- assert.throws(function() {
- txb.build()
- }, /Transaction is missing signatures/)
+ txb.sign(index, privKey, redeemScript)
+ })
+ })
+
+ assert.throws(function() {
+ txb.build()
+ }, new RegExp(f.exception))
+ })
})
})
})
From 377b815417011d4839381ff7967cb1cf3e416b55 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 16 Jul 2014 22:37:28 +1000
Subject: [PATCH 049/291] TxBuilder: transform all signatures once
---
src/transaction_builder.js | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 6611bca5e..07fce4b9b 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -127,24 +127,26 @@ TransactionBuilder.prototype.build = function(allowIncomplete) {
this.signatures.forEach(function(input, index) {
var scriptSig
+ var signatures = input.signatures.map(function(signature) {
+ return signature.toScriptSignature(input.hashType)
+ })
+
if (input.scriptType === 'pubkeyhash') {
- var signature = input.signatures[0].toScriptSignature(input.hashType)
+ var signature = signatures[0]
var publicKey = input.pubKeys[0]
scriptSig = scripts.pubKeyHashInput(signature, publicKey)
} else if (input.scriptType === 'multisig') {
var redeemScript = allowIncomplete ? undefined : input.redeemScript
- var signatures = input.signatures.map(function(signature) {
- return signature.toScriptSignature(input.hashType)
- })
scriptSig = scripts.multisigInput(signatures, redeemScript)
} else if (input.scriptType === 'pubkey') {
- var signature = input.signatures[0]
+ var signature = signatures[0]
scriptSig = scripts.pubKeyInput(signature)
} else {
assert(false, input.scriptType + ' not supported')
+
}
if (input.redeemScript) {
From 4e3a6c9557b75a37f256648c5dc695d93799fb86 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 15 Aug 2014 13:13:36 +1000
Subject: [PATCH 050/291] TxBuilder: use build/buildIncomplete over boolean
---
src/transaction_builder.js | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 07fce4b9b..b2e039609 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -114,7 +114,15 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
}
-TransactionBuilder.prototype.build = function(allowIncomplete) {
+TransactionBuilder.prototype.build = function() {
+ return this.__build(false)
+}
+
+TransactionBuilder.prototype.buildIncomplete = function() {
+ return this.__build(true)
+}
+
+TransactionBuilder.prototype.__build = function(allowIncomplete) {
if (!allowIncomplete) {
assert(this.tx.ins.length > 0, 'Transaction has no inputs')
assert(this.tx.outs.length > 0, 'Transaction has no outputs')
From 26b028adcf564030db4f5aeeefb1427f968b8071 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 16 Jul 2014 22:43:40 +1000
Subject: [PATCH 051/291] Wallet: use TxBuilder instead
---
src/wallet.js | 25 +++++++++++--------------
test/wallet.js | 9 +++++----
2 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index 29f124bd9..af28be07d 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -4,7 +4,7 @@ var networks = require('./networks')
var Address = require('./address')
var HDNode = require('./hdnode')
-var Transaction = require('./transaction')
+var TransactionBuilder = require('./transaction_builder')
var Script = require('./script')
function Wallet(seed, network, unspents) {
@@ -57,17 +57,17 @@ Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
var subTotal = value
var addresses = []
- var tx = new Transaction()
- tx.addOutput(to, value)
+ var txb = new TransactionBuilder()
+ txb.addOutput(to, value)
for (var i = 0; i < utxos.length; ++i) {
var utxo = utxos[i]
addresses.push(utxo.address)
var outpoint = utxo.from.split(':')
- tx.addInput(outpoint[0], parseInt(outpoint[1]))
+ txb.addInput(outpoint[0], parseInt(outpoint[1]))
- var fee = fixedFee === undefined ? estimatePaddedFee(tx, this.network) : fixedFee
+ var fee = fixedFee === undefined ? estimatePaddedFee(txb.buildIncomplete(), this.network) : fixedFee
accum += utxo.value
subTotal = value + fee
@@ -75,7 +75,7 @@ Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
var change = accum - subTotal
if (change > this.network.dustThreshold) {
- tx.addOutput(changeAddress || this.getChangeAddress(), change)
+ txb.addOutput(changeAddress || this.getChangeAddress(), change)
}
break
@@ -84,8 +84,7 @@ Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
assert(accum >= subTotal, 'Not enough funds (incl. fee): ' + accum + ' < ' + subTotal)
- this.signWith(tx, addresses)
- return tx
+ return this.signWith(txb, addresses).build()
}
Wallet.prototype.processPendingTx = function(tx){
@@ -219,16 +218,14 @@ Wallet.prototype.setUnspentOutputs = function(utxo) {
this.outputs = processUnspentOutputs(utxo)
}
-Wallet.prototype.signWith = function(tx, addresses) {
- assert.equal(tx.ins.length, addresses.length, 'Number of addresses must match number of transaction inputs')
-
+Wallet.prototype.signWith = function(txb, addresses) {
addresses.forEach(function(address, i) {
- var key = this.getPrivateKeyForAddress(address)
+ var privKey = this.getPrivateKeyForAddress(address)
- tx.sign(i, key)
+ txb.sign(i, privKey)
}, this)
- return tx
+ return txb
}
function outputToUnspentOutput(output){
diff --git a/test/wallet.js b/test/wallet.js
index c08ae2fe8..87d0cede2 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -7,6 +7,7 @@ var scripts = require('../src/scripts')
var Address = require('../src/address')
var HDNode = require('../src/hdnode')
var Transaction = require('../src/transaction')
+var TransactionBuilder = require('../src/transaction_builder')
var Wallet = require('../src/wallet')
var fixtureTxes = require('./fixtures/mainnet_tx')
@@ -623,17 +624,17 @@ describe('Wallet', function() {
describe('signing', function(){
afterEach(function(){
- Transaction.prototype.sign.restore()
+ TransactionBuilder.prototype.sign.restore()
})
it('signes the inputs with respective keys', function(){
var fee = 30000
- sinon.stub(Transaction.prototype, "sign")
+ sinon.spy(TransactionBuilder.prototype, "sign")
var tx = wallet.createTx(to, value, fee)
- assert(Transaction.prototype.sign.calledWith(0, wallet.getPrivateKeyForAddress(address2)))
- assert(Transaction.prototype.sign.calledWith(1, wallet.getPrivateKeyForAddress(address1)))
+ assert(TransactionBuilder.prototype.sign.calledWith(0, wallet.getPrivateKeyForAddress(address2)))
+ assert(TransactionBuilder.prototype.sign.calledWith(1, wallet.getPrivateKeyForAddress(address1)))
})
})
From d0ac9b405a5eb9bba58dfd8c37ba6207f0ba906d Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 16 Jul 2014 23:05:49 +1000
Subject: [PATCH 052/291] tests: add TxBuilder pubKey test fixture
---
test/fixtures/transaction_builder.json | 22 ++++++++++++++++++++--
test/transaction_builder.js | 22 ++++++++++------------
2 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index 894680508..3fbc794e9 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -2,7 +2,7 @@
"valid": {
"build": [
{
- "description": "pubKeyHash 1:1 transaction",
+ "description": "pubKeyHash->pubKeyHash 1:1 transaction",
"txid": "bd641f4b0aa8bd70189ab45e935c4762f0e1c49f294b4779d79887937b7cf42e",
"inputs": [
{
@@ -19,7 +19,25 @@
]
},
{
- "description": "2-of-2 P2SH multisig Transaction",
+ "description": "pubKey->pubKeyHash 1:1 transaction",
+ "txid": "a900dea133a3c51e9fe55d82bf4a4f50a4c3ac6e380c841f93651a076573320c",
+ "inputs": [
+ {
+ "index": 0,
+ "prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "prevTxScript": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_CHECKSIG",
+ "privKeys": ["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]
+ }
+ ],
+ "outputs": [
+ {
+ "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+ "value": 2500000000
+ }
+ ]
+ },
+ {
+ "description": "2-of-2 P2SH multisig -> pubKeyHash 1:1 Transaction",
"txid": "8c500ce6eef6c78a10de923b68394cf31120151bdc4600e4b12de865defa9d24",
"inputs": [
{
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 36ad20cfb..0d2abdf9f 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -153,14 +153,13 @@ describe('TransactionBuilder', function() {
fixtures.valid.build.forEach(function(f) {
it('builds the correct transaction', function() {
f.inputs.forEach(function(input) {
- var prevTx
- if (input.prevTx.length === 64) {
- prevTx = input.prevTx
- } else {
- prevTx = Transaction.fromHex(input.prevTx)
+ var prevTxScript
+
+ if (input.prevTxScript) {
+ prevTxScript = Script.fromASM(input.prevTxScript)
}
- txb.addInput(prevTx, input.index)
+ txb.addInput(input.prevTx, input.index, prevTxScript)
})
f.outputs.forEach(function(output) {
@@ -192,14 +191,13 @@ describe('TransactionBuilder', function() {
fixtures.invalid.build.forEach(function(f) {
it('throws on ' + f.exception, function() {
f.inputs.forEach(function(input) {
- var prevTx
- if (input.prevTx.length === 64) {
- prevTx = input.prevTx
- } else {
- prevTx = Transaction.fromHex(input.prevTx)
+ var prevTxScript
+
+ if (input.prevTxScript) {
+ prevTxScript = Script.fromASM(input.prevTxScript)
}
- txb.addInput(prevTx, input.index)
+ txb.addInput(input.prevTx, input.index, prevTxScript)
})
f.outputs.forEach(function(output) {
From 31ea956e8e0cc00ad1590565b3475e031df0d0a0 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 16 Jul 2014 23:39:20 +1000
Subject: [PATCH 053/291] TxBuilder: add invalid nulldata case
---
test/fixtures/transaction_builder.json | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index 3fbc794e9..4301cda1b 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -115,6 +115,23 @@
"value": 1000
}
]
+ },
+ {
+ "exception": "nulldata not supported",
+ "inputs": [
+ {
+ "index": 0,
+ "prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "prevTxScript": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474",
+ "privKeys": ["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]
+ }
+ ],
+ "outputs": [
+ {
+ "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+ "value": 1000
+ }
+ ]
}
]
}
From 14211b5f3e8eb1f854b005fd0811250026bfa91a Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 18 Jul 2014 02:50:36 +1000
Subject: [PATCH 054/291] TxBuilder: sign after error checking
---
src/transaction_builder.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index b2e039609..f0863d3ef 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -94,8 +94,6 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
hash = this.tx.hashForSignature(index, prevOutScript, hashType)
}
- var signature = privKey.sign(hash)
-
if (!(index in this.signatures)) {
this.signatures[index] = {
hashType: hashType,
@@ -107,11 +105,13 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
}
var input = this.signatures[index]
- input.pubKeys.push(privKey.pub)
- input.signatures.push(signature)
assert.equal(input.hashType, hashType, 'Inconsistent hashType')
assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
+
+ var signature = privKey.sign(hash)
+ input.pubKeys.push(privKey.pub)
+ input.signatures.push(signature)
}
TransactionBuilder.prototype.build = function() {
From 1e3e003120fbc182e5e4e2fdd45aa8684dc55126 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 25 Jul 2014 15:49:42 +1000
Subject: [PATCH 055/291] TxBuilder: remove unnecessary assert
---
src/transaction_builder.js | 2 --
test/transaction_builder.js | 6 ------
2 files changed, 8 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index f0863d3ef..5a86ffbb4 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -24,8 +24,6 @@ TransactionBuilder.prototype.addInput = function(prevTx, index, prevOutScript) {
Array.prototype.reverse.call(prevOutHash)
} else if (prevTx instanceof Transaction) {
- assert(prevOutScript === undefined, 'Unnecessary Script provided')
-
prevOutHash = prevTx.getHash()
prevOutScript = prevTx.outs[index].script
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 0d2abdf9f..5bc972a3d 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -68,12 +68,6 @@ describe('TransactionBuilder', function() {
assert.equal(txb.addInput(prevTxHash, 1), 1)
})
- it('throws if a Tx and prevOutScript is given', function() {
- assert.throws(function() {
- txb.addInput(prevTx, 0, privScript)
- }, /Unnecessary Script provided/)
- })
-
it('throws if prevOutScript is not supported', function() {
assert.throws(function() {
txb.addInput(prevTxHash, 0, Script.EMPTY)
From 418a56cbdcc7791dec465dbe39d5cbbdf5b59efd Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 25 Jul 2014 17:16:30 +1000
Subject: [PATCH 056/291] index: add TransactionBuilder
---
src/index.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/index.js b/src/index.js
index 0b2897efd..73f3c1ede 100644
--- a/src/index.js
+++ b/src/index.js
@@ -13,6 +13,7 @@ module.exports = {
Script: require('./script'),
scripts: require('./scripts'),
Transaction: require('./transaction'),
+ TransactionBuilder: require('./transaction_builder'),
networks: require('./networks'),
Wallet: require('./wallet')
}
From f3199b6fcef68ea543a8c33200c20c37a3e29c8d Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 25 Jul 2014 16:18:13 +1000
Subject: [PATCH 057/291] tests: integration test to use TxBuilder
---
test/integration/p2sh.js | 28 +++++++++++-----------------
1 file changed, 11 insertions(+), 17 deletions(-)
diff --git a/test/integration/p2sh.js b/test/integration/p2sh.js
index ff7946c65..3d474068e 100644
--- a/test/integration/p2sh.js
+++ b/test/integration/p2sh.js
@@ -1,14 +1,12 @@
var assert = require('assert')
var bitcoin = require('../../')
-var crypto = bitcoin.crypto
var networks = bitcoin.networks
var scripts = bitcoin.scripts
var Address = bitcoin.Address
var ECKey = bitcoin.ECKey
-var Transaction = bitcoin.Transaction
-var Script = bitcoin.Script
+var TransactionBuilder = bitcoin.TransactionBuilder
var helloblock = require('helloblock-js')({
network: 'testnet'
@@ -43,35 +41,31 @@ describe('Bitcoin-js', function() {
var targetAddress = ECKey.makeRandom().pub.getAddress(networks.testnet).toString()
// get latest unspents from the multisigAddress
- helloblock.addresses.getUnspents(multisigAddress, function(err, resp, resource) {
+ helloblock.addresses.getUnspents(multisigAddress, function(err, res, unspents) {
if (err) return done(err)
// use the oldest unspent
- var unspent = resource[resource.length - 1]
+ var unspent = unspents[unspents.length - 1]
var spendAmount = Math.min(unspent.value, outputAmount)
- var tx = new Transaction()
- tx.addInput(unspent.txHash, unspent.index)
- tx.addOutput(targetAddress, spendAmount)
+ var txb = new TransactionBuilder()
+ txb.addInput(unspent.txHash, unspent.index)
+ txb.addOutput(targetAddress, spendAmount)
- var signatures = privKeys.map(function(privKey) {
- return tx.signInput(0, redeemScript, privKey)
+ privKeys.forEach(function(privKey) {
+ txb.sign(0, privKey, redeemScript)
})
- var redeemScriptSig = scripts.multisigInput(signatures)
- var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
- tx.setInputScript(0, scriptSig)
-
// broadcast our transaction
- helloblock.transactions.propagate(tx.toHex(), function(err, resp, resource) {
+ helloblock.transactions.propagate(txb.build().toHex(), function(err, res) {
// no err means that the transaction has been successfully propagated
if (err) return done(err)
// Check that the funds (spendAmount Satoshis) indeed arrived at the intended address
- helloblock.addresses.get(targetAddress, function(err, resp, resource) {
+ helloblock.addresses.get(targetAddress, function(err, res, addrInfo) {
if (err) return done(err)
- assert.equal(resource.balance, spendAmount)
+ assert.equal(addrInfo.balance, spendAmount)
done()
})
})
From 7f62069d82735e16b8d725e8d5c8645e347efe8b Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 25 Jul 2014 18:30:39 +1000
Subject: [PATCH 058/291] TxBuilder: add sequence number passthrough
---
src/transaction_builder.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 5a86ffbb4..c3d3507d3 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -14,7 +14,7 @@ function TransactionBuilder() {
this.tx = new Transaction()
}
-TransactionBuilder.prototype.addInput = function(prevTx, index, prevOutScript) {
+TransactionBuilder.prototype.addInput = function(prevTx, index, prevOutScript, sequence) {
var prevOutHash
if (typeof prevTx === 'string') {
@@ -46,7 +46,7 @@ TransactionBuilder.prototype.addInput = function(prevTx, index, prevOutScript) {
var prevOut = prevOutHash.toString('hex') + ':' + index
assert(!(prevOut in this.prevOutMap), 'Transaction is already an input')
- var vout = this.tx.addInput(prevOutHash, index)
+ var vout = this.tx.addInput(prevOutHash, index, sequence)
this.prevOutMap[prevOut] = true
this.prevOutScripts[vout] = prevOutScript
this.prevOutTypes[vout] = prevOutType
From f9fed3c8155ef622bc29a3382881444b75cc3fef Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 28 Jul 2014 14:28:44 +1000
Subject: [PATCH 059/291] TxBuilder: adds fromTransaction impl. and basic tests
---
src/transaction_builder.js | 124 +++++++++++++++++++++----
test/fixtures/transaction_builder.json | 24 ++++-
test/transaction_builder.js | 32 +++++--
3 files changed, 146 insertions(+), 34 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index c3d3507d3..ad8c704da 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -1,9 +1,10 @@
var assert = require('assert')
var scripts = require('./scripts')
-var ECKey = require('./eckey')
-var Transaction = require('./transaction')
+var ECPubKey = require('./ecpubkey')
+var ECSignature = require('./ecsignature')
var Script = require('./script')
+var Transaction = require('./transaction')
function TransactionBuilder() {
this.prevOutMap = {}
@@ -14,7 +15,7 @@ function TransactionBuilder() {
this.tx = new Transaction()
}
-TransactionBuilder.prototype.addInput = function(prevTx, index, prevOutScript, sequence) {
+TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOutScript) {
var prevOutHash
if (typeof prevTx === 'string') {
@@ -103,7 +104,6 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
}
var input = this.signatures[index]
-
assert.equal(input.hashType, hashType, 'Inconsistent hashType')
assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
@@ -130,29 +130,34 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
var tx = this.tx.clone()
+ // Create script signatures from signature meta-data
this.signatures.forEach(function(input, index) {
var scriptSig
+ var scriptType = input.scriptType
var signatures = input.signatures.map(function(signature) {
return signature.toScriptSignature(input.hashType)
})
- if (input.scriptType === 'pubkeyhash') {
- var signature = signatures[0]
- var publicKey = input.pubKeys[0]
- scriptSig = scripts.pubKeyHashInput(signature, publicKey)
-
- } else if (input.scriptType === 'multisig') {
- var redeemScript = allowIncomplete ? undefined : input.redeemScript
- scriptSig = scripts.multisigInput(signatures, redeemScript)
-
- } else if (input.scriptType === 'pubkey') {
- var signature = signatures[0]
- scriptSig = scripts.pubKeyInput(signature)
-
- } else {
- assert(false, input.scriptType + ' not supported')
-
+ switch (scriptType) {
+ case 'pubkeyhash':
+ var signature = signatures[0]
+ var pubKey = input.pubKeys[0]
+ scriptSig = scripts.pubKeyHashInput(signature, pubKey)
+
+ break
+ case 'multisig':
+ var redeemScript = allowIncomplete ? undefined : input.redeemScript
+ scriptSig = scripts.multisigInput(signatures, redeemScript)
+
+ break
+ case 'pubkey':
+ var signature = signatures[0]
+ scriptSig = scripts.pubKeyInput(signature)
+
+ break
+ default:
+ assert(false, scriptType + ' not supported')
}
if (input.redeemScript) {
@@ -165,4 +170,83 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
return tx
}
+TransactionBuilder.fromTransaction = function(transaction) {
+ var txb = new TransactionBuilder()
+
+ // Extract/add inputs
+ transaction.ins.forEach(function(txin) {
+ txb.addInput(txin.hash, txin.index, txin.sequence)
+ })
+
+ // Extract/add outputs
+ transaction.outs.forEach(function(txout) {
+ txb.addOutput(txout.script, txout.value)
+ })
+
+ // Extract/add signatures
+ transaction.ins.forEach(function(txin) {
+ // Ignore empty scripts
+ if (txin.script.buffer.length === 0) return
+
+ var redeemScript
+ var scriptSig = txin.script
+ var scriptType = scripts.classifyInput(scriptSig)
+
+ // Re-classify if P2SH
+ if (scriptType === 'scripthash') {
+ redeemScript = Script.fromBuffer(scriptSig.chunks.slice(-1)[0])
+ scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1))
+
+ scriptType = scripts.classifyInput(scriptSig)
+ assert.equal(scripts.classifyOutput(redeemScript), scriptType, 'Non-matching scriptSig and scriptPubKey in input')
+ }
+
+ // Extract hashType, pubKeys and signatures
+ var hashType, pubKeys, signatures
+
+ switch (scriptType) {
+ case 'pubkeyhash':
+ var parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
+ var pubKey = ECPubKey.fromBuffer(scriptSig.chunks[1])
+
+ hashType = parsed.hashType
+ pubKeys = [pubKey]
+ signatures = [parsed.signature]
+
+ break
+ case 'multisig':
+ var scriptSigs = scriptSig.chunks.slice(1) // ignore OP_0
+ var parsed = scriptSigs.map(function(scriptSig) {
+ return ECSignature.parseScriptSignature(scriptSig)
+ })
+
+ hashType = parsed[0].hashType
+ pubKeys = []
+ signatures = parsed.map(function(p) { return p.signature })
+
+ break
+ case 'pubkey':
+ var parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
+
+ hashType = parsed.hashType
+ pubKeys = []
+ signatures = [parsed.signature]
+
+ break
+ default:
+ assert(false, scriptType + ' not supported')
+ }
+
+ txb.signatures[txin.index] = {
+ hashType: hashType,
+ pubKeys: pubKeys,
+ redeemScript: redeemScript,
+ scriptType: scriptType,
+ signatures: signatures
+ }
+ })
+
+ return txb
+}
+
module.exports = TransactionBuilder
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index 4301cda1b..c2444eaa0 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -4,11 +4,14 @@
{
"description": "pubKeyHash->pubKeyHash 1:1 transaction",
"txid": "bd641f4b0aa8bd70189ab45e935c4762f0e1c49f294b4779d79887937b7cf42e",
+ "txhex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000006b483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
"inputs": [
{
"index": 0,
"prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "privKeys": ["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]
+ "privKeys": [
+ "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+ ]
}
],
"outputs": [
@@ -21,12 +24,15 @@
{
"description": "pubKey->pubKeyHash 1:1 transaction",
"txid": "a900dea133a3c51e9fe55d82bf4a4f50a4c3ac6e380c841f93651a076573320c",
+ "txhex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000494830450221009833abb3ab49d7004c06bcc79eafd6905ada3eee91f3376ad388548034acd9a702202e84dda6ef2678c82256afcfc459aaa68e179b2bb0e6b2dc3f1410e132c5e6c301ffffffff0100f90295000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
"inputs": [
{
"index": 0,
"prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"prevTxScript": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_CHECKSIG",
- "privKeys": ["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]
+ "privKeys": [
+ "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+ ]
}
],
"outputs": [
@@ -39,11 +45,15 @@
{
"description": "2-of-2 P2SH multisig -> pubKeyHash 1:1 Transaction",
"txid": "8c500ce6eef6c78a10de923b68394cf31120151bdc4600e4b12de865defa9d24",
+ "txhex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1a0100473044022040039a3d0a806d6c2c0ac8a62f2467c979c897c945f3f11905b9c5ea76b4a88002200976f187f852f7d186e8e8aa39332092aa8a504b63a7ae3d0eca09ebea1497fd0147304402205522d1949d13347054bd5ea86cdcad2344f49628a935faaee8f5e744bd3ef87e022063a28ab077817222ccd7d5a70e77ed7274840b9ba8db5dd93a33bdd41813d548014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0110270000000000001976a914faf1d99bf040ea9c7f8cc9f14ac6733ad75ce24688ac00000000",
"inputs": [
{
"index": 0,
"prevTx": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
- "privKeys": ["91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"],
+ "privKeys": [
+ "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+ "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
+ ],
"redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG"
}
],
@@ -101,7 +111,9 @@
{
"index": 0,
"prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "privKeys": ["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]
+ "privKeys": [
+ "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+ ]
},
{
"index": 1,
@@ -123,7 +135,9 @@
"index": 0,
"prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"prevTxScript": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474",
- "privKeys": ["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]
+ "privKeys": [
+ "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+ ]
}
],
"outputs": [
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 5bc972a3d..563e242fb 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -33,33 +33,36 @@ describe('TransactionBuilder', function() {
})
describe('addInput', function() {
- it('accepts a txHash and index', function() {
- var vin = txb.addInput(prevTxHash, 1)
+ it('accepts a txHash, index [and sequence number]', function() {
+ var vin = txb.addInput(prevTxHash, 1, 54)
assert.equal(vin, 0)
var txin = txb.tx.ins[0]
assert.equal(txin.hash, prevTxHash)
assert.equal(txin.index, 1)
+ assert.equal(txin.sequence, 54)
assert.equal(txb.prevOutScripts[0], undefined)
})
- it('accepts a txHash, index and scriptPubKey', function() {
- var vin = txb.addInput(prevTxHash, 1, prevTx.outs[1].script)
+ it('accepts a txHash, index [, sequence number and scriptPubKey]', function() {
+ var vin = txb.addInput(prevTxHash, 1, 54, prevTx.outs[1].script)
assert.equal(vin, 0)
var txin = txb.tx.ins[0]
assert.equal(txin.hash, prevTxHash)
assert.equal(txin.index, 1)
+ assert.equal(txin.sequence, 54)
assert.equal(txb.prevOutScripts[0], prevTx.outs[1].script)
})
- it('accepts a prevTx and index', function() {
- var vin = txb.addInput(prevTx, 1)
+ it('accepts a prevTx, index [and sequence number]', function() {
+ var vin = txb.addInput(prevTx, 1, 54)
assert.equal(vin, 0)
var txin = txb.tx.ins[0]
assert.deepEqual(txin.hash, prevTxHash)
assert.equal(txin.index, 1)
+ assert.equal(txin.sequence, 54)
assert.equal(txb.prevOutScripts[0], prevTx.outs[1].script)
})
@@ -70,7 +73,7 @@ describe('TransactionBuilder', function() {
it('throws if prevOutScript is not supported', function() {
assert.throws(function() {
- txb.addInput(prevTxHash, 0, Script.EMPTY)
+ txb.addInput(prevTxHash, 0, undefined, Script.EMPTY)
}, /PrevOutScript not supported \(nonstandard\)/)
})
@@ -153,7 +156,7 @@ describe('TransactionBuilder', function() {
prevTxScript = Script.fromASM(input.prevTxScript)
}
- txb.addInput(input.prevTx, input.index, prevTxScript)
+ txb.addInput(input.prevTx, input.index, input.sequence, prevTxScript)
})
f.outputs.forEach(function(output) {
@@ -191,7 +194,7 @@ describe('TransactionBuilder', function() {
prevTxScript = Script.fromASM(input.prevTxScript)
}
- txb.addInput(input.prevTx, input.index, prevTxScript)
+ txb.addInput(input.prevTx, input.index, input.sequence, prevTxScript)
})
f.outputs.forEach(function(output) {
@@ -220,4 +223,15 @@ describe('TransactionBuilder', function() {
})
})
})
+
+ describe('fromTransaction', function() {
+ fixtures.valid.build.forEach(function(f) {
+ it('builds the correct TransactionBuilder for ' + f.description, function() {
+ var tx = Transaction.fromHex(f.txhex)
+ var txb = TransactionBuilder.fromTransaction(tx)
+
+ assert.equal(txb.build().toHex(), f.txhex)
+ })
+ })
+ })
})
From 4f88980dfb0a729841f4222d47033005a704724e Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 28 Jul 2014 15:40:07 +1000
Subject: [PATCH 060/291] tests: add P2SH multisig example case
---
src/transaction_builder.js | 6 ++++++
test/transaction_builder.js | 25 +++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index ad8c704da..023591adb 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -146,16 +146,19 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
scriptSig = scripts.pubKeyHashInput(signature, pubKey)
break
+
case 'multisig':
var redeemScript = allowIncomplete ? undefined : input.redeemScript
scriptSig = scripts.multisigInput(signatures, redeemScript)
break
+
case 'pubkey':
var signature = signatures[0]
scriptSig = scripts.pubKeyInput(signature)
break
+
default:
assert(false, scriptType + ' not supported')
}
@@ -214,6 +217,7 @@ TransactionBuilder.fromTransaction = function(transaction) {
signatures = [parsed.signature]
break
+
case 'multisig':
var scriptSigs = scriptSig.chunks.slice(1) // ignore OP_0
var parsed = scriptSigs.map(function(scriptSig) {
@@ -225,6 +229,7 @@ TransactionBuilder.fromTransaction = function(transaction) {
signatures = parsed.map(function(p) { return p.signature })
break
+
case 'pubkey':
var parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
@@ -233,6 +238,7 @@ TransactionBuilder.fromTransaction = function(transaction) {
signatures = [parsed.signature]
break
+
default:
assert(false, scriptType + ' not supported')
}
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 563e242fb..d6ab2f0a0 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -233,5 +233,30 @@ describe('TransactionBuilder', function() {
assert.equal(txb.build().toHex(), f.txhex)
})
})
+
+ it('works for the P2SH multisig case', function() {
+ var privKeys = [
+ "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+ "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
+ ].map(function(wif) { return ECKey.fromWIF(wif) })
+ var redeemScript = Script.fromASM("OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG")
+
+ txb.addInput("4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", 0)
+ txb.addOutput("1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH", 10000)
+ txb.sign(0, privKeys[0], redeemScript)
+
+ var tx = txb.buildIncomplete()
+
+ // in another galaxy...
+ // ... far, far away
+ var txb2 = TransactionBuilder.fromTransaction(tx)
+
+ // [you should] verify that Transaction is what you want...
+ // ... then sign it
+ txb2.sign(0, privKeys[1], redeemScript)
+ var tx2 = txb2.build()
+
+ assert.equal(tx2.toHex(), '0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c01004830450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a8014830450221009418caa5bc18da87b188a180125c0cf06dce6092f75b2d3c01a29493466800fd02206ead65e7ca6e0f17eefe6f78457c084eab59af7c9882be1437de2e7116358eb9014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0110270000000000001976a914751e76e8199196d454941c45d1b3a323f1433bd688ac00000000')
+ })
})
})
From 22f8c8aa4aa21ea5f41ed86d8b0efe075cd1e791 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 18 Aug 2014 08:59:26 +1000
Subject: [PATCH 061/291] TxBuilder: re-order functions to project standard
---
src/transaction_builder.js | 230 +++++++++++++++++++------------------
1 file changed, 116 insertions(+), 114 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 023591adb..05c0591ef 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -15,6 +15,90 @@ function TransactionBuilder() {
this.tx = new Transaction()
}
+// Static constructors
+TransactionBuilder.fromTransaction = function(transaction) {
+ var txb = new TransactionBuilder()
+
+ // Extract/add inputs
+ transaction.ins.forEach(function(txin) {
+ txb.addInput(txin.hash, txin.index, txin.sequence)
+ })
+
+ // Extract/add outputs
+ transaction.outs.forEach(function(txout) {
+ txb.addOutput(txout.script, txout.value)
+ })
+
+ // Extract/add signatures
+ transaction.ins.forEach(function(txin) {
+ // Ignore empty scripts
+ if (txin.script.buffer.length === 0) return
+
+ var redeemScript
+ var scriptSig = txin.script
+ var scriptType = scripts.classifyInput(scriptSig)
+
+ // Re-classify if P2SH
+ if (scriptType === 'scripthash') {
+ redeemScript = Script.fromBuffer(scriptSig.chunks.slice(-1)[0])
+ scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1))
+
+ scriptType = scripts.classifyInput(scriptSig)
+ assert.equal(scripts.classifyOutput(redeemScript), scriptType, 'Non-matching scriptSig and scriptPubKey in input')
+ }
+
+ // Extract hashType, pubKeys and signatures
+ var hashType, pubKeys, signatures
+
+ switch (scriptType) {
+ case 'pubkeyhash':
+ var parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
+ var pubKey = ECPubKey.fromBuffer(scriptSig.chunks[1])
+
+ hashType = parsed.hashType
+ pubKeys = [pubKey]
+ signatures = [parsed.signature]
+
+ break
+
+ case 'multisig':
+ var scriptSigs = scriptSig.chunks.slice(1) // ignore OP_0
+ var parsed = scriptSigs.map(function(scriptSig) {
+ return ECSignature.parseScriptSignature(scriptSig)
+ })
+
+ hashType = parsed[0].hashType
+ pubKeys = []
+ signatures = parsed.map(function(p) { return p.signature })
+
+ break
+
+ case 'pubkey':
+ var parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
+
+ hashType = parsed.hashType
+ pubKeys = []
+ signatures = [parsed.signature]
+
+ break
+
+ default:
+ assert(false, scriptType + ' not supported')
+ }
+
+ txb.signatures[txin.index] = {
+ hashType: hashType,
+ pubKeys: pubKeys,
+ redeemScript: redeemScript,
+ scriptType: scriptType,
+ signatures: signatures
+ }
+ })
+
+ return txb
+}
+
+// Operations
TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOutScript) {
var prevOutHash
@@ -63,55 +147,6 @@ TransactionBuilder.prototype.addOutput = function(scriptPubKey, value) {
return this.tx.addOutput(scriptPubKey, value)
}
-TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashType) {
- assert(this.tx.ins.length >= index, 'No input at index: ' + index)
- hashType = hashType || Transaction.SIGHASH_ALL
-
- var prevOutScript = this.prevOutScripts[index]
- var prevOutType = this.prevOutTypes[index]
-
- var scriptType, hash
- if (redeemScript) {
- prevOutScript = prevOutScript || scripts.scriptHashOutput(redeemScript.getHash())
- prevOutType = prevOutType || 'scripthash'
-
- assert.equal(prevOutType, 'scripthash', 'PrevOutScript must be P2SH')
-
- scriptType = scripts.classifyOutput(redeemScript)
-
- assert.notEqual(scriptType, 'scripthash', 'RedeemScript can\'t be P2SH')
- assert.notEqual(scriptType, 'nonstandard', 'RedeemScript not supported (nonstandard)')
-
- hash = this.tx.hashForSignature(index, redeemScript, hashType)
-
- } else {
- prevOutScript = prevOutScript || privKey.pub.getAddress().toOutputScript()
- scriptType = prevOutType || 'pubkeyhash'
-
- assert.notEqual(scriptType, 'scripthash', 'PrevOutScript requires redeemScript')
-
- hash = this.tx.hashForSignature(index, prevOutScript, hashType)
- }
-
- if (!(index in this.signatures)) {
- this.signatures[index] = {
- hashType: hashType,
- pubKeys: [],
- redeemScript: redeemScript,
- scriptType: scriptType,
- signatures: []
- }
- }
-
- var input = this.signatures[index]
- assert.equal(input.hashType, hashType, 'Inconsistent hashType')
- assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
-
- var signature = privKey.sign(hash)
- input.pubKeys.push(privKey.pub)
- input.signatures.push(signature)
-}
-
TransactionBuilder.prototype.build = function() {
return this.__build(false)
}
@@ -173,86 +208,53 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
return tx
}
-TransactionBuilder.fromTransaction = function(transaction) {
- var txb = new TransactionBuilder()
-
- // Extract/add inputs
- transaction.ins.forEach(function(txin) {
- txb.addInput(txin.hash, txin.index, txin.sequence)
- })
-
- // Extract/add outputs
- transaction.outs.forEach(function(txout) {
- txb.addOutput(txout.script, txout.value)
- })
-
- // Extract/add signatures
- transaction.ins.forEach(function(txin) {
- // Ignore empty scripts
- if (txin.script.buffer.length === 0) return
-
- var redeemScript
- var scriptSig = txin.script
- var scriptType = scripts.classifyInput(scriptSig)
-
- // Re-classify if P2SH
- if (scriptType === 'scripthash') {
- redeemScript = Script.fromBuffer(scriptSig.chunks.slice(-1)[0])
- scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1))
-
- scriptType = scripts.classifyInput(scriptSig)
- assert.equal(scripts.classifyOutput(redeemScript), scriptType, 'Non-matching scriptSig and scriptPubKey in input')
- }
-
- // Extract hashType, pubKeys and signatures
- var hashType, pubKeys, signatures
-
- switch (scriptType) {
- case 'pubkeyhash':
- var parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
- var pubKey = ECPubKey.fromBuffer(scriptSig.chunks[1])
+TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashType) {
+ assert(this.tx.ins.length >= index, 'No input at index: ' + index)
+ hashType = hashType || Transaction.SIGHASH_ALL
- hashType = parsed.hashType
- pubKeys = [pubKey]
- signatures = [parsed.signature]
+ var prevOutScript = this.prevOutScripts[index]
+ var prevOutType = this.prevOutTypes[index]
- break
+ var scriptType, hash
+ if (redeemScript) {
+ prevOutScript = prevOutScript || scripts.scriptHashOutput(redeemScript.getHash())
+ prevOutType = prevOutType || 'scripthash'
- case 'multisig':
- var scriptSigs = scriptSig.chunks.slice(1) // ignore OP_0
- var parsed = scriptSigs.map(function(scriptSig) {
- return ECSignature.parseScriptSignature(scriptSig)
- })
+ assert.equal(prevOutType, 'scripthash', 'PrevOutScript must be P2SH')
- hashType = parsed[0].hashType
- pubKeys = []
- signatures = parsed.map(function(p) { return p.signature })
+ scriptType = scripts.classifyOutput(redeemScript)
- break
+ assert.notEqual(scriptType, 'scripthash', 'RedeemScript can\'t be P2SH')
+ assert.notEqual(scriptType, 'nonstandard', 'RedeemScript not supported (nonstandard)')
- case 'pubkey':
- var parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
+ hash = this.tx.hashForSignature(index, redeemScript, hashType)
- hashType = parsed.hashType
- pubKeys = []
- signatures = [parsed.signature]
+ } else {
+ prevOutScript = prevOutScript || privKey.pub.getAddress().toOutputScript()
+ scriptType = prevOutType || 'pubkeyhash'
- break
+ assert.notEqual(scriptType, 'scripthash', 'PrevOutScript requires redeemScript')
- default:
- assert(false, scriptType + ' not supported')
- }
+ hash = this.tx.hashForSignature(index, prevOutScript, hashType)
+ }
- txb.signatures[txin.index] = {
+ if (!(index in this.signatures)) {
+ this.signatures[index] = {
hashType: hashType,
- pubKeys: pubKeys,
+ pubKeys: [],
redeemScript: redeemScript,
scriptType: scriptType,
- signatures: signatures
+ signatures: []
}
- })
+ }
- return txb
+ var input = this.signatures[index]
+ assert.equal(input.hashType, hashType, 'Inconsistent hashType')
+ assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
+
+ var signature = privKey.sign(hash)
+ input.pubKeys.push(privKey.pub)
+ input.signatures.push(signature)
}
module.exports = TransactionBuilder
From 0782e8e8372debdb349d01b450b14b76d4fa1948 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 18 Aug 2014 09:31:24 +1000
Subject: [PATCH 062/291] tests: fixes test description typos
---
test/wallet.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/wallet.js b/test/wallet.js
index c08ae2fe8..fe47a9d34 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -241,7 +241,7 @@ describe('Wallet', function() {
wallet = new Wallet(seed, networks.bitcoin, [utxo])
})
- it('parses wallet outputs to the expect format', function(){
+ it('parses wallet outputs to the expected format', function(){
assert.deepEqual(wallet.getUnspentOutputs(), [utxo])
})
@@ -626,7 +626,7 @@ describe('Wallet', function() {
Transaction.prototype.sign.restore()
})
- it('signes the inputs with respective keys', function(){
+ it('signs the inputs with respective keys', function(){
var fee = 30000
sinon.stub(Transaction.prototype, "sign")
From 7ef963c7f992e610ac95cd07331900a2cf222566 Mon Sep 17 00:00:00 2001
From: hobofife
Date: Tue, 19 Aug 2014 00:29:42 -0500
Subject: [PATCH 063/291] Change Browserify results to 'bitcoin', not 'Bitcoin'
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 78523bfba..e0c459cd1 100644
--- a/package.json
+++ b/package.json
@@ -60,7 +60,7 @@
"files": "test/*.js"
},
"scripts": {
- "compile": "browserify ./src/index.js -s Bitcoin | uglifyjs > bitcoinjs-min.js",
+ "compile": "browserify ./src/index.js -s bitcoin | uglifyjs > bitcoinjs-min.js",
"coverage": "istanbul cover _mocha -- test/*.js",
"coveralls": "npm run-script coverage && coveralls < coverage/lcov.info",
"integration": "mocha --reporter list test/integration/*.js",
From 4b52c42c910029f2f247731a0949bb74f30033aa Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 20 Aug 2014 09:14:04 +1000
Subject: [PATCH 064/291] Message: allow base64 strings as input
---
src/message.js | 9 +++++++--
test/message.js | 14 +++++---------
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/src/message.js b/src/message.js
index 943d82ba9..4bb96a361 100644
--- a/src/message.js
+++ b/src/message.js
@@ -35,14 +35,19 @@ function sign(privKey, message, network) {
}
// TODO: network could be implied from address
-function verify(address, signatureBuffer, message, network) {
+function verify(address, signature, message, network) {
+ if (!Buffer.isBuffer(signature)) {
+ signature = new Buffer(signature, 'base64')
+ }
+
if (address instanceof Address) {
address = address.toString()
}
+
network = network || networks.bitcoin
var hash = magicHash(message, network)
- var parsed = ECSignature.parseCompact(signatureBuffer)
+ var parsed = ECSignature.parseCompact(signature)
var e = BigInteger.fromBuffer(hash)
var Q = ecdsa.recoverPubKey(ecparams, e, parsed.signature, parsed.i)
diff --git a/test/message.js b/test/message.js
index d69a41f6d..a9530b230 100644
--- a/test/message.js
+++ b/test/message.js
@@ -26,29 +26,25 @@ describe('Message', function() {
var network = networks[f.network]
var address = Address.fromBase58Check(f.address)
- var signature = new Buffer(f.signature, 'base64')
- assert.ok(Message.verify(address, signature, f.message, network))
+ assert.ok(Message.verify(address, f.signature, f.message, network))
})
fixtures.valid.verify.forEach(function(f) {
it('verifies a valid signature for \"' + f.message + '\" (' + f.network + ')', function() {
var network = networks[f.network]
- var signature = new Buffer(f.signature, 'base64')
- assert.ok(Message.verify(f.address, signature, f.message, network))
+ var signature = f.signature
+ assert.ok(Message.verify(f.address, f.signature, f.message, network))
if (f.compressed) {
- var compressedSignature = new Buffer(f.compressed.signature, 'base64')
-
- assert.ok(Message.verify(f.compressed.address, compressedSignature, f.message, network))
+ assert.ok(Message.verify(f.compressed.address, f.compressed.signature, f.message, network))
}
})
})
fixtures.invalid.verify.forEach(function(f) {
it(f.description, function() {
- var signature = new Buffer(f.signature, 'base64')
- assert.ok(!Message.verify(f.address, signature, f.message))
+ assert.ok(!Message.verify(f.address, f.signature, f.message))
})
})
})
From 82d8e207932affd97100acd3d0ae2dd9d11bea6e Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 20 Aug 2014 09:17:55 +1000
Subject: [PATCH 065/291] tests: avoid unnecessary .ok
---
test/ecpubkey.js | 4 ++--
test/message.js | 8 ++++----
test/wallet.js | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/test/ecpubkey.js b/test/ecpubkey.js
index 62609ef96..35302f51d 100644
--- a/test/ecpubkey.js
+++ b/test/ecpubkey.js
@@ -91,13 +91,13 @@ describe('ECPubKey', function() {
it('verifies a valid signature', function() {
var hash = crypto.sha256(fixtures.message)
- assert.ok(pubKey.verify(hash, signature))
+ assert(pubKey.verify(hash, signature))
})
it('doesn\'t verify the wrong signature', function() {
var hash = crypto.sha256('mushrooms')
- assert.ok(!pubKey.verify(hash, signature))
+ assert(!pubKey.verify(hash, signature))
})
})
})
diff --git a/test/message.js b/test/message.js
index a9530b230..0161e1bcb 100644
--- a/test/message.js
+++ b/test/message.js
@@ -26,7 +26,7 @@ describe('Message', function() {
var network = networks[f.network]
var address = Address.fromBase58Check(f.address)
- assert.ok(Message.verify(address, f.signature, f.message, network))
+ assert(Message.verify(address, f.signature, f.message, network))
})
fixtures.valid.verify.forEach(function(f) {
@@ -34,17 +34,17 @@ describe('Message', function() {
var network = networks[f.network]
var signature = f.signature
- assert.ok(Message.verify(f.address, f.signature, f.message, network))
+ assert(Message.verify(f.address, f.signature, f.message, network))
if (f.compressed) {
- assert.ok(Message.verify(f.compressed.address, f.compressed.signature, f.message, network))
+ assert(Message.verify(f.compressed.address, f.compressed.signature, f.message, network))
}
})
})
fixtures.invalid.verify.forEach(function(f) {
it(f.description, function() {
- assert.ok(!Message.verify(f.address, f.signature, f.message))
+ assert(!Message.verify(f.address, f.signature, f.message))
})
})
})
diff --git a/test/wallet.js b/test/wallet.js
index 8f18241be..9c002feff 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -63,7 +63,7 @@ describe('Wallet', function() {
describe('when seed is not specified', function(){
it('generates a seed', function(){
var wallet = new Wallet()
- assert.ok(wallet.getMasterKey())
+ assert(wallet.getMasterKey())
})
})
From b66e53d1e7eeaef6ef7a7805174d54c33fbf358c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 20 Aug 2014 10:37:24 +1000
Subject: [PATCH 066/291] Transaction: add comment to explain -1 on add*
---
src/transaction.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index d8a0fc47b..a9a08997f 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -53,6 +53,7 @@ Transaction.prototype.addInput = function(tx, index, sequence) {
assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
+ // Add the input and return the input's index
return (this.ins.push({
hash: hash,
index: index,
@@ -78,14 +79,13 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) {
// Attempt to get a valid script if it's an Address object
if (scriptPubKey instanceof Address) {
- var address = scriptPubKey
-
- scriptPubKey = address.toOutputScript()
+ scriptPubKey = scriptPubKey.toOutputScript()
}
assert(scriptPubKey instanceof Script, 'Expected Address or Script, got ' + scriptPubKey)
assert.equal(typeof value, 'number', 'Expected number value, got ' + value)
+ // Add the output and return the output's index
return (this.outs.push({
script: scriptPubKey,
value: value
From 0f9674e65ff1980ffeb4a46b6b38152d925e425c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 18 Aug 2014 10:47:39 +1000
Subject: [PATCH 067/291] tests: code formatting
---
test/wallet.js | 164 ++++++++++++++++++++++++-------------------------
1 file changed, 82 insertions(+), 82 deletions(-)
diff --git a/test/wallet.js b/test/wallet.js
index 9c002feff..8e30d3323 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -28,13 +28,13 @@ function fakeTxId(i) {
describe('Wallet', function() {
var seed
- beforeEach(function(){
+ beforeEach(function() {
seed = crypto.sha256("don't use a string seed like this in real life")
})
describe('constructor', function() {
var wallet
- beforeEach(function(){
+ beforeEach(function() {
wallet = new Wallet(seed)
})
@@ -60,8 +60,8 @@ describe('Wallet', function() {
assert.equal(account.depth, 2)
})
- describe('when seed is not specified', function(){
- it('generates a seed', function(){
+ describe('when seed is not specified', function() {
+ it('generates a seed', function() {
var wallet = new Wallet()
assert(wallet.getMasterKey())
})
@@ -78,8 +78,8 @@ describe('Wallet', function() {
})
})
- describe('newMasterKey', function(){
- it('resets accounts', function(){
+ describe('newMasterKey', function() {
+ it('resets accounts', function() {
var wallet = new Wallet()
var oldAccountZero = wallet.getAccountZero()
var oldExternalAccount = wallet.getExternalAccount()
@@ -91,7 +91,7 @@ describe('Wallet', function() {
assertNotEqual(wallet.getInternalAccount(), oldInternalAccount)
})
- it('resets addresses', function(){
+ it('resets addresses', function() {
var wallet = new Wallet()
wallet.generateAddress()
wallet.generateChangeAddress()
@@ -106,8 +106,8 @@ describe('Wallet', function() {
})
})
- describe('generateAddress', function(){
- it('generate receiving addresses', function(){
+ describe('generateAddress', function() {
+ it('generate receiving addresses', function() {
var wallet = new Wallet(seed, networks.testnet)
var expectedAddresses = [
"n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa",
@@ -120,13 +120,13 @@ describe('Wallet', function() {
})
})
- describe('generateChangeAddress', function(){
+ describe('generateChangeAddress', function() {
var wallet
- beforeEach(function(){
+ beforeEach(function() {
wallet = new Wallet(seed)
})
- it('generates change addresses', function(){
+ it('generates change addresses', function() {
var wallet = new Wallet(seed, networks.testnet)
var expectedAddresses = ["mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn"]
@@ -135,13 +135,13 @@ describe('Wallet', function() {
})
})
- describe('getPrivateKey', function(){
+ describe('getPrivateKey', function() {
var wallet
- beforeEach(function(){
+ beforeEach(function() {
wallet = new Wallet(seed)
})
- it('returns the private key at the given index of external account', function(){
+ it('returns the private key at the given index of external account', function() {
var wallet = new Wallet(seed, networks.testnet)
assertEqual(wallet.getPrivateKey(0), wallet.getExternalAccount().derive(0).privKey)
@@ -149,13 +149,13 @@ describe('Wallet', function() {
})
})
- describe('getInternalPrivateKey', function(){
+ describe('getInternalPrivateKey', function() {
var wallet
- beforeEach(function(){
+ beforeEach(function() {
wallet = new Wallet(seed)
})
- it('returns the private key at the given index of internal account', function(){
+ it('returns the private key at the given index of internal account', function() {
var wallet = new Wallet(seed, networks.testnet)
assertEqual(wallet.getInternalPrivateKey(0), wallet.getInternalAccount().derive(0).privKey)
@@ -163,13 +163,13 @@ describe('Wallet', function() {
})
})
- describe('getPrivateKeyForAddress', function(){
+ describe('getPrivateKeyForAddress', function() {
var wallet
- beforeEach(function(){
+ beforeEach(function() {
wallet = new Wallet(seed)
})
- it('returns the private key for the given address', function(){
+ it('returns the private key for the given address', function() {
var wallet = new Wallet(seed, networks.testnet)
wallet.generateChangeAddress()
wallet.generateAddress()
@@ -185,7 +185,7 @@ describe('Wallet', function() {
)
})
- it('raises an error when address is not found', function(){
+ it('raises an error when address is not found', function() {
var wallet = new Wallet(seed, networks.testnet)
assert.throws(function() {
@@ -194,11 +194,11 @@ describe('Wallet', function() {
})
})
- describe('Unspent Outputs', function(){
+ describe('Unspent Outputs', function() {
var utxo, expectedOutputKey
var wallet
- beforeEach(function(){
+ beforeEach(function() {
utxo = {
"address" : "1AZpKpcfCzKDUeTFBQUL4MokQai3m3HMXv",
"hash": fakeTxId(6),
@@ -210,12 +210,12 @@ describe('Wallet', function() {
expectedOutputKey = utxo.hash + ":" + utxo.index
})
- describe('on construction', function(){
- beforeEach(function(){
+ describe('on construction', function() {
+ beforeEach(function() {
wallet = new Wallet(seed, networks.bitcoin, [utxo])
})
- it('matches the expected behaviour', function(){
+ it('matches the expected behaviour', function() {
var output = wallet.outputs[expectedOutputKey]
assert(output)
@@ -224,29 +224,29 @@ describe('Wallet', function() {
})
})
- describe('getBalance', function(){
- beforeEach(function(){
+ describe('getBalance', function() {
+ beforeEach(function() {
var utxo1 = cloneObject(utxo)
utxo1.hash = fakeTxId(5)
wallet = new Wallet(seed, networks.bitcoin, [utxo, utxo1])
})
- it('sums over utxo values', function(){
+ it('sums over utxo values', function() {
assert.equal(wallet.getBalance(), 40000)
})
})
- describe('getUnspentOutputs', function(){
- beforeEach(function(){
+ describe('getUnspentOutputs', function() {
+ beforeEach(function() {
wallet = new Wallet(seed, networks.bitcoin, [utxo])
})
- it('parses wallet outputs to the expected format', function(){
+ it('parses wallet outputs to the expected format', function() {
assert.deepEqual(wallet.getUnspentOutputs(), [utxo])
})
- it("ignores pending spending outputs (outputs with 'to' property)", function(){
+ it("ignores pending spending outputs (outputs with 'to' property)", function() {
var output = wallet.outputs[expectedOutputKey]
output.to = fakeTxId(0) + ':' + 0
output.pending = true
@@ -256,11 +256,11 @@ describe('Wallet', function() {
})
// FIXME: remove in 2.x.y
- describe('setUnspentOutputs', function(){
+ describe('setUnspentOutputs', function() {
var utxo
var expectedOutputKey
- beforeEach(function(){
+ beforeEach(function() {
utxo = {
hash: fakeTxId(0),
index: 0,
@@ -273,7 +273,7 @@ describe('Wallet', function() {
wallet = new Wallet(seed, networks.bitcoin)
})
- it('matches the expected behaviour', function(){
+ it('matches the expected behaviour', function() {
wallet.setUnspentOutputs([utxo])
var output = wallet.outputs[expectedOutputKey]
@@ -282,9 +282,9 @@ describe('Wallet', function() {
assert.equal(output.address, utxo.address)
})
- describe('required fields', function(){
+ describe('required fields', function() {
['index', 'address', 'hash', 'value'].forEach(function(field){
- it("throws an error when " + field + " is missing", function(){
+ it("throws an error when " + field + " is missing", function() {
delete utxo[field]
assert.throws(function() {
@@ -295,16 +295,16 @@ describe('Wallet', function() {
})
})
- describe('Process transaction', function(){
+ describe('Process transaction', function() {
var wallet
- beforeEach(function(){
+ beforeEach(function() {
wallet = new Wallet(seed)
})
var addresses
var tx
- beforeEach(function(){
+ beforeEach(function() {
addresses = [
'115qa7iPZqn6as57hxLL8E9VUnhmGQxKWi',
'1Bu3bhwRmevHLAy1JrRB6AfcxfgDG2vXRd',
@@ -314,24 +314,24 @@ describe('Wallet', function() {
tx = Transaction.fromHex(fixtureTx1Hex)
})
- describe("processPendingTx", function(){
- it("incoming: sets the pending flag on output", function(){
+ describe("processPendingTx", function() {
+ it("incoming: sets the pending flag on output", function() {
wallet.addresses = [addresses[0]]
wallet.processPendingTx(tx)
verifyOutputAdded(0, true)
})
- describe("when tx ins outpoint contains a known txhash:i", function(){
+ describe("when tx ins outpoint contains a known txhash:i", function() {
var spendTx
- beforeEach(function(){
+ beforeEach(function() {
wallet.addresses = [addresses[0]]
wallet.processConfirmedTx(tx)
spendTx = Transaction.fromHex(fixtureTx2Hex)
})
- it("outgoing: sets the pending flag and 'to' on output", function(){
+ it("outgoing: sets the pending flag and 'to' on output", function() {
var txIn = spendTx.ins[0]
var txInId = new Buffer(txIn.hash)
Array.prototype.reverse.call(txInId)
@@ -347,7 +347,7 @@ describe('Wallet', function() {
})
})
- describe('processConfirmedTx', function(){
+ describe('processConfirmedTx', function() {
it('does not throw on scripts with no corresponding Address', function() {
var pubKey = wallet.getPrivateKey(0).pub
var script = scripts.pubKeyOutput(pubKey)
@@ -359,8 +359,8 @@ describe('Wallet', function() {
wallet.processConfirmedTx(tx2)
})
- describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.outputs", function(){
- it("works for receive address", function(){
+ describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.outputs", function() {
+ it("works for receive address", function() {
var totalOuts = outputCount()
wallet.addresses = [addresses[0]]
@@ -370,7 +370,7 @@ describe('Wallet', function() {
verifyOutputAdded(0, false)
})
- it("works for change address", function(){
+ it("works for change address", function() {
var totalOuts = outputCount()
wallet.changeAddresses = [addresses[1]]
@@ -380,26 +380,26 @@ describe('Wallet', function() {
verifyOutputAdded(1, false)
})
- function outputCount(){
+ function outputCount() {
return Object.keys(wallet.outputs).length
}
})
- describe("when tx ins outpoint contains a known txhash:i", function(){
+ describe("when tx ins outpoint contains a known txhash:i", function() {
var spendTx
- beforeEach(function(){
+ beforeEach(function() {
wallet.addresses = [addresses[0]] // the address fixtureTx2 used as input
wallet.processConfirmedTx(tx)
spendTx = Transaction.fromHex(fixtureTx2Hex)
})
- it("does not add to wallet.outputs", function(){
+ it("does not add to wallet.outputs", function() {
wallet.processConfirmedTx(spendTx)
assert.deepEqual(wallet.outputs, {})
})
- it("deletes corresponding 'output'", function(){
+ it("deletes corresponding 'output'", function() {
var txIn = spendTx.ins[0]
var txInId = new Buffer(txIn.hash)
Array.prototype.reverse.call(txInId)
@@ -413,7 +413,7 @@ describe('Wallet', function() {
})
})
- it("does nothing when none of the involved addresses belong to the wallet", function(){
+ it("does nothing when none of the involved addresses belong to the wallet", function() {
wallet.processConfirmedTx(tx)
assert.deepEqual(wallet.outputs, {})
})
@@ -432,12 +432,12 @@ describe('Wallet', function() {
}
})
- describe('createTx', function(){
+ describe('createTx', function() {
var wallet
var address1, address2
var to, value
- beforeEach(function(){
+ beforeEach(function() {
to = 'mt7MyTVVEWnbwpF5hBn6fgnJcv95Syk2ue'
value = 500000
@@ -471,15 +471,15 @@ describe('Wallet', function() {
wallet.generateAddress()
})
- describe('transaction fee', function(){
- it('allows fee to be specified', function(){
+ describe('transaction fee', function() {
+ it('allows fee to be specified', function() {
var fee = 30000
var tx = wallet.createTx(to, value, fee)
assert.equal(getFee(wallet, tx), fee)
})
- it('allows fee to be set to zero', function(){
+ it('allows fee to be set to zero', function() {
value = 510000
var fee = 0
var tx = wallet.createTx(to, value, fee)
@@ -487,7 +487,7 @@ describe('Wallet', function() {
assert.equal(getFee(wallet, tx), fee)
})
- it('does not overestimate fees when network has dustSoftThreshold', function(){
+ it('does not overestimate fees when network has dustSoftThreshold', function() {
var utxo = {
hash: fakeTxId(0),
index: 0,
@@ -516,8 +516,8 @@ describe('Wallet', function() {
}
})
- describe('choosing utxo', function(){
- it('takes fees into account', function(){
+ describe('choosing utxo', function() {
+ it('takes fees into account', function() {
var tx = wallet.createTx(to, value)
assert.equal(tx.ins.length, 1)
@@ -525,7 +525,7 @@ describe('Wallet', function() {
assert.equal(tx.ins[0].index, 0)
})
- it('uses confirmed outputs', function(){
+ it('uses confirmed outputs', function() {
var tx2 = new Transaction()
tx2.addInput(fakeTxId(4), 0)
tx2.addOutput(address2, 530000)
@@ -538,7 +538,7 @@ describe('Wallet', function() {
assert.equal(tx.ins[0].index, 0)
})
- it('ignores pending outputs', function(){
+ it('ignores pending outputs', function() {
var tx2 = new Transaction()
tx2.addInput(fakeTxId(4), 0)
tx2.addOutput(address2, 530000)
@@ -552,8 +552,8 @@ describe('Wallet', function() {
})
})
- describe('changeAddress', function(){
- it('should allow custom changeAddress', function(){
+ describe('changeAddress', function() {
+ it('should allow custom changeAddress', function() {
var changeAddress = 'mfrFjnKZUvTcvdAK2fUX5D8v1Epu5H8JCk'
var fromValue = 510000
var toValue = fromValue / 2
@@ -573,8 +573,8 @@ describe('Wallet', function() {
})
})
- describe('transaction outputs', function(){
- it('includes the specified address and amount', function(){
+ describe('transaction outputs', function() {
+ it('includes the specified address and amount', function() {
var tx = wallet.createTx(to, value)
assert.equal(tx.outs.length, 1)
@@ -585,8 +585,8 @@ describe('Wallet', function() {
assert.equal(out.value, value)
})
- describe('change', function(){
- it('uses the last change address if there is any', function(){
+ describe('change', function() {
+ it('uses the last change address if there is any', function() {
var fee = 0
wallet.generateChangeAddress()
wallet.generateChangeAddress()
@@ -600,7 +600,7 @@ describe('Wallet', function() {
assert.equal(out.value, 10000)
})
- it('generates a change address if there is not any', function(){
+ it('generates a change address if there is not any', function() {
var fee = 0
assert.equal(wallet.changeAddresses.length, 0)
@@ -614,7 +614,7 @@ describe('Wallet', function() {
assert.equal(out.value, 10000)
})
- it('skips change if it is not above dust threshold', function(){
+ it('skips change if it is not above dust threshold', function() {
var fee = 14570
var tx = wallet.createTx(to, value)
assert.equal(tx.outs.length, 1)
@@ -622,12 +622,12 @@ describe('Wallet', function() {
})
})
- describe('signing', function(){
- afterEach(function(){
+ describe('signing', function() {
+ afterEach(function() {
TransactionBuilder.prototype.sign.restore()
})
- it('signs the inputs with respective keys', function(){
+ it('signs the inputs with respective keys', function() {
var fee = 30000
sinon.spy(TransactionBuilder.prototype, "sign")
@@ -638,8 +638,8 @@ describe('Wallet', function() {
})
})
- describe('when value is below dust threshold', function(){
- it('throws an error', function(){
+ describe('when value is below dust threshold', function() {
+ it('throws an error', function() {
var value = 546
assert.throws(function() {
@@ -648,8 +648,8 @@ describe('Wallet', function() {
})
})
- describe('when there is not enough money', function(){
- it('throws an error', function(){
+ describe('when there is not enough money', function() {
+ it('throws an error', function() {
var value = 1400001
assert.throws(function() {
From 735feab7babebb6f14e0f3c4484bf774832dcb78 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 17 Aug 2014 15:16:45 +1000
Subject: [PATCH 068/291] Wallet: remove txId:index storage for spent outputs
---
src/wallet.js | 13 +++++++++----
test/wallet.js | 13 +++++++------
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index af28be07d..8177a354a 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -96,7 +96,7 @@ Wallet.prototype.processConfirmedTx = function(tx){
}
Wallet.prototype.__processTx = function(tx, isPending) {
- var txid = tx.getId()
+ var txId = tx.getId()
tx.outs.forEach(function(txOut, i) {
var address
@@ -109,7 +109,7 @@ Wallet.prototype.__processTx = function(tx, isPending) {
var myAddresses = this.addresses.concat(this.changeAddresses)
if (myAddresses.indexOf(address) > -1) {
- var output = txid + ':' + i
+ var output = txId + ':' + i
this.outputs[output] = {
from: output,
@@ -131,8 +131,9 @@ Wallet.prototype.__processTx = function(tx, isPending) {
if (!(output in this.outputs)) return
if (isPending) {
- this.outputs[output].to = txid + ':' + i
this.outputs[output].pending = true
+ this.outputs[output].spent = true
+
} else {
delete this.outputs[output]
}
@@ -206,7 +207,11 @@ Wallet.prototype.getUnspentOutputs = function() {
for(var key in this.outputs){
var output = this.outputs[key]
- if(!output.to) utxo.push(outputToUnspentOutput(output))
+
+ // Don't include pending spent outputs
+ if (!output.spent) {
+ utxo.push(outputToUnspentOutput(output))
+ }
}
return utxo
diff --git a/test/wallet.js b/test/wallet.js
index 8e30d3323..9917c8318 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -246,10 +246,10 @@ describe('Wallet', function() {
assert.deepEqual(wallet.getUnspentOutputs(), [utxo])
})
- it("ignores pending spending outputs (outputs with 'to' property)", function() {
+ it("ignores pending spending outputs (outputs with 'spent' property)", function() {
var output = wallet.outputs[expectedOutputKey]
- output.to = fakeTxId(0) + ':' + 0
output.pending = true
+ output.spent = true
assert.deepEqual(wallet.getUnspentOutputs(), [])
})
})
@@ -331,18 +331,19 @@ describe('Wallet', function() {
spendTx = Transaction.fromHex(fixtureTx2Hex)
})
- it("outgoing: sets the pending flag and 'to' on output", function() {
+ it("outgoing: sets the pending flag and 'spent' on output", function() {
var txIn = spendTx.ins[0]
var txInId = new Buffer(txIn.hash)
Array.prototype.reverse.call(txInId)
txInId = txInId.toString('hex')
var key = txInId + ':' + txIn.index
- assert(!wallet.outputs[key].pending)
+ var output = wallet.outputs[key]
+ assert(!output.pending)
wallet.processPendingTx(spendTx)
- assert(wallet.outputs[key].pending)
- assert.equal(wallet.outputs[key].to, spendTx.getId() + ':' + 0)
+ assert(output.pending)
+ assert(output.spent, true)
})
})
})
From 33955a7fb5a2bacb2cfe2237a15bab3f8db6284f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 17 Aug 2014 16:42:00 +1000
Subject: [PATCH 069/291] Wallet: store txHash, vout separately instead of
"from: txid:vout"
---
src/wallet.js | 28 ++++++++++++++++++----------
test/wallet.js | 3 ++-
2 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index 8177a354a..26f8bfdd8 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -64,8 +64,7 @@ Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
var utxo = utxos[i]
addresses.push(utxo.address)
- var outpoint = utxo.from.split(':')
- txb.addInput(outpoint[0], parseInt(outpoint[1]))
+ txb.addInput(utxo.hash, utxo.index)
var fee = fixedFee === undefined ? estimatePaddedFee(txb.buildIncomplete(), this.network) : fixedFee
@@ -97,6 +96,7 @@ Wallet.prototype.processConfirmedTx = function(tx){
Wallet.prototype.__processTx = function(tx, isPending) {
var txId = tx.getId()
+ var txHash = tx.getHash()
tx.outs.forEach(function(txOut, i) {
var address
@@ -112,7 +112,8 @@ Wallet.prototype.__processTx = function(tx, isPending) {
var output = txId + ':' + i
this.outputs[output] = {
- from: output,
+ hash: txHash,
+ index: i,
value: txOut.value,
address: address,
pending: isPending
@@ -233,12 +234,15 @@ Wallet.prototype.signWith = function(txb, addresses) {
return txb
}
-function outputToUnspentOutput(output){
- var hashAndIndex = output.from.split(":")
+function outputToUnspentOutput(output) {
+ var txid = new Buffer(output.hash)
+
+ // hash is little-endian, we want big-endian
+ Array.prototype.reverse.call(txid)
return {
- hash: hashAndIndex[0],
- index: parseInt(hashAndIndex[1]),
+ hash: txid.toString('hex'),
+ index: output.index,
address: output.address,
value: output.value,
pending: output.pending
@@ -271,11 +275,15 @@ function processUnspentOutputs(utxos) {
var key = utxo.hash + ':' + utxo.index
+ // little-endian hash is what we use internally
+ Array.prototype.reverse(hash)
+
outputs[key] = {
- from: key,
address: address,
- value: value,
- pending: utxo.pending
+ hash: hash,
+ index: utxo.index,
+ pending: utxo.pending,
+ value: value
}
})
diff --git a/test/wallet.js b/test/wallet.js
index 9917c8318..133392645 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -422,9 +422,10 @@ describe('Wallet', function() {
function verifyOutputAdded(index, pending) {
var txOut = tx.outs[index]
+
var key = tx.getId() + ":" + index
var output = wallet.outputs[key]
- assert.equal(output.from, key)
+ assert.deepEqual(output.hash, tx.getHash())
assert.equal(output.value, txOut.value)
assert.equal(output.pending, pending)
From 71d4c78b884212edf9c356c0b736b19d2fde9c2e Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 17 Aug 2014 17:24:48 +1000
Subject: [PATCH 070/291] bufferutils: add Buffer reverse
---
src/bufferutils.js | 7 +++++++
src/transaction.js | 12 +++---------
src/wallet.js | 6 ++----
test/bufferutils.js | 13 +++++++++++++
4 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/src/bufferutils.js b/src/bufferutils.js
index 05364e1f3..858a9346c 100644
--- a/src/bufferutils.js
+++ b/src/bufferutils.js
@@ -159,11 +159,18 @@ function writeVarInt(buffer, number, offset) {
return size
}
+function reverse(buffer) {
+ var buffer2 = new Buffer(buffer)
+ Array.prototype.reverse.call(buffer2)
+ return buffer2
+}
+
module.exports = {
pushDataSize: pushDataSize,
readPushDataInt: readPushDataInt,
readUInt64LE: readUInt64LE,
readVarInt: readVarInt,
+ reverse: reverse,
varIntSize: varIntSize,
writePushDataInt: writePushDataInt,
writeUInt64LE: writeUInt64LE,
diff --git a/src/transaction.js b/src/transaction.js
index a9a08997f..91be756d7 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -37,10 +37,8 @@ Transaction.prototype.addInput = function(tx, index, sequence) {
var hash
if (typeof tx === 'string') {
- hash = new Buffer(tx, 'hex')
-
// TxId hex is big-endian, we need little-endian
- Array.prototype.reverse.call(hash)
+ hash = bufferutils.reverse(new Buffer(tx, 'hex'))
} else if (tx instanceof Transaction) {
hash = tx.getHash()
@@ -211,12 +209,8 @@ Transaction.prototype.getHash = function () {
}
Transaction.prototype.getId = function () {
- var buffer = this.getHash()
-
- // Big-endian is used for TxHash
- Array.prototype.reverse.call(buffer)
-
- return buffer.toString('hex')
+ // TxHash is little-endian, we need big-endian
+ return bufferutils.reverse(this.getHash()).toString('hex')
}
Transaction.prototype.clone = function () {
diff --git a/src/wallet.js b/src/wallet.js
index 26f8bfdd8..f3f0adfd4 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -1,4 +1,5 @@
var assert = require('assert')
+var bufferutils = require('./bufferutils')
var crypto = require('crypto')
var networks = require('./networks')
@@ -123,10 +124,7 @@ Wallet.prototype.__processTx = function(tx, isPending) {
tx.ins.forEach(function(txIn, i) {
// copy and convert to big-endian hex
- var txinId = new Buffer(txIn.hash)
- Array.prototype.reverse.call(txinId)
- txinId = txinId.toString('hex')
-
+ var txinId = bufferutils.reverse(txIn.hash).toString('hex')
var output = txinId + ':' + txIn.index
if (!(output in this.outputs)) return
diff --git a/test/bufferutils.js b/test/bufferutils.js
index d7dbfa33f..447d51606 100644
--- a/test/bufferutils.js
+++ b/test/bufferutils.js
@@ -75,6 +75,19 @@ describe('bufferutils', function() {
})
})
+ describe('reverse', function() {
+ fixtures.valid.forEach(function(f) {
+ it('reverses ' + f.hex64 + ' correctly', function() {
+ var buffer = new Buffer(f.hex64, 'hex')
+ var buffer2 = bufferutils.reverse(buffer)
+
+ Array.prototype.reverse.call(buffer)
+
+ assert.deepEqual(buffer, buffer2)
+ })
+ })
+ })
+
describe('varIntSize', function() {
fixtures.valid.forEach(function(f) {
it('determines the varIntSize of ' + f.dec + ' correctly', function() {
From 02e71e430c0c2ca6ca5423842587c0c79c3580db Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 17 Aug 2014 17:35:07 +1000
Subject: [PATCH 071/291] Wallet: revert 2f00c9a
---
src/wallet.js | 96 +++++++++++++++++++++-----------------------------
test/wallet.js | 15 +++++---
2 files changed, 50 insertions(+), 61 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index f3f0adfd4..f9b93cf55 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -8,7 +8,7 @@ var HDNode = require('./hdnode')
var TransactionBuilder = require('./transaction_builder')
var Script = require('./script')
-function Wallet(seed, network, unspents) {
+function Wallet(seed, network) {
seed = seed || crypto.randomBytes(32)
network = network || networks.bitcoin
@@ -24,7 +24,7 @@ function Wallet(seed, network, unspents) {
this.addresses = []
this.changeAddresses = []
this.network = network
- this.outputs = unspents ? processUnspentOutputs(unspents) : {}
+ this.outputs = {}
// FIXME: remove in 2.x.y
var me = this
@@ -202,63 +202,35 @@ Wallet.prototype.getReceiveAddress = function() {
}
Wallet.prototype.getUnspentOutputs = function() {
- var utxo = []
+ var utxos = []
- for(var key in this.outputs){
+ for (var key in this.outputs) {
var output = this.outputs[key]
// Don't include pending spent outputs
if (!output.spent) {
- utxo.push(outputToUnspentOutput(output))
+ // hash is little-endian, we want big-endian
+ var txid = bufferutils.reverse(output.hash)
+
+ utxos.push({
+ hash: txid.toString('hex'),
+ index: output.index,
+ address: output.address,
+ value: output.value,
+ pending: output.pending
+ })
}
}
- return utxo
+ return utxos
}
-Wallet.prototype.setUnspentOutputs = function(utxo) {
- console.warn('setUnspentOutputs is deprecated, please use the constructor option instead')
+Wallet.prototype.setUnspentOutputs = function(utxos) {
+ utxos.forEach(function(utxo) {
+ var txid = utxo.hash
+ assert.equal(typeof txid, 'string', 'Expected txId, got ' + txid)
- this.outputs = processUnspentOutputs(utxo)
-}
-
-Wallet.prototype.signWith = function(txb, addresses) {
- addresses.forEach(function(address, i) {
- var privKey = this.getPrivateKeyForAddress(address)
-
- txb.sign(i, privKey)
- }, this)
-
- return txb
-}
-
-function outputToUnspentOutput(output) {
- var txid = new Buffer(output.hash)
-
- // hash is little-endian, we want big-endian
- Array.prototype.reverse.call(txid)
-
- return {
- hash: txid.toString('hex'),
- index: output.index,
- address: output.address,
- value: output.value,
- pending: output.pending
- }
-}
-
-function estimatePaddedFee(tx, network) {
- var tmpTx = tx.clone()
- tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0)
-
- return network.estimateFee(tmpTx)
-}
-
-function processUnspentOutputs(utxos) {
- var outputs = {}
-
- utxos.forEach(function(utxo){
- var hash = new Buffer(utxo.hash, 'hex')
+ var hash = bufferutils.reverse(new Buffer(txid, 'hex'))
var index = utxo.index
var address = utxo.address
var value = utxo.value
@@ -271,21 +243,33 @@ function processUnspentOutputs(utxos) {
assert.doesNotThrow(function() { Address.fromBase58Check(address) }, 'Expected Base58 Address, got ' + address)
assert.equal(typeof value, 'number', 'Expected number value, got ' + value)
- var key = utxo.hash + ':' + utxo.index
+ var key = txid + ':' + index
- // little-endian hash is what we use internally
- Array.prototype.reverse(hash)
-
- outputs[key] = {
+ this.outputs[key] = {
address: address,
hash: hash,
- index: utxo.index,
+ index: index,
pending: utxo.pending,
value: value
}
- })
+ }, this)
+}
+
+Wallet.prototype.signWith = function(tx, addresses) {
+ addresses.forEach(function(address, i) {
+ var privKey = this.getPrivateKeyForAddress(address)
- return outputs
+ tx.sign(i, privKey)
+ }, this)
+
+ return tx
+}
+
+function estimatePaddedFee(tx, network) {
+ var tmpTx = tx.clone()
+ tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0)
+
+ return network.estimateFee(tmpTx)
}
function getCandidateOutputs(outputs/*, value*/) {
diff --git a/test/wallet.js b/test/wallet.js
index 133392645..c82c127b6 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -212,7 +212,8 @@ describe('Wallet', function() {
describe('on construction', function() {
beforeEach(function() {
- wallet = new Wallet(seed, networks.bitcoin, [utxo])
+ wallet = new Wallet(seed, networks.bitcoin)
+ wallet.setUnspentOutputs([utxo])
})
it('matches the expected behaviour', function() {
@@ -229,7 +230,8 @@ describe('Wallet', function() {
var utxo1 = cloneObject(utxo)
utxo1.hash = fakeTxId(5)
- wallet = new Wallet(seed, networks.bitcoin, [utxo, utxo1])
+ wallet = new Wallet(seed, networks.bitcoin)
+ wallet.setUnspentOutputs([utxo, utxo1])
})
it('sums over utxo values', function() {
@@ -239,7 +241,8 @@ describe('Wallet', function() {
describe('getUnspentOutputs', function() {
beforeEach(function() {
- wallet = new Wallet(seed, networks.bitcoin, [utxo])
+ wallet = new Wallet(seed, networks.bitcoin)
+ wallet.setUnspentOutputs([utxo])
})
it('parses wallet outputs to the expected format', function() {
@@ -468,7 +471,8 @@ describe('Wallet', function() {
}
]
- wallet = new Wallet(seed, networks.testnet, utxos)
+ wallet = new Wallet(seed, networks.testnet)
+ wallet.setUnspentOutputs(utxos)
wallet.generateAddress()
wallet.generateAddress()
})
@@ -497,7 +501,8 @@ describe('Wallet', function() {
value: 500000
}
- var wallet = new Wallet(seed, networks.litecoin, [utxo])
+ var wallet = new Wallet(seed, networks.litecoin)
+ wallet.setUnspentOutputs([utxo])
wallet.generateAddress()
value = 200000
From d24fdef585043f5e29f4568f0988d0dc46f96e28 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 17 Aug 2014 17:39:06 +1000
Subject: [PATCH 072/291] Wallet: consistent variable naming
---
src/wallet.js | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index f9b93cf55..f4faf7fe6 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -210,10 +210,10 @@ Wallet.prototype.getUnspentOutputs = function() {
// Don't include pending spent outputs
if (!output.spent) {
// hash is little-endian, we want big-endian
- var txid = bufferutils.reverse(output.hash)
+ var txId = bufferutils.reverse(output.hash)
utxos.push({
- hash: txid.toString('hex'),
+ hash: txId.toString('hex'),
index: output.index,
address: output.address,
value: output.value,
@@ -227,10 +227,10 @@ Wallet.prototype.getUnspentOutputs = function() {
Wallet.prototype.setUnspentOutputs = function(utxos) {
utxos.forEach(function(utxo) {
- var txid = utxo.hash
- assert.equal(typeof txid, 'string', 'Expected txId, got ' + txid)
+ var txId = utxo.hash
+ assert.equal(typeof txId, 'string', 'Expected txId, got ' + txId)
- var hash = bufferutils.reverse(new Buffer(txid, 'hex'))
+ var hash = bufferutils.reverse(new Buffer(txId, 'hex'))
var index = utxo.index
var address = utxo.address
var value = utxo.value
@@ -243,9 +243,9 @@ Wallet.prototype.setUnspentOutputs = function(utxos) {
assert.doesNotThrow(function() { Address.fromBase58Check(address) }, 'Expected Base58 Address, got ' + address)
assert.equal(typeof value, 'number', 'Expected number value, got ' + value)
- var key = txid + ':' + index
+ var output = txId + ':' + index
- this.outputs[key] = {
+ this.outputs[output] = {
address: address,
hash: hash,
index: index,
@@ -273,18 +273,20 @@ function estimatePaddedFee(tx, network) {
}
function getCandidateOutputs(outputs/*, value*/) {
- var unspent = []
+ var unspents = []
for (var key in outputs) {
var output = outputs[key]
- if (!output.pending) unspent.push(output)
+
+ if (!output.pending) {
+ unspents.push(output)
+ }
}
- var sortByValueDesc = unspent.sort(function(o1, o2){
+ // sorted by descending value
+ return unspents.sort(function(o1, o2) {
return o2.value - o1.value
})
-
- return sortByValueDesc
}
module.exports = Wallet
From 06f13db8d752fa3805db612a675a852dbc9a1413 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 18 Aug 2014 15:18:20 +1000
Subject: [PATCH 073/291] Wallet: rename outputs to unspentsMap
---
src/wallet.js | 22 +++++++++++-----------
test/wallet.js | 26 +++++++++++++-------------
2 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index f4faf7fe6..00a08579c 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -24,7 +24,7 @@ function Wallet(seed, network) {
this.addresses = []
this.changeAddresses = []
this.network = network
- this.outputs = {}
+ this.unspentMap = {}
// FIXME: remove in 2.x.y
var me = this
@@ -41,7 +41,7 @@ function Wallet(seed, network) {
me.addresses = []
me.changeAddresses = []
- me.outputs = {}
+ me.unspentMap = {}
}
this.getMasterKey = function() { return masterKey }
@@ -53,7 +53,7 @@ function Wallet(seed, network) {
Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
assert(value > this.network.dustThreshold, value + ' must be above dust threshold (' + this.network.dustThreshold + ' Satoshis)')
- var utxos = getCandidateOutputs(this.outputs, value)
+ var utxos = getCandidateOutputs(this.unspentMap, value)
var accum = 0
var subTotal = value
var addresses = []
@@ -112,7 +112,7 @@ Wallet.prototype.__processTx = function(tx, isPending) {
if (myAddresses.indexOf(address) > -1) {
var output = txId + ':' + i
- this.outputs[output] = {
+ this.unspentMap[output] = {
hash: txHash,
index: i,
value: txOut.value,
@@ -127,14 +127,14 @@ Wallet.prototype.__processTx = function(tx, isPending) {
var txinId = bufferutils.reverse(txIn.hash).toString('hex')
var output = txinId + ':' + txIn.index
- if (!(output in this.outputs)) return
+ if (!(output in this.unspentMap)) return
if (isPending) {
- this.outputs[output].pending = true
- this.outputs[output].spent = true
+ this.unspentMap[output].pending = true
+ this.unspentMap[output].spent = true
} else {
- delete this.outputs[output]
+ delete this.unspentMap[output]
}
}, this)
}
@@ -204,8 +204,8 @@ Wallet.prototype.getReceiveAddress = function() {
Wallet.prototype.getUnspentOutputs = function() {
var utxos = []
- for (var key in this.outputs) {
- var output = this.outputs[key]
+ for (var key in this.unspentMap) {
+ var output = this.unspentMap[key]
// Don't include pending spent outputs
if (!output.spent) {
@@ -245,7 +245,7 @@ Wallet.prototype.setUnspentOutputs = function(utxos) {
var output = txId + ':' + index
- this.outputs[output] = {
+ this.unspentMap[output] = {
address: address,
hash: hash,
index: index,
diff --git a/test/wallet.js b/test/wallet.js
index c82c127b6..917c3bfe1 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -217,7 +217,7 @@ describe('Wallet', function() {
})
it('matches the expected behaviour', function() {
- var output = wallet.outputs[expectedOutputKey]
+ var output = wallet.unspentMap[expectedOutputKey]
assert(output)
assert.equal(output.value, utxo.value)
@@ -250,7 +250,7 @@ describe('Wallet', function() {
})
it("ignores pending spending outputs (outputs with 'spent' property)", function() {
- var output = wallet.outputs[expectedOutputKey]
+ var output = wallet.unspentMap[expectedOutputKey]
output.pending = true
output.spent = true
assert.deepEqual(wallet.getUnspentOutputs(), [])
@@ -279,7 +279,7 @@ describe('Wallet', function() {
it('matches the expected behaviour', function() {
wallet.setUnspentOutputs([utxo])
- var output = wallet.outputs[expectedOutputKey]
+ var output = wallet.unspentMap[expectedOutputKey]
assert(output)
assert.equal(output.value, utxo.value)
assert.equal(output.address, utxo.address)
@@ -341,7 +341,7 @@ describe('Wallet', function() {
txInId = txInId.toString('hex')
var key = txInId + ':' + txIn.index
- var output = wallet.outputs[key]
+ var output = wallet.unspentMap[key]
assert(!output.pending)
wallet.processPendingTx(spendTx)
@@ -363,7 +363,7 @@ describe('Wallet', function() {
wallet.processConfirmedTx(tx2)
})
- describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.outputs", function() {
+ describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.unspentMap", function() {
it("works for receive address", function() {
var totalOuts = outputCount()
@@ -385,7 +385,7 @@ describe('Wallet', function() {
})
function outputCount() {
- return Object.keys(wallet.outputs).length
+ return Object.keys(wallet.unspentMap).length
}
})
@@ -398,9 +398,9 @@ describe('Wallet', function() {
spendTx = Transaction.fromHex(fixtureTx2Hex)
})
- it("does not add to wallet.outputs", function() {
+ it("does not add to wallet.unspentMap", function() {
wallet.processConfirmedTx(spendTx)
- assert.deepEqual(wallet.outputs, {})
+ assert.deepEqual(wallet.unspentMap, {})
})
it("deletes corresponding 'output'", function() {
@@ -410,16 +410,16 @@ describe('Wallet', function() {
txInId = txInId.toString('hex')
var expected = txInId + ':' + txIn.index
- assert(expected in wallet.outputs)
+ assert(expected in wallet.unspentMap)
wallet.processConfirmedTx(spendTx)
- assert(!(expected in wallet.outputs))
+ assert(!(expected in wallet.unspentMap))
})
})
it("does nothing when none of the involved addresses belong to the wallet", function() {
wallet.processConfirmedTx(tx)
- assert.deepEqual(wallet.outputs, {})
+ assert.deepEqual(wallet.unspentMap, {})
})
})
@@ -427,7 +427,7 @@ describe('Wallet', function() {
var txOut = tx.outs[index]
var key = tx.getId() + ":" + index
- var output = wallet.outputs[key]
+ var output = wallet.unspentMap[key]
assert.deepEqual(output.hash, tx.getHash())
assert.equal(output.value, txOut.value)
assert.equal(output.pending, pending)
@@ -514,7 +514,7 @@ describe('Wallet', function() {
function getFee(wallet, tx) {
var inputValue = tx.ins.reduce(function(memo, input){
var id = Array.prototype.reverse.call(input.hash).toString('hex')
- return memo + wallet.outputs[id + ':' + input.index].value
+ return memo + wallet.unspentMap[id + ':' + input.index].value
}, 0)
return tx.outs.reduce(function(memo, output){
From b727a65ea0dde78b8806d8e1162e13b1fc03e6e5 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 18 Aug 2014 15:23:13 +1000
Subject: [PATCH 074/291] Wallet: refactor to use Array unspents solely,
deprecating unspentsMap
---
src/wallet.js | 236 +++++++++++++++++++++++++++++++------------------
test/wallet.js | 85 ++++++++++--------
2 files changed, 196 insertions(+), 125 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index 00a08579c..f25f7d856 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -24,9 +24,12 @@ function Wallet(seed, network) {
this.addresses = []
this.changeAddresses = []
this.network = network
+ this.unspents = []
+
+ // FIXME: remove in 2.0.0
this.unspentMap = {}
- // FIXME: remove in 2.x.y
+ // FIXME: remove in 2.0.0
var me = this
this.newMasterKey = function(seed) {
console.warn('newMasterKey is deprecated, please make a new Wallet instance instead')
@@ -41,6 +44,7 @@ function Wallet(seed, network) {
me.addresses = []
me.changeAddresses = []
+ me.unspents = []
me.unspentMap = {}
}
@@ -50,27 +54,54 @@ function Wallet(seed, network) {
this.getInternalAccount = function() { return internalAccount }
}
-Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
+Wallet.prototype.createTransaction = function(to, value, options) {
+ // FIXME: remove in 2.0.0
+ if (typeof options !== 'object') {
+ if (options !== undefined) {
+ console.warn('Non options object parameters are deprecated, use options object instead')
+
+ options = {
+ fixedFee: arguments[2],
+ changeAddress: arguments[3]
+ }
+ }
+ }
+
+ options = options || {}
+
assert(value > this.network.dustThreshold, value + ' must be above dust threshold (' + this.network.dustThreshold + ' Satoshis)')
- var utxos = getCandidateOutputs(this.unspentMap, value)
+ var changeAddress = options.changeAddress
+ var fixedFee = options.fixedFee
+ var minConf = options.minConf === undefined ? 0 : options.minConf // FIXME: change minConf:1 by default in 2.0.0
+
+ // filter by minConf, then pending and sort by descending value
+ var unspents = this.unspents.filter(function(unspent) {
+ return unspent.confirmations >= minConf
+ }).filter(function(unspent) {
+ return !unspent.pending
+ }).sort(function(o1, o2) {
+ return o2.value - o1.value
+ })
+
var accum = 0
- var subTotal = value
var addresses = []
+ var subTotal = value
var txb = new TransactionBuilder()
txb.addOutput(to, value)
- for (var i = 0; i < utxos.length; ++i) {
- var utxo = utxos[i]
- addresses.push(utxo.address)
+ for (var i = 0; i < unspents.length; ++i) {
+ var unspent = unspents[i]
+ addresses.push(unspent.address)
- txb.addInput(utxo.hash, utxo.index)
+ txb.addInput(unspent.txHash, unspent.index)
var fee = fixedFee === undefined ? estimatePaddedFee(txb.buildIncomplete(), this.network) : fixedFee
- accum += utxo.value
+ accum += unspent.value
subTotal = value + fee
+
if (accum >= subTotal) {
var change = accum - subTotal
@@ -87,15 +118,20 @@ Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
return this.signWith(txb, addresses).build()
}
+// FIXME: remove in 2.0.0
Wallet.prototype.processPendingTx = function(tx){
this.__processTx(tx, true)
}
+// FIXME: remove in 2.0.0
Wallet.prototype.processConfirmedTx = function(tx){
this.__processTx(tx, false)
}
+// FIXME: remove in 2.0.0
Wallet.prototype.__processTx = function(tx, isPending) {
+ console.warn('processTransaction is considered harmful, see issue #260 for more information')
+
var txId = tx.getId()
var txHash = tx.getHash()
@@ -110,31 +146,44 @@ Wallet.prototype.__processTx = function(tx, isPending) {
var myAddresses = this.addresses.concat(this.changeAddresses)
if (myAddresses.indexOf(address) > -1) {
- var output = txId + ':' + i
+ var lookup = txId + ':' + i
+ if (lookup in this.unspentMap) return
- this.unspentMap[output] = {
- hash: txHash,
+ // its unique, add it
+ var unspent = {
+ address: address,
+ confirmations: 0, // no way to determine this without more information
index: i,
+ txHash: txHash,
+ txId: txId,
value: txOut.value,
- address: address,
pending: isPending
}
+
+ this.unspentMap[lookup] = unspent
+ this.unspents.push(unspent)
}
}, this)
tx.ins.forEach(function(txIn, i) {
// copy and convert to big-endian hex
- var txinId = bufferutils.reverse(txIn.hash).toString('hex')
- var output = txinId + ':' + txIn.index
+ var txInId = bufferutils.reverse(txIn.hash).toString('hex')
+
+ var lookup = txInId + ':' + txIn.index
+ if (!(lookup in this.unspentMap)) return
- if (!(output in this.unspentMap)) return
+ var unspent = this.unspentMap[lookup]
if (isPending) {
- this.unspentMap[output].pending = true
- this.unspentMap[output].spent = true
+ unspent.pending = true
+ unspent.spent = true
} else {
- delete this.unspentMap[output]
+ delete this.unspentMap[lookup]
+
+ this.unspents = this.unspents.filter(function(unspent2) {
+ return unspent !== unspent2
+ })
}
}, this)
}
@@ -157,9 +206,25 @@ Wallet.prototype.generateChangeAddress = function() {
return this.getChangeAddress()
}
-Wallet.prototype.getBalance = function() {
- return this.getUnspentOutputs().reduce(function(accum, output) {
- return accum + output.value
+Wallet.prototype.getAddress = function() {
+ if (this.addresses.length === 0) {
+ this.generateAddress()
+ }
+
+ return this.addresses[this.addresses.length - 1]
+}
+
+Wallet.prototype.getBalance = function(minConf) {
+ minConf = minConf || 0
+
+ return this.unspents.filter(function(unspent) {
+ return unspent.confirmations >= minConf
+
+ // FIXME: remove spent filter in 2.0.0
+ }).filter(function(unspent) {
+ return !unspent.spent
+ }).reduce(function(accum, unspent) {
+ return accum + unspent.value
}, 0)
}
@@ -193,65 +258,77 @@ Wallet.prototype.getPrivateKeyForAddress = function(address) {
assert(false, 'Unknown address. Make sure the address is from the keychain and has been generated')
}
-Wallet.prototype.getReceiveAddress = function() {
- if (this.addresses.length === 0) {
- this.generateAddress()
- }
-
- return this.addresses[this.addresses.length - 1]
+Wallet.prototype.getUnspentOutputs = function(minConf) {
+ minConf = minConf || 0
+
+ return this.unspents.filter(function(unspent) {
+ return unspent.confirmations >= minConf
+
+ // FIXME: remove spent filter in 2.0.0
+ }).filter(function(unspent) {
+ return !unspent.spent
+ }).map(function(unspent) {
+ return {
+ address: unspent.address,
+ confirmations: unspent.confirmations,
+ index: unspent.index,
+ txId: unspent.txId,
+ value: unspent.value,
+
+ // FIXME: remove in 2.0.0
+ hash: unspent.txId,
+ pending: unspent.pending
+ }
+ })
}
-Wallet.prototype.getUnspentOutputs = function() {
- var utxos = []
-
- for (var key in this.unspentMap) {
- var output = this.unspentMap[key]
-
- // Don't include pending spent outputs
- if (!output.spent) {
- // hash is little-endian, we want big-endian
- var txId = bufferutils.reverse(output.hash)
+Wallet.prototype.setUnspentOutputs = function(unspents) {
+ this.unspentMap = {}
+ this.unspents = unspents.map(function(unspent) {
+ // FIXME: remove unspent.hash in 2.0.0
+ var txId = unspent.txId || unspent.hash
+ var index = unspent.index
+
+ // FIXME: remove in 2.0.0
+ if (unspent.hash !== undefined) {
+ console.warn('unspent.hash is deprecated, use unspent.txId instead')
+ }
- utxos.push({
- hash: txId.toString('hex'),
- index: output.index,
- address: output.address,
- value: output.value,
- pending: output.pending
- })
+ // FIXME: remove in 2.0.0
+ if (index === undefined) {
+ console.warn('unspent.outputIndex is deprecated, use unspent.index instead')
+ index = utxo.outputIndex
}
- }
- return utxos
-}
+ assert.equal(typeof txId, 'string', 'Expected txId, got ' + txId)
+ assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId)
+ assert.doesNotThrow(function() { Address.fromBase58Check(unspent.address) }, 'Expected Base58 Address, got ' + unspent.address)
+ assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
+ assert.equal(typeof unspent.value, 'number', 'Expected number value, got ' + unspent.value)
-Wallet.prototype.setUnspentOutputs = function(utxos) {
- utxos.forEach(function(utxo) {
- var txId = utxo.hash
- assert.equal(typeof txId, 'string', 'Expected txId, got ' + txId)
+ // FIXME: remove branch in 2.0.0
+ if (unspent.confirmations !== undefined) {
+ assert.equal(typeof unspent.confirmations, 'number', 'Expected number confirmations, got ' + unspent.confirmations)
+ }
- var hash = bufferutils.reverse(new Buffer(txId, 'hex'))
- var index = utxo.index
- var address = utxo.address
- var value = utxo.value
+ var txHash = bufferutils.reverse(new Buffer(txId, 'hex'))
- // FIXME: remove alternative in 2.x.y
- if (index === undefined) index = utxo.outputIndex
+ var unspent = {
+ address: unspent.address,
+ confirmations: unspent.confirmations || 0,
+ index: index,
+ txHash: txHash,
+ txId: txId,
+ value: unspent.value,
- assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
- assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
- assert.doesNotThrow(function() { Address.fromBase58Check(address) }, 'Expected Base58 Address, got ' + address)
- assert.equal(typeof value, 'number', 'Expected number value, got ' + value)
+ // FIXME: remove in 2.0.0
+ pending: unspent.pending || false
+ }
- var output = txId + ':' + index
+ // FIXME: remove in 2.0.0
+ this.unspentMap[txId + ':' + index] = unspent
- this.unspentMap[output] = {
- address: address,
- hash: hash,
- index: index,
- pending: utxo.pending,
- value: value
- }
+ return unspent
}, this)
}
@@ -272,21 +349,8 @@ function estimatePaddedFee(tx, network) {
return network.estimateFee(tmpTx)
}
-function getCandidateOutputs(outputs/*, value*/) {
- var unspents = []
-
- for (var key in outputs) {
- var output = outputs[key]
-
- if (!output.pending) {
- unspents.push(output)
- }
- }
-
- // sorted by descending value
- return unspents.sort(function(o1, o2) {
- return o2.value - o1.value
- })
-}
+// FIXME: 1.0.0 shims, remove in 2.0.0
+Wallet.prototype.getReceiveAddress = Wallet.prototype.getAddress
+Wallet.prototype.createTx = Wallet.prototype.createTransaction
module.exports = Wallet
diff --git a/test/wallet.js b/test/wallet.js
index 917c3bfe1..f73d7be0b 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -1,4 +1,5 @@
var assert = require('assert')
+var bufferutils = require('../src/bufferutils')
var crypto = require('../src/crypto')
var networks = require('../src/networks')
var sinon = require('sinon')
@@ -201,13 +202,12 @@ describe('Wallet', function() {
beforeEach(function() {
utxo = {
"address" : "1AZpKpcfCzKDUeTFBQUL4MokQai3m3HMXv",
- "hash": fakeTxId(6),
+ "confirmations": 1,
"index": 0,
- "pending": true,
- "value": 20000
+ "txId": fakeTxId(6),
+ "value": 20000,
+ "pending": false
}
-
- expectedOutputKey = utxo.hash + ":" + utxo.index
})
describe('on construction', function() {
@@ -217,11 +217,10 @@ describe('Wallet', function() {
})
it('matches the expected behaviour', function() {
- var output = wallet.unspentMap[expectedOutputKey]
+ var output = wallet.unspents[0]
- assert(output)
- assert.equal(output.value, utxo.value)
assert.equal(output.address, utxo.address)
+ assert.equal(output.value, utxo.value)
})
})
@@ -245,20 +244,32 @@ describe('Wallet', function() {
wallet.setUnspentOutputs([utxo])
})
- it('parses wallet outputs to the expected format', function() {
- assert.deepEqual(wallet.getUnspentOutputs(), [utxo])
+ it('parses wallet unspents to the expected format', function() {
+ var outputs = wallet.getUnspentOutputs()
+ var output = outputs[0]
+
+ assert.equal(utxo.address, output.address)
+ assert.equal(utxo.index, output.index)
+ assert.equal(utxo.value, output.value)
+
+ // FIXME: remove in 2.0.0
+ assert.equal(utxo.txId, output.hash)
+ assert.equal(utxo.pending, output.pending)
+
+ // new in 2.0.0
+ assert.equal(utxo.txId, output.txId)
+ assert.equal(utxo.confirmations, output.confirmations)
})
- it("ignores pending spending outputs (outputs with 'spent' property)", function() {
- var output = wallet.unspentMap[expectedOutputKey]
- output.pending = true
- output.spent = true
+ it("ignores spent unspents (outputs with 'spent' property)", function() {
+ var unspent = wallet.unspents[0]
+ unspent.pending = true
+ unspent.spent = true
assert.deepEqual(wallet.getUnspentOutputs(), [])
})
})
})
- // FIXME: remove in 2.x.y
describe('setUnspentOutputs', function() {
var utxo
var expectedOutputKey
@@ -271,16 +282,13 @@ describe('Wallet', function() {
value: 500000
}
- expectedOutputKey = utxo.hash + ":" + utxo.index
-
wallet = new Wallet(seed, networks.bitcoin)
})
it('matches the expected behaviour', function() {
wallet.setUnspentOutputs([utxo])
- var output = wallet.unspentMap[expectedOutputKey]
- assert(output)
+ var output = wallet.unspents[0]
assert.equal(output.value, utxo.value)
assert.equal(output.address, utxo.address)
})
@@ -340,13 +348,12 @@ describe('Wallet', function() {
Array.prototype.reverse.call(txInId)
txInId = txInId.toString('hex')
- var key = txInId + ':' + txIn.index
- var output = wallet.unspentMap[key]
+ var unspent = wallet.unspents[0]
+ assert(!unspent.pending)
- assert(!output.pending)
wallet.processPendingTx(spendTx)
- assert(output.pending)
- assert(output.spent, true)
+ assert(unspent.pending)
+ assert(unspent.spent, true)
})
})
})
@@ -389,7 +396,7 @@ describe('Wallet', function() {
}
})
- describe("when tx ins outpoint contains a known txhash:i", function() {
+ describe("when tx ins contains a known txhash:i", function() {
var spendTx
beforeEach(function() {
wallet.addresses = [addresses[0]] // the address fixtureTx2 used as input
@@ -403,11 +410,9 @@ describe('Wallet', function() {
assert.deepEqual(wallet.unspentMap, {})
})
- it("deletes corresponding 'output'", function() {
+ it("deletes corresponding 'unspent'", function() {
var txIn = spendTx.ins[0]
- var txInId = new Buffer(txIn.hash)
- Array.prototype.reverse.call(txInId)
- txInId = txInId.toString('hex')
+ var txInId = bufferutils.reverse(txIn.hash).toString('hex')
var expected = txInId + ':' + txIn.index
assert(expected in wallet.unspentMap)
@@ -416,19 +421,20 @@ describe('Wallet', function() {
assert(!(expected in wallet.unspentMap))
})
})
+ })
- it("does nothing when none of the involved addresses belong to the wallet", function() {
- wallet.processConfirmedTx(tx)
- assert.deepEqual(wallet.unspentMap, {})
- })
+ it("does nothing when none of the involved addresses belong to the wallet", function() {
+ wallet.processConfirmedTx(tx)
+ assert.deepEqual(wallet.unspentMap, {})
})
+
function verifyOutputAdded(index, pending) {
var txOut = tx.outs[index]
var key = tx.getId() + ":" + index
var output = wallet.unspentMap[key]
- assert.deepEqual(output.hash, tx.getHash())
+ assert.deepEqual(output.txHash, tx.getHash())
assert.equal(output.value, txOut.value)
assert.equal(output.pending, pending)
@@ -512,13 +518,14 @@ describe('Wallet', function() {
})
function getFee(wallet, tx) {
- var inputValue = tx.ins.reduce(function(memo, input){
- var id = Array.prototype.reverse.call(input.hash).toString('hex')
- return memo + wallet.unspentMap[id + ':' + input.index].value
+ var inputValue = tx.ins.reduce(function(accum, input) {
+ var txId = bufferutils.reverse(input.hash).toString('hex')
+
+ return accum + wallet.unspentMap[txId + ':' + input.index].value
}, 0)
- return tx.outs.reduce(function(memo, output){
- return memo - output.value
+ return tx.outs.reduce(function(accum, output) {
+ return accum - output.value
}, inputValue)
}
})
From 6e1517482b024faf6176d0462d9844027592cd2c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 18 Aug 2014 15:52:36 +1000
Subject: [PATCH 075/291] tests: avoid use of deprecated APIs
---
test/wallet.js | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/test/wallet.js b/test/wallet.js
index f73d7be0b..4e49ca825 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -458,19 +458,19 @@ describe('Wallet', function() {
// set up 3 utxos
var utxos = [
{
- "hash": fakeTxId(1),
+ "txId": fakeTxId(1),
"index": 0,
"address": address1,
"value": 400000 // not enough for value
},
{
- "hash": fakeTxId(2),
+ "txId": fakeTxId(2),
"index": 1,
"address": address1,
"value": 500000 // enough for only value
},
{
- "hash": fakeTxId(3),
+ "txId": fakeTxId(3),
"index": 0,
"address" : address2,
"value": 510000 // enough for value and fee
@@ -486,7 +486,7 @@ describe('Wallet', function() {
describe('transaction fee', function() {
it('allows fee to be specified', function() {
var fee = 30000
- var tx = wallet.createTx(to, value, fee)
+ var tx = wallet.createTx(to, value, { fixedFee: fee })
assert.equal(getFee(wallet, tx), fee)
})
@@ -494,14 +494,14 @@ describe('Wallet', function() {
it('allows fee to be set to zero', function() {
value = 510000
var fee = 0
- var tx = wallet.createTx(to, value, fee)
+ var tx = wallet.createTx(to, value, { fixedFee: fee })
assert.equal(getFee(wallet, tx), fee)
})
it('does not overestimate fees when network has dustSoftThreshold', function() {
var utxo = {
- hash: fakeTxId(0),
+ txId: fakeTxId(0),
index: 0,
address: "LeyySKbQrRRwodKEj1W4a8y3YQupPLw5os",
value: 500000
@@ -573,7 +573,10 @@ describe('Wallet', function() {
var toValue = fromValue / 2
var fee = 1e3
- var tx = wallet.createTx(to, toValue, fee, changeAddress)
+ var tx = wallet.createTx(to, toValue, {
+ fixedFee: fee,
+ changeAddress: changeAddress
+ })
assert.equal(tx.outs.length, 2)
var outAddress0 = Address.fromOutputScript(tx.outs[0].script, networks.testnet)
@@ -604,7 +607,7 @@ describe('Wallet', function() {
var fee = 0
wallet.generateChangeAddress()
wallet.generateChangeAddress()
- var tx = wallet.createTx(to, value, fee)
+ var tx = wallet.createTx(to, value, { fixedFee: fee })
assert.equal(tx.outs.length, 2)
var out = tx.outs[1]
@@ -618,7 +621,7 @@ describe('Wallet', function() {
var fee = 0
assert.equal(wallet.changeAddresses.length, 0)
- var tx = wallet.createTx(to, value, fee)
+ var tx = wallet.createTx(to, value, { fixedFee: fee })
assert.equal(wallet.changeAddresses.length, 1)
var out = tx.outs[1]
@@ -645,7 +648,7 @@ describe('Wallet', function() {
var fee = 30000
sinon.spy(TransactionBuilder.prototype, "sign")
- var tx = wallet.createTx(to, value, fee)
+ var tx = wallet.createTx(to, value, { fixedFee: fee })
assert(TransactionBuilder.prototype.sign.calledWith(0, wallet.getPrivateKeyForAddress(address2)))
assert(TransactionBuilder.prototype.sign.calledWith(1, wallet.getPrivateKeyForAddress(address1)))
From 1c744cfa5abf2aa8340005f20faa26974b793bcb Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 30 Aug 2014 12:09:31 +1000
Subject: [PATCH 076/291] TxBuilder: add failing test for non-zero vin inputs
---
test/fixtures/transaction_builder.json | 20 ++++++++++++++++++++
test/transaction_builder.js | 1 +
2 files changed, 21 insertions(+)
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index c2444eaa0..6795c4865 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -63,6 +63,26 @@
"value": 10000
}
]
+ },
+ {
+ "description": "Transaction w/ non-zero vin inputs",
+ "txid": "7d9b699f26765fdfdd598223a952a6e129f8c159e2e05e911af822ee743fa745",
+ "txhex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a47304402205c80bbb5125b35d5e5a8324b1336832d29a6fc004859c8a9ff6bef47ba7fc348022018612216e57a521b2c4543f1f4fd738a76814c37c074e88adfe12464fff31cf901210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
+ "inputs": [
+ {
+ "index": 1,
+ "prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "privKeys": [
+ "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+ "value": 10000
+ }
+ ]
}
]
},
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index d6ab2f0a0..7f16dbce5 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -182,6 +182,7 @@ describe('TransactionBuilder', function() {
var tx = txb.build()
assert.equal(tx.getId(), f.txid)
+ assert.equal(tx.toHex(), f.txhex)
})
})
From e2357c09ce74f30676e129e15ef16adbfe0493c1 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 30 Aug 2014 12:10:02 +1000
Subject: [PATCH 077/291] TxBuilder: fix invalid txin.index usage for non-zero
vin inputs
---
src/transaction_builder.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 05c0591ef..c4f18da6b 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -30,7 +30,7 @@ TransactionBuilder.fromTransaction = function(transaction) {
})
// Extract/add signatures
- transaction.ins.forEach(function(txin) {
+ transaction.ins.forEach(function(txin, i) {
// Ignore empty scripts
if (txin.script.buffer.length === 0) return
@@ -86,7 +86,7 @@ TransactionBuilder.fromTransaction = function(transaction) {
assert(false, scriptType + ' not supported')
}
- txb.signatures[txin.index] = {
+ txb.signatures[i] = {
hashType: hashType,
pubKeys: pubKeys,
redeemScript: redeemScript,
From aa80bde815eaf1b669e16013171759e1b80076de Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 30 Aug 2014 12:22:55 +1000
Subject: [PATCH 078/291] TxBuilder: avoid unnecessary recalculation of
prevOutScript data
---
src/transaction_builder.js | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index c4f18da6b..42a77bfce 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -231,13 +231,18 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
} else {
prevOutScript = prevOutScript || privKey.pub.getAddress().toOutputScript()
- scriptType = prevOutType || 'pubkeyhash'
+ prevOutType = prevOutType || 'pubkeyhash'
- assert.notEqual(scriptType, 'scripthash', 'PrevOutScript requires redeemScript')
+ assert.notEqual(prevOutType, 'scripthash', 'PrevOutScript is P2SH, missing redeemScript')
+
+ scriptType = prevOutType
hash = this.tx.hashForSignature(index, prevOutScript, hashType)
}
+ this.prevOutScripts[index] = prevOutScript
+ this.prevOutTypes[index] = prevOutType
+
if (!(index in this.signatures)) {
this.signatures[index] = {
hashType: hashType,
From b3438c5ef2636711011afe481650670dc4f2d273 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 30 Aug 2014 12:51:29 +1000
Subject: [PATCH 079/291] Transaction: throw if sequence is not a number
---
src/transaction.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/transaction.js b/src/transaction.js
index a9a08997f..ffb952257 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -52,6 +52,7 @@ Transaction.prototype.addInput = function(tx, index, sequence) {
assert(Buffer.isBuffer(hash), 'Expected Transaction, txId or txHash, got ' + tx)
assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
+ assert.equal(typeof sequence, 'number', 'Expected number sequence, got ' + sequence)
// Add the input and return the input's index
return (this.ins.push({
From e5618bb8bd0c69ea9d5677d4a6fc4a3bf8698a49 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 30 Aug 2014 12:52:05 +1000
Subject: [PATCH 080/291] TxBuilder: add test for missing redeemScript if P2SH
---
test/transaction_builder.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 7f16dbce5..fb2ae674b 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -110,6 +110,18 @@ describe('TransactionBuilder', function() {
})
})
+ describe('when redeemScript is undefined', function() {
+ it('throws if prevOutScript is P2SH', function() {
+ var privScriptP2SH = scripts.scriptHashOutput(privScript.getHash())
+
+ txb.addInput(prevTxHash, 0, undefined, privScriptP2SH)
+
+ assert.throws(function() {
+ txb.sign(0, privKey)
+ }, /PrevOutScript is P2SH, missing redeemScript/)
+ })
+ })
+
describe('when redeemScript is defined', function() {
it('assumes scriptHash', function() {
txb.addInput(prevTxHash, 0)
From 8d5ef2dd063cf0d9671734b9df3391e42aeb2021 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 30 Aug 2014 13:02:26 +1000
Subject: [PATCH 081/291] TxBuilder: limit signatures depending on scriptType
---
src/transaction_builder.js | 2 ++
test/transaction_builder.js | 9 +++++++++
2 files changed, 11 insertions(+)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 42a77bfce..fc6a419c0 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -251,6 +251,8 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
scriptType: scriptType,
signatures: []
}
+ } else {
+ assert.equal(scriptType, 'multisig', scriptType + ' doesn\'t support multiple signatures')
}
var input = this.signatures[index]
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index fb2ae674b..974f68751 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -110,6 +110,15 @@ describe('TransactionBuilder', function() {
})
})
+ it('throws if scriptType doesn\'t support multiple signatures', function() {
+ txb.addInput(prevTxHash, 0)
+ txb.sign(0, privKey)
+
+ assert.throws(function() {
+ txb.sign(0, privKey)
+ }, /pubkeyhash doesn\'t support multiple signatures/)
+ })
+
describe('when redeemScript is undefined', function() {
it('throws if prevOutScript is P2SH', function() {
var privScriptP2SH = scripts.scriptHashOutput(privScript.getHash())
From e1479b6fa54a9c33c9c7cbd0f7378603d1643461 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 30 Aug 2014 13:02:02 +1000
Subject: [PATCH 082/291] scripts: add error for >n signatures with multisig
---
src/scripts.js | 10 +++++++---
test/fixtures/scripts.json | 13 +++++++++++++
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index 661285ab1..88e3e616c 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -238,9 +238,13 @@ function multisigInput(signatures, scriptPubKey) {
if (scriptPubKey) {
assert(isMultisigOutput.call(scriptPubKey))
- var m = scriptPubKey.chunks[0]
- var k = m - (opcodes.OP_1 - 1)
- assert(k <= signatures.length, 'Not enough signatures provided')
+ var mOp = scriptPubKey.chunks[0]
+ var nOp = scriptPubKey.chunks[scriptPubKey.chunks.length - 2]
+ var m = mOp - (opcodes.OP_1 - 1)
+ var n = nOp - (opcodes.OP_1 - 1)
+
+ assert(signatures.length >= m, 'Not enough signatures provided')
+ assert(signatures.length <= n, 'Too many signatures provided')
}
return Script.fromChunks([].concat(opcodes.OP_0, signatures))
diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json
index 666ea592e..e264a4ab0 100644
--- a/test/fixtures/scripts.json
+++ b/test/fixtures/scripts.json
@@ -101,6 +101,19 @@
"304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801"
],
"scriptPubKey": false
+ },
+ {
+ "exception": "Too many signatures provided",
+ "pubKeys": [
+ "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
+ "0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a"
+ ],
+ "signatures": [
+ "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+ "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
+ "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
+ ],
+ "scriptPubKey": false
}
]
}
From 1d0fd3e9a473108ce55fd9eb5a9726593d04caa2 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 30 Aug 2014 14:35:46 +1000
Subject: [PATCH 083/291] TxBuilder: add more failing cases and error handling
---
src/transaction_builder.js | 6 +++++-
test/fixtures/transaction_builder.json | 10 ++++++++++
test/transaction_builder.js | 10 ++++++++++
3 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index fc6a419c0..c0acb099c 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -34,6 +34,10 @@ TransactionBuilder.fromTransaction = function(transaction) {
// Ignore empty scripts
if (txin.script.buffer.length === 0) return
+ assert(!Array.prototype.every.call(txin.hash, function(x) {
+ return x === 0
+ }), 'coinbase inputs not supported')
+
var redeemScript
var scriptSig = txin.script
var scriptType = scripts.classifyInput(scriptSig)
@@ -83,7 +87,7 @@ TransactionBuilder.fromTransaction = function(transaction) {
break
default:
- assert(false, scriptType + ' not supported')
+ assert(false, scriptType + ' inputs not supported')
}
txb.signatures[i] = {
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index 6795c4865..a44078b26 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -167,6 +167,16 @@
}
]
}
+ ],
+ "fromTransaction": [
+ {
+ "exception": "coinbase inputs not supported",
+ "hex":"01000000010000000000000000000000000000000000000000000000000000000000000000000000006b483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+ },
+ {
+ "exception": "nonstandard inputs not supported",
+ "hex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000023aa206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000087ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+ }
]
}
}
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 974f68751..0bc10323d 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -256,6 +256,16 @@ describe('TransactionBuilder', function() {
})
})
+ fixtures.invalid.fromTransaction.forEach(function(f,i) {
+ it('throws on ' + f.exception, function() {
+ var tx = Transaction.fromHex(f.hex)
+
+ assert.throws(function() {
+ TransactionBuilder.fromTransaction(tx)
+ }, new RegExp(f.exception))
+ })
+ })
+
it('works for the P2SH multisig case', function() {
var privKeys = [
"91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
From 1764d45b423214bee08835bc3f0d1d9ee6229143 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 5 Sep 2014 15:45:39 +1000
Subject: [PATCH 084/291] README: added Quickcoin
---
README.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index dda294848..db9081908 100644
--- a/README.md
+++ b/README.md
@@ -84,6 +84,7 @@ console.log(key.pub.getAddress().toString())
// => 14bZ7YWde4KdRb5YN7GYkToz3EHVCvRxkF
```
+
### Creating a Transaction
```javascript
@@ -108,6 +109,7 @@ console.log(tx.toHex())
// You could now push the transaction onto the Bitcoin network manually (see https://blockchain.info/pushtx)
```
+
### Creating a P2SH Multsig Address
``` javascript
@@ -126,7 +128,6 @@ console.log("multisigP2SH:", multisigAddress)
```
-
## Projects utilizing BitcoinJS
- [Coinpunk](https://coinpunk.com)
@@ -139,7 +140,9 @@ console.log("multisigP2SH:", multisigAddress)
- [Dark Wallet](https://darkwallet.unsystem.net)
- [Dogechain Wallet](https://dogechain.info)
- [GreenAddress](https://greenaddress.it)
-- [DecentralBank](http://decentralbank.com)
+- [DecentralBank](http://decentralbank.co)
+- [Quickcoin](https://wallet.quickcoin.co)
+
## Contributors
@@ -149,6 +152,7 @@ Since then, many people have contributed. [Click here](https://github.com/bitcoi
Daniel Cousens, Wei Lu, JP Richardson and Kyle Drake lead the major refactor of the library from 0.1.3 to 1.0.0.
+
## Contributing
Join the ongoing IRC development channel at `#bitcoinjs-dev` on Freenode.
From dce269071ea3871c5a74c825a6ed09ffc9b7f47e Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 5 Sep 2014 15:48:01 +1000
Subject: [PATCH 085/291] README: add BIP38
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index db9081908..47b6d5a6e 100644
--- a/README.md
+++ b/README.md
@@ -169,9 +169,9 @@ Please make your best effort to adhere to these when contributing to save on tri
## Complementing Libraries
-- [bip39](https://github.com/weilu/bip39) - Wei Lu's Mnemonic code generator
+- [BIP39](https://github.com/weilu/bip39) - Mnemonic code for generating deterministic keys
+- [BIP38](https://github.com/cryptocoinjs/bip38) - Passphrase-protected private keys
- [BCoin](https://github.com/indutny/bcoin) - BIP37 / Bloom Filters / SPV client
-- [scryptsy](https://github.com/cryptocoinjs/scryptsy) - Private key encryption (BIP38)
- [insight](https://github.com/bitpay/insight) - A bitcoin blockchain API for web wallets.
From c41c3bb62ddb4d4d133651283dc8d91597c57282 Mon Sep 17 00:00:00 2001
From: BtcDrak
Date: Sat, 6 Sep 2014 17:57:07 +0100
Subject: [PATCH 086/291] Add viacoin support
---
src/networks.js | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/src/networks.js b/src/networks.js
index 60a321edb..aefc396c5 100644
--- a/src/networks.js
+++ b/src/networks.js
@@ -55,6 +55,34 @@ var networks = {
dustThreshold: 546,
feePerKb: 10000,
estimateFee: estimateFee('testnet')
+ },
+ viacoin: {
+ magicPrefix: '\x18Viacoin Signed Message:\n',
+ bip32: {
+ public: 0x0488b21e,
+ private: 0x0488ade4
+ },
+ pubKeyHash: 0x47,
+ scriptHash: 0x21,
+ wif: 0xc7,
+ dustThreshold: 560,
+ dustSoftThreshold: 100000,
+ feePerKb: 100000, //
+ estimateFee: estimateFee('viacoin')
+ },
+ viacointestnet: {
+ magicPrefix: '\x18Viacoin Signed Message:\n',
+ bip32: {
+ public: 0x043587cf,
+ private: 0x04358394
+ },
+ pubKeyHash: 0x7f,
+ scriptHash: 0xc4,
+ wif: 0xff,
+ dustThreshold: 560,
+ dustSoftThreshold: 100000,
+ feePerKb: 100000,
+ estimateFee: estimateFee('viacointestnet')
}
}
From 6c5a68207a01e04faf246b0e18e1113de9e52034 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 8 Sep 2014 18:42:47 +1000
Subject: [PATCH 087/291] Transaction: use isFinite instead over typeof number
---
src/transaction.js | 6 +++---
src/wallet.js | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index 80aaceede..39ab4885e 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -49,8 +49,8 @@ Transaction.prototype.addInput = function(tx, index, sequence) {
assert(Buffer.isBuffer(hash), 'Expected Transaction, txId or txHash, got ' + tx)
assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
- assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
- assert.equal(typeof sequence, 'number', 'Expected number sequence, got ' + sequence)
+ assert(Number.isFinite(index), 'Expected number index, got ' + index)
+ assert(Number.isFinite(sequence), 'Expected number sequence, got ' + sequence)
// Add the input and return the input's index
return (this.ins.push({
@@ -82,7 +82,7 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) {
}
assert(scriptPubKey instanceof Script, 'Expected Address or Script, got ' + scriptPubKey)
- assert.equal(typeof value, 'number', 'Expected number value, got ' + value)
+ assert(Number.isFinite(value), 'Expected number value, got ' + value)
// Add the output and return the output's index
return (this.outs.push({
diff --git a/src/wallet.js b/src/wallet.js
index f25f7d856..d131e017a 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -303,7 +303,7 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
assert.equal(typeof txId, 'string', 'Expected txId, got ' + txId)
assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId)
assert.doesNotThrow(function() { Address.fromBase58Check(unspent.address) }, 'Expected Base58 Address, got ' + unspent.address)
- assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
+ assert(Number.isFinite(index), 'Expected number index, got ' + index)
assert.equal(typeof unspent.value, 'number', 'Expected number value, got ' + unspent.value)
// FIXME: remove branch in 2.0.0
From 4e04a7e8835493de4cc24aad4d954c590ea1fd54 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 8 Sep 2014 23:15:31 +1000
Subject: [PATCH 088/291] Transaction: use isFinite over Number.isFinite
---
src/transaction.js | 6 +++---
src/wallet.js | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index 39ab4885e..29e1a43c2 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -49,8 +49,8 @@ Transaction.prototype.addInput = function(tx, index, sequence) {
assert(Buffer.isBuffer(hash), 'Expected Transaction, txId or txHash, got ' + tx)
assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
- assert(Number.isFinite(index), 'Expected number index, got ' + index)
- assert(Number.isFinite(sequence), 'Expected number sequence, got ' + sequence)
+ assert(isFinite(index), 'Expected number index, got ' + index)
+ assert(isFinite(sequence), 'Expected number sequence, got ' + sequence)
// Add the input and return the input's index
return (this.ins.push({
@@ -82,7 +82,7 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) {
}
assert(scriptPubKey instanceof Script, 'Expected Address or Script, got ' + scriptPubKey)
- assert(Number.isFinite(value), 'Expected number value, got ' + value)
+ assert(isFinite(value), 'Expected number value, got ' + value)
// Add the output and return the output's index
return (this.outs.push({
diff --git a/src/wallet.js b/src/wallet.js
index d131e017a..c61715f3a 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -303,7 +303,7 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
assert.equal(typeof txId, 'string', 'Expected txId, got ' + txId)
assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId)
assert.doesNotThrow(function() { Address.fromBase58Check(unspent.address) }, 'Expected Base58 Address, got ' + unspent.address)
- assert(Number.isFinite(index), 'Expected number index, got ' + index)
+ assert(isFinite(index), 'Expected number index, got ' + index)
assert.equal(typeof unspent.value, 'number', 'Expected number value, got ' + unspent.value)
// FIXME: remove branch in 2.0.0
From f028dfffa93164851340f4d4c99c056d7a33ff2a Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 8 Sep 2014 23:14:57 +1000
Subject: [PATCH 089/291] Wallet: fix missing variable utxo
---
src/wallet.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index c61715f3a..593912eed 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -297,7 +297,7 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
// FIXME: remove in 2.0.0
if (index === undefined) {
console.warn('unspent.outputIndex is deprecated, use unspent.index instead')
- index = utxo.outputIndex
+ index = unspent.outputIndex
}
assert.equal(typeof txId, 'string', 'Expected txId, got ' + txId)
@@ -313,7 +313,7 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
var txHash = bufferutils.reverse(new Buffer(txId, 'hex'))
- var unspent = {
+ unspent = {
address: unspent.address,
confirmations: unspent.confirmations || 0,
index: index,
From 69dfd3204d696f9764fa5a81ff4df18132be6553 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 8 Sep 2014 23:21:16 +1000
Subject: [PATCH 090/291] Wallet: add missing variable wallet
---
test/wallet.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/wallet.js b/test/wallet.js
index 4e49ca825..6ae9ea97f 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -273,6 +273,7 @@ describe('Wallet', function() {
describe('setUnspentOutputs', function() {
var utxo
var expectedOutputKey
+ var wallet
beforeEach(function() {
utxo = {
From c3f88693864f9fa67d00e8f9c4120763161404d6 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 8 Sep 2014 23:27:01 +1000
Subject: [PATCH 091/291] tests: Wallet test was not comprehensive
---
test/wallet.js | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/test/wallet.js b/test/wallet.js
index 6ae9ea97f..dd235879c 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -633,9 +633,11 @@ describe('Wallet', function() {
})
it('skips change if it is not above dust threshold', function() {
- var fee = 14570
- var tx = wallet.createTx(to, value)
- assert.equal(tx.outs.length, 1)
+ var tx1 = wallet.createTx(to, value - 546)
+ assert.equal(tx1.outs.length, 1)
+
+ var tx2 = wallet.createTx(to, value - 547)
+ assert.equal(tx2.outs.length, 2)
})
})
})
From 0a232cdb9ddd6116839e330987c6d2853fbfce18 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 15 Sep 2014 14:25:02 +1000
Subject: [PATCH 092/291] tests: sign test needs to trigger ecurve.Point side
effects
---
test/wallet.js | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/test/wallet.js b/test/wallet.js
index dd235879c..ccb5f2269 100644
--- a/test/wallet.js
+++ b/test/wallet.js
@@ -651,10 +651,16 @@ describe('Wallet', function() {
var fee = 30000
sinon.spy(TransactionBuilder.prototype, "sign")
- var tx = wallet.createTx(to, value, { fixedFee: fee })
+ wallet.createTx(to, value, { fixedFee: fee })
+
+ var priv1 = wallet.getPrivateKeyForAddress(address1)
+ var priv2 = wallet.getPrivateKeyForAddress(address2)
+
+ // FIXME: boo (required) side effects
+ priv1.pub.Q.affineX, priv2.pub.Q.affineX
- assert(TransactionBuilder.prototype.sign.calledWith(0, wallet.getPrivateKeyForAddress(address2)))
- assert(TransactionBuilder.prototype.sign.calledWith(1, wallet.getPrivateKeyForAddress(address1)))
+ assert(TransactionBuilder.prototype.sign.calledWith(0, priv2))
+ assert(TransactionBuilder.prototype.sign.calledWith(1, priv1))
})
})
From 3b60d7abf33422f3392527592e7dfd21831d9165 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 15 Sep 2014 18:49:13 +1000
Subject: [PATCH 093/291] README: s/Bitcoin/bitcoin for namespacing
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 47b6d5a6e..48b3a2301 100644
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@ From the repository: Compile `bitcoinjs-min.js` with the following command:
From NPM:
$ npm -g install bitcoinjs-lib browserify uglify-js
- $ browserify -r bitcoinjs-lib -s Bitcoin | uglifyjs > bitcoinjs.min.js
+ $ browserify -r bitcoinjs-lib -s bitcoin | uglifyjs > bitcoinjs.min.js
After loading this file in your browser, you will be able to use the global `bitcoin` object.
From e3d05c6f2cf825b7d8313c5925e71380ead31939 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 20 Sep 2014 10:47:23 +1000
Subject: [PATCH 094/291] 1.1.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index e0c459cd1..3b5cf187b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.0.2",
+ "version": "1.1.0",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From c96b8625302e0e35bf9f155436fb233a89af6396 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 6 Sep 2014 01:05:50 +1000
Subject: [PATCH 095/291] crypto: remove cryptojs
---
package.json | 1 -
src/convert.js | 32 --------------------------------
src/crypto.js | 16 ++--------------
src/index.js | 1 -
test/convert.js | 27 ---------------------------
test/fixtures/convert.json | 25 -------------------------
6 files changed, 2 insertions(+), 100 deletions(-)
delete mode 100644 src/convert.js
delete mode 100644 test/convert.js
delete mode 100644 test/fixtures/convert.json
diff --git a/package.json b/package.json
index 3b5cf187b..7d766ac4b 100644
--- a/package.json
+++ b/package.json
@@ -75,7 +75,6 @@
"bigi": "1.1.0",
"bs58": "1.2.1",
"bs58check": "1.0.1",
- "crypto-js": "3.1.2-3",
"crypto-browserify": "3.0.0",
"ecurve": "1.0.0"
}
diff --git a/src/convert.js b/src/convert.js
deleted file mode 100644
index 85488660e..000000000
--- a/src/convert.js
+++ /dev/null
@@ -1,32 +0,0 @@
-var assert = require('assert')
-var Crypto = require('crypto-js')
-var WordArray = Crypto.lib.WordArray
-
-function bufferToWordArray(buffer) {
- assert(Buffer.isBuffer(buffer), 'Expected Buffer, got', buffer)
-
- var words = []
- for (var i = 0, b = 0; i < buffer.length; i++, b += 8) {
- words[b >>> 5] |= buffer[i] << (24 - b % 32)
- }
-
- return new WordArray.init(words, buffer.length)
-}
-
-function wordArrayToBuffer(wordArray) {
- assert(Array.isArray(wordArray.words), 'Expected WordArray, got' + wordArray)
-
- var words = wordArray.words
- var buffer = new Buffer(words.length * 4)
-
- words.forEach(function(value, i) {
- buffer.writeInt32BE(value & -1, i * 4)
- })
-
- return buffer
-}
-
-module.exports = {
- bufferToWordArray: bufferToWordArray,
- wordArrayToBuffer: wordArrayToBuffer
-}
diff --git a/src/crypto.js b/src/crypto.js
index 1c8423b3b..890bf0a6b 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -1,8 +1,4 @@
-// Crypto, crypto, where art thou crypto
-var assert = require('assert')
-var CryptoJS = require('crypto-js')
var crypto = require('crypto')
-var convert = require('./convert')
function hash160(buffer) {
return ripemd160(sha256(buffer))
@@ -29,16 +25,8 @@ function HmacSHA256(buffer, secret) {
return crypto.createHmac('sha256', secret).update(buffer).digest()
}
-function HmacSHA512(data, secret) {
- assert(Buffer.isBuffer(data), 'Expected Buffer for data, got ' + data)
- assert(Buffer.isBuffer(secret), 'Expected Buffer for secret, got ' + secret)
-
- var dataWords = convert.bufferToWordArray(data)
- var secretWords = convert.bufferToWordArray(secret)
-
- var hash = CryptoJS.HmacSHA512(dataWords, secretWords)
-
- return convert.wordArrayToBuffer(hash)
+function HmacSHA512(buffer, secret) {
+ return crypto.createHmac('sha512', secret).update(buffer).digest()
}
module.exports = {
diff --git a/src/index.js b/src/index.js
index 73f3c1ede..0ab57e2cf 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,7 +1,6 @@
module.exports = {
Address: require('./address'),
bufferutils: require('./bufferutils'),
- convert: require('./convert'),
crypto: require('./crypto'),
ecdsa: require('./ecdsa'),
ECKey: require('./eckey'),
diff --git a/test/convert.js b/test/convert.js
deleted file mode 100644
index 0b06e4429..000000000
--- a/test/convert.js
+++ /dev/null
@@ -1,27 +0,0 @@
-var assert = require('assert')
-var convert = require('../src/convert')
-
-var fixtures = require('./fixtures/convert')
-
-describe('convert', function() {
- describe('bufferToWordArray', function() {
- fixtures.valid.forEach(function(f) {
- it('converts ' + f.hex + ' correctly', function() {
- var buffer = new Buffer(f.hex, 'hex')
- var result = convert.bufferToWordArray(buffer)
-
- assert.deepEqual(result, f.wordArray)
- })
- })
- })
-
- describe('wordArrayToBuffer', function() {
- fixtures.valid.forEach(function(f) {
- it('converts to ' + f.hex + ' correctly', function() {
- var resultHex = convert.wordArrayToBuffer(f.wordArray).toString('hex')
-
- assert.deepEqual(resultHex, f.hex)
- })
- })
- })
-})
diff --git a/test/fixtures/convert.json b/test/fixtures/convert.json
deleted file mode 100644
index b75900418..000000000
--- a/test/fixtures/convert.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "valid": [
- {
- "hex": "0000000000000000000000000000000000000000",
- "wordArray": {
- "words": [0, 0, 0, 0, 0],
- "sigBytes": 20
- }
- },
- {
- "hex": "62e907b15cbf27d5425399ebf6f0fb50ebb88f18",
- "wordArray": {
- "words": [1659439025, 1556031445, 1112775147, -151979184, -340226280],
- "sigBytes": 20
- }
- },
- {
- "hex": "ffffffffffffffffffffffffffffffffffffffff",
- "wordArray": {
- "words": [-1, -1, -1, -1, -1],
- "sigBytes": 20
- }
- }
- ]
-}
From e82da0ca8533255e9ff75c3cffe22a9d66b6321d Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 16 Sep 2014 11:53:11 +1000
Subject: [PATCH 096/291] package: browserify now uses crypto-browserify 3.0.0
---
package.json | 4 ----
1 file changed, 4 deletions(-)
diff --git a/package.json b/package.json
index 7d766ac4b..69ecc167e 100644
--- a/package.json
+++ b/package.json
@@ -68,14 +68,10 @@
"test": "npm run-script unit",
"unit": "istanbul test mocha -- --reporter list test/*.js"
},
- "browser": {
- "crypto": "crypto-browserify"
- },
"dependencies": {
"bigi": "1.1.0",
"bs58": "1.2.1",
"bs58check": "1.0.1",
- "crypto-browserify": "3.0.0",
"ecurve": "1.0.0"
}
}
From a58088795f6542129e22d439083152192d28516c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 15 Sep 2014 16:04:12 +1000
Subject: [PATCH 097/291] HDNode: indicate 2.x.y removal of Buffer interop
---
src/hdnode.js | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/src/hdnode.js b/src/hdnode.js
index 3a7f86079..e14ad4473 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -72,10 +72,15 @@ HDNode.fromSeedHex = function(hex, network) {
}
HDNode.fromBase58 = function(string) {
- return HDNode.fromBuffer(base58check.decode(string))
+ return HDNode.fromBuffer(base58check.decode(string), true)
}
-HDNode.fromBuffer = function(buffer) {
+// FIXME: remove in 2.x.y
+HDNode.fromBuffer = function(buffer, __ignoreDeprecation) {
+ if (!__ignoreDeprecation) {
+ console.warn('HDNode.fromBuffer() is deprecated for removal in 2.x.y, use fromBase58 instead')
+ }
+
assert.strictEqual(buffer.length, HDNode.LENGTH, 'Invalid buffer length')
// 4 byte: version bytes
@@ -127,6 +132,7 @@ HDNode.fromBuffer = function(buffer) {
return hd
}
+// FIXME: remove in 2.x.y
HDNode.fromHex = function(hex) {
return HDNode.fromBuffer(new Buffer(hex, 'hex'))
}
@@ -153,10 +159,11 @@ HDNode.prototype.neutered = function() {
}
HDNode.prototype.toBase58 = function(isPrivate) {
- return base58check.encode(this.toBuffer(isPrivate))
+ return base58check.encode(this.toBuffer(isPrivate, true))
}
-HDNode.prototype.toBuffer = function(isPrivate) {
+// FIXME: remove in 2.x.y
+HDNode.prototype.toBuffer = function(isPrivate, __ignoreDeprecation) {
if (isPrivate == undefined) {
isPrivate = !!this.privKey
@@ -165,6 +172,10 @@ HDNode.prototype.toBuffer = function(isPrivate) {
console.warn('isPrivate flag is deprecated, please use the .neutered() method instead')
}
+ if (!__ignoreDeprecation) {
+ console.warn('HDNode.toBuffer() is deprecated for removal in 2.x.y, use toBase58 instead')
+ }
+
// Version
var version = isPrivate ? this.network.bip32.private : this.network.bip32.public
var buffer = new Buffer(HDNode.LENGTH)
@@ -204,6 +215,7 @@ HDNode.prototype.toBuffer = function(isPrivate) {
return buffer
}
+// FIXME: remove in 2.x.y
HDNode.prototype.toHex = function(isPrivate) {
return this.toBuffer(isPrivate).toString('hex')
}
From 1dad7b617ba01839c8d6d392ebf8f51fce1ae8ce Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 22 Sep 2014 18:18:46 +1000
Subject: [PATCH 098/291] package: crypto-browserify must be specified until
browserify catches up
---
package.json | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/package.json b/package.json
index 69ecc167e..69dbb4b19 100644
--- a/package.json
+++ b/package.json
@@ -68,10 +68,14 @@
"test": "npm run-script unit",
"unit": "istanbul test mocha -- --reporter list test/*.js"
},
+ "browser": {
+ "crypto": "crypto-browserify"
+ },
"dependencies": {
"bigi": "1.1.0",
"bs58": "1.2.1",
"bs58check": "1.0.1",
+ "crypto-browserify": "3.2.0",
"ecurve": "1.0.0"
}
}
From 18c3a4a8567b15d2faa0deb1c13e26bb119cd554 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 22 Sep 2014 19:10:15 +1000
Subject: [PATCH 099/291] 1.1.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 69dbb4b19..96a3faed1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.0",
+ "version": "1.1.1",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From faea16cadc5bad2f287b309ec89f8665434d3b47 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 25 Sep 2014 12:30:38 +1000
Subject: [PATCH 100/291] package: use latest crypto-browserify
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 96a3faed1..bbffc04d3 100644
--- a/package.json
+++ b/package.json
@@ -75,7 +75,7 @@
"bigi": "1.1.0",
"bs58": "1.2.1",
"bs58check": "1.0.1",
- "crypto-browserify": "3.2.0",
+ "crypto-browserify": "3.2.4",
"ecurve": "1.0.0"
}
}
From 012f95840f1aaba43f687fc0bc3caea1149ab680 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 25 Sep 2014 12:46:21 +1000
Subject: [PATCH 101/291] package: update dev-dependencies, bigi
---
package.json | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/package.json b/package.json
index bbffc04d3..08dae3b9c 100644
--- a/package.json
+++ b/package.json
@@ -36,15 +36,15 @@
"url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
},
"devDependencies": {
- "browserify": "^4.2.1",
- "coveralls": "~2.10.0",
- "helloblock-js": "^0.2.1",
- "istanbul": "0.1.30",
- "jshint": "2.5.1",
- "mocha": "1.18.2",
+ "browserify": "^5.12.0",
+ "coveralls": "^2.11.2",
+ "helloblock-js": "^0.2.5",
+ "istanbul": "^0.3.2",
+ "jshint": "^2.5.6",
+ "mocha": "^1.21.4",
"mocha-lcov-reporter": "0.0.1",
- "sinon": "1.9.0",
- "uglify-js": "2.4.13"
+ "sinon": "^1.10.3",
+ "uglify-js": "^2.4.15"
},
"testling": {
"browsers": [
@@ -72,7 +72,7 @@
"crypto": "crypto-browserify"
},
"dependencies": {
- "bigi": "1.1.0",
+ "bigi": "^1.1.0",
"bs58": "1.2.1",
"bs58check": "1.0.1",
"crypto-browserify": "3.2.4",
From 0631db517c33707a5707b02a077f55d834ebfa1c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 25 Sep 2014 12:46:34 +1000
Subject: [PATCH 102/291] 1.1.2
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 08dae3b9c..767610cde 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.1",
+ "version": "1.1.2",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From de1755307ae3baecac275de67752e7be50bc3df8 Mon Sep 17 00:00:00 2001
From: wmcbain
Date: Thu, 25 Sep 2014 07:45:54 -0400
Subject: [PATCH 103/291] Added Zetacoin support
Added support for zetacoin
---
src/networks.js | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/src/networks.js b/src/networks.js
index aefc396c5..4d4948533 100644
--- a/src/networks.js
+++ b/src/networks.js
@@ -83,6 +83,19 @@ var networks = {
dustSoftThreshold: 100000,
feePerKb: 100000,
estimateFee: estimateFee('viacointestnet')
+ },
+ zetacoin: {
+ magicPrefix: '\x18Zetacoin Signed Message:\n',
+ bip32: {
+ public: 0x0488b21e,
+ private: 0x0488ade4
+ },
+ pubKeyHash: 0x50,
+ scriptHash: 0x09,
+ wif: 0xe0,
+ dustThreshold: 546, // https://github.com/zetacoin/zetacoin/blob/master/src/core.h#L159
+ feePerKb: 10000, // https://github.com/zetacoin/zetacoin/blob/master/src/main.cpp#L54
+ estimateFee: estimateFee('zetacoin')
}
}
From ed01ed5bb4dbf4ffaee4edd2a77029db47fb9fb3 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 3 Oct 2014 19:11:38 +1000
Subject: [PATCH 104/291] remove unused bs58 core dependency
---
package.json | 2 +-
test/bitcoin.core.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 767610cde..b5fe50305 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
},
"devDependencies": {
"browserify": "^5.12.0",
+ "bs58": "^2.0.0",
"coveralls": "^2.11.2",
"helloblock-js": "^0.2.5",
"istanbul": "^0.3.2",
@@ -73,7 +74,6 @@
},
"dependencies": {
"bigi": "^1.1.0",
- "bs58": "1.2.1",
"bs58check": "1.0.1",
"crypto-browserify": "3.2.4",
"ecurve": "1.0.0"
diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js
index 5cf004b2c..3560c8155 100644
--- a/test/bitcoin.core.js
+++ b/test/bitcoin.core.js
@@ -27,7 +27,7 @@ describe('Bitcoin-core', function() {
it('can decode ' + fb58, function() {
var buffer = base58.decode(fb58)
- var actual = buffer.toString('hex')
+ var actual = new Buffer(buffer).toString('hex')
assert.equal(actual, fhex)
})
From 756e38bc58f72460d55d4cfe9cb96197dda201c7 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 3 Oct 2014 19:12:46 +1000
Subject: [PATCH 105/291] package: upgrade bs58check to 1.0.3
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index b5fe50305..dee67ac65 100644
--- a/package.json
+++ b/package.json
@@ -74,7 +74,7 @@
},
"dependencies": {
"bigi": "^1.1.0",
- "bs58check": "1.0.1",
+ "bs58check": "1.0.3",
"crypto-browserify": "3.2.4",
"ecurve": "1.0.0"
}
From 166053a3e5120cccc3ed3feefa9a1735b6abebf5 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 3 Oct 2014 19:12:56 +1000
Subject: [PATCH 106/291] 1.1.3
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index dee67ac65..194dc7ee7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.2",
+ "version": "1.1.3",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 35542e115df07eefd9f0cb6fb7d181fa7946116a Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 15 Sep 2014 14:21:01 +1000
Subject: [PATCH 107/291] types: enforce consistent type checking
---
src/address.js | 4 +++-
src/ecdsa.js | 7 +++++--
src/eckey.js | 4 +++-
src/ecpubkey.js | 8 ++++----
src/ecsignature.js | 7 +++++--
src/hdnode.js | 7 +++++--
src/script.js | 7 ++++---
src/scripts.js | 16 +++++++++-------
src/transaction.js | 45 +++++++++++++++++++++++----------------------
src/types.js | 38 ++++++++++++++++++++++++++++++++++++++
10 files changed, 99 insertions(+), 44 deletions(-)
create mode 100644 src/types.js
diff --git a/src/address.js b/src/address.js
index fde2b2842..124c0ef7b 100644
--- a/src/address.js
+++ b/src/address.js
@@ -1,5 +1,6 @@
var assert = require('assert')
var base58check = require('bs58check')
+var enforceType = require('./types')
var networks = require('./networks')
var scripts = require('./scripts')
@@ -13,7 +14,8 @@ function findScriptTypeByVersion(version) {
}
function Address(hash, version) {
- assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)
+ enforceType('Buffer', hash)
+
assert.strictEqual(hash.length, 20, 'Invalid hash length')
assert.strictEqual(version & 0xff, version, 'Invalid version byte')
diff --git a/src/ecdsa.js b/src/ecdsa.js
index dabcd0566..7b9db0b3b 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -1,14 +1,17 @@
var assert = require('assert')
var crypto = require('./crypto')
+var enforceType = require('./types')
var BigInteger = require('bigi')
var ECSignature = require('./ecsignature')
// https://tools.ietf.org/html/rfc6979#section-3.2
function deterministicGenerateK(curve, hash, d) {
- assert(Buffer.isBuffer(hash), 'Hash must be a Buffer, not ' + hash)
+ enforceType('Buffer', hash)
+ enforceType(BigInteger, d)
+
+ // sanity check
assert.equal(hash.length, 32, 'Hash must be 256 bit')
- assert(d instanceof BigInteger, 'Private key must be a BigInteger')
var x = d.toBuffer(32)
var k = new Buffer(32)
diff --git a/src/eckey.js b/src/eckey.js
index a3073ec33..23cd43d03 100644
--- a/src/eckey.js
+++ b/src/eckey.js
@@ -2,6 +2,7 @@ var assert = require('assert')
var base58check = require('bs58check')
var crypto = require('crypto')
var ecdsa = require('./ecdsa')
+var enforceType = require('./types')
var networks = require('./networks')
var BigInteger = require('bigi')
@@ -46,7 +47,8 @@ ECKey.makeRandom = function(compressed, rng) {
rng = rng || crypto.randomBytes
var buffer = rng(32)
- assert(Buffer.isBuffer(buffer), 'Expected Buffer, got ' + buffer)
+ enforceType('Buffer', buffer)
+ assert.equal(buffer.length, 32, 'Expected 256-bit Buffer from RNG')
var d = BigInteger.fromBuffer(buffer)
d = d.mod(curve.n)
diff --git a/src/ecpubkey.js b/src/ecpubkey.js
index 37167297d..840fa5069 100644
--- a/src/ecpubkey.js
+++ b/src/ecpubkey.js
@@ -1,6 +1,6 @@
-var assert = require('assert')
var crypto = require('./crypto')
var ecdsa = require('./ecdsa')
+var enforceType = require('./types')
var networks = require('./networks')
var Address = require('./address')
@@ -9,10 +9,10 @@ var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')
function ECPubKey(Q, compressed) {
- assert(Q instanceof ecurve.Point, 'Expected Point, got ' + Q)
+ if (compressed === undefined) compressed = true
- if (compressed == undefined) compressed = true
- assert.strictEqual(typeof compressed, 'boolean', 'Expected boolean, got ' + compressed)
+ enforceType(ecurve.Point, Q)
+ enforceType('Boolean', compressed)
this.compressed = compressed
this.Q = Q
diff --git a/src/ecsignature.js b/src/ecsignature.js
index bcd59d53f..7b71c6183 100644
--- a/src/ecsignature.js
+++ b/src/ecsignature.js
@@ -1,9 +1,12 @@
var assert = require('assert')
+var enforceType = require('./types')
+
var BigInteger = require('bigi')
function ECSignature(r, s) {
- assert(r instanceof BigInteger, 'Expected BigInteger, got ' + r)
- assert(s instanceof BigInteger, 'Expected BigInteger, got ' + s)
+ enforceType(BigInteger, r)
+ enforceType(BigInteger, s)
+
this.r = r
this.s = s
}
diff --git a/src/hdnode.js b/src/hdnode.js
index e14ad4473..018b913e4 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -1,6 +1,7 @@
var assert = require('assert')
var base58check = require('bs58check')
var crypto = require('./crypto')
+var enforceType = require('./types')
var networks = require('./networks')
var BigInteger = require('bigi')
@@ -30,7 +31,8 @@ function findBIP32ParamsByVersion(version) {
function HDNode(K, chainCode, network) {
network = network || networks.bitcoin
- assert(Buffer.isBuffer(chainCode), 'Expected Buffer, got ' + chainCode)
+ enforceType('Buffer', chainCode)
+
assert.equal(chainCode.length, 32, 'Expected chainCode length of 32, got ' + chainCode.length)
assert(network.bip32, 'Unknown BIP32 constants for network')
@@ -52,7 +54,8 @@ HDNode.HIGHEST_BIT = 0x80000000
HDNode.LENGTH = 78
HDNode.fromSeedBuffer = function(seed, network) {
- assert(Buffer.isBuffer(seed), 'Expected Buffer, got ' + seed)
+ enforceType('Buffer', seed)
+
assert(seed.length >= 16, 'Seed should be at least 128 bits')
assert(seed.length <= 64, 'Seed should be at most 512 bits')
diff --git a/src/script.js b/src/script.js
index 15565982b..d3afc7061 100644
--- a/src/script.js
+++ b/src/script.js
@@ -1,11 +1,12 @@
var assert = require('assert')
var bufferutils = require('./bufferutils')
var crypto = require('./crypto')
+var enforceType = require('./types')
var opcodes = require('./opcodes')
function Script(buffer, chunks) {
- assert(Buffer.isBuffer(buffer), 'Expected Buffer, got ' + buffer)
- assert(Array.isArray(chunks), 'Expected Array, got ' + chunks)
+ enforceType('Buffer', buffer)
+ enforceType('Array', chunks)
this.buffer = buffer
this.chunks = chunks
@@ -55,7 +56,7 @@ Script.fromBuffer = function(buffer) {
}
Script.fromChunks = function(chunks) {
- assert(Array.isArray(chunks), 'Expected Array, got ' + chunks)
+ enforceType('Array', chunks)
var bufferSize = chunks.reduce(function(accum, chunk) {
if (Buffer.isBuffer(chunk)) {
diff --git a/src/scripts.js b/src/scripts.js
index 88e3e616c..911fd1c33 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -1,4 +1,5 @@
var assert = require('assert')
+var enforceType = require('./types')
var opcodes = require('./opcodes')
// FIXME: use ECPubKey, currently the circular dependency breaks everything.
@@ -18,7 +19,7 @@ var ECSignature = require('./ecsignature')
var Script = require('./script')
function classifyOutput(script) {
- assert(script instanceof Script, 'Expected Script, got ', script)
+ enforceType(Script, script)
if (isPubKeyHashOutput.call(script)) {
return 'pubkeyhash'
@@ -36,7 +37,7 @@ function classifyOutput(script) {
}
function classifyInput(script) {
- assert(script instanceof Script, 'Expected Script, got ', script)
+ enforceType(Script, script)
if (isPubKeyHashInput.call(script)) {
return 'pubkeyhash'
@@ -171,7 +172,7 @@ function pubKeyOutput(pubKey) {
// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput(hash) {
- assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)
+ enforceType('Buffer', hash)
return Script.fromChunks([
opcodes.OP_DUP,
@@ -184,7 +185,7 @@ function pubKeyHashOutput(hash) {
// OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput(hash) {
- assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)
+ enforceType('Buffer', hash)
return Script.fromChunks([
opcodes.OP_HASH160,
@@ -195,7 +196,8 @@ function scriptHashOutput(hash) {
// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput(m, pubKeys) {
- assert(Array.isArray(pubKeys), 'Expected Array, got ' + pubKeys)
+ enforceType('Array', pubKeys)
+
assert(pubKeys.length >= m, 'Not enough pubKeys provided')
var pubKeyBuffers = pubKeys.map(function(pubKey) {
@@ -213,14 +215,14 @@ function multisigOutput(m, pubKeys) {
// {signature}
function pubKeyInput(signature) {
- assert(Buffer.isBuffer(signature), 'Expected Buffer, got ' + signature)
+ enforceType('Buffer', signature)
return Script.fromChunks([signature])
}
// {signature} {pubKey}
function pubKeyHashInput(signature, pubKey) {
- assert(Buffer.isBuffer(signature), 'Expected Buffer, got ' + signature)
+ enforceType('Buffer', signature)
return Script.fromChunks([signature, pubKey.toBuffer()])
}
diff --git a/src/transaction.js b/src/transaction.js
index 29e1a43c2..72ab8428e 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -1,6 +1,7 @@
var assert = require('assert')
var bufferutils = require('./bufferutils')
var crypto = require('./crypto')
+var enforceType = require('./types')
var opcodes = require('./opcodes')
var scripts = require('./scripts')
@@ -8,12 +9,6 @@ var Address = require('./address')
var ECSignature = require('./ecsignature')
var Script = require('./script')
-Transaction.DEFAULT_SEQUENCE = 0xffffffff
-Transaction.SIGHASH_ALL = 0x01
-Transaction.SIGHASH_NONE = 0x02
-Transaction.SIGHASH_SINGLE = 0x03
-Transaction.SIGHASH_ANYONECANPAY = 0x80
-
function Transaction() {
this.version = 1
this.locktime = 0
@@ -21,6 +16,12 @@ function Transaction() {
this.outs = []
}
+Transaction.DEFAULT_SEQUENCE = 0xffffffff
+Transaction.SIGHASH_ALL = 0x01
+Transaction.SIGHASH_NONE = 0x02
+Transaction.SIGHASH_SINGLE = 0x03
+Transaction.SIGHASH_ANYONECANPAY = 0x80
+
/**
* Create a new txin.
*
@@ -31,26 +32,23 @@ function Transaction() {
*
* Note that this method does not sign the created input.
*/
-Transaction.prototype.addInput = function(tx, index, sequence) {
- if (sequence == undefined) sequence = Transaction.DEFAULT_SEQUENCE
+Transaction.prototype.addInput = function(hash, index, sequence) {
+ if (sequence === undefined) sequence = Transaction.DEFAULT_SEQUENCE
- var hash
-
- if (typeof tx === 'string') {
+ if (typeof hash === 'string') {
// TxId hex is big-endian, we need little-endian
- hash = bufferutils.reverse(new Buffer(tx, 'hex'))
+ hash = bufferutils.reverse(new Buffer(hash, 'hex'))
- } else if (tx instanceof Transaction) {
- hash = tx.getHash()
+ } else if (hash instanceof Transaction) {
+ hash = hash.getHash()
- } else {
- hash = tx
}
- assert(Buffer.isBuffer(hash), 'Expected Transaction, txId or txHash, got ' + tx)
+ enforceType('Buffer', hash)
+ enforceType('Number', index)
+ enforceType('Number', sequence)
+
assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
- assert(isFinite(index), 'Expected number index, got ' + index)
- assert(isFinite(sequence), 'Expected number sequence, got ' + sequence)
// Add the input and return the input's index
return (this.ins.push({
@@ -81,8 +79,8 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) {
scriptPubKey = scriptPubKey.toOutputScript()
}
- assert(scriptPubKey instanceof Script, 'Expected Address or Script, got ' + scriptPubKey)
- assert(isFinite(value), 'Expected number value, got ' + value)
+ enforceType(Script, scriptPubKey)
+ enforceType('Number', value)
// Add the output and return the output's index
return (this.outs.push({
@@ -172,9 +170,12 @@ Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashTy
prevOutScript = tmp
}
+ enforceType('Number', inIndex)
+ enforceType(Script, prevOutScript)
+ enforceType('Number', hashType)
+
assert(inIndex >= 0, 'Invalid vin index')
assert(inIndex < this.ins.length, 'Invalid vin index')
- assert(prevOutScript instanceof Script, 'Invalid Script object')
var txTmp = this.clone()
var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR)
diff --git a/src/types.js b/src/types.js
new file mode 100644
index 000000000..dfcde9fcb
--- /dev/null
+++ b/src/types.js
@@ -0,0 +1,38 @@
+module.exports = function enforce(type, value) {
+ switch (type) {
+ // http://jsperf.com/array-typecheck-2
+ case 'Array': {
+ if (value != null && value.constructor === Array) return
+ break
+ }
+
+ // http://jsperf.com/boolean-typecheck
+ case 'Boolean': {
+ if (typeof value === 'boolean') return
+ break
+ }
+
+ case 'Buffer': {
+ if (Buffer.isBuffer(value)) return
+ break
+ }
+
+ // http://jsperf.com/number-constructor-v-isnan
+ case 'Number': {
+ if (typeof value === 'number') return
+ break
+ }
+
+ // http://jsperf.com/string-typecheck-2
+ case 'String': {
+ if (value != null && value.constructor === String) return
+ break
+ }
+
+ default: {
+ if (value instanceof type) return
+ }
+ }
+
+ throw new TypeError('Expected ' + (type.name || type) + ', got ' + value)
+}
From deaf06b3505c0f513ddb5612de72dfa956a287e3 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 5 Oct 2014 15:43:14 +1100
Subject: [PATCH 108/291] Wallet: use enforceType where applicable
---
src/wallet.js | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/wallet.js b/src/wallet.js
index 593912eed..799bc8118 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -1,6 +1,7 @@
var assert = require('assert')
var bufferutils = require('./bufferutils')
var crypto = require('crypto')
+var enforceType = require('./types')
var networks = require('./networks')
var Address = require('./address')
@@ -300,15 +301,17 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
index = unspent.outputIndex
}
- assert.equal(typeof txId, 'string', 'Expected txId, got ' + txId)
+ enforceType('String', txId)
+ enforceType('Number', index)
+ enforceType('Number', unspent.value)
+
assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId)
assert.doesNotThrow(function() { Address.fromBase58Check(unspent.address) }, 'Expected Base58 Address, got ' + unspent.address)
- assert(isFinite(index), 'Expected number index, got ' + index)
- assert.equal(typeof unspent.value, 'number', 'Expected number value, got ' + unspent.value)
+ assert(isFinite(index), 'Expected finite index, got ' + index)
// FIXME: remove branch in 2.0.0
if (unspent.confirmations !== undefined) {
- assert.equal(typeof unspent.confirmations, 'number', 'Expected number confirmations, got ' + unspent.confirmations)
+ enforceType('Number', unspent.confirmations)
}
var txHash = bufferutils.reverse(new Buffer(txId, 'hex'))
From 0c380a063ab44f161d73a0ab6a9a7e4caaad8bbb Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 7 Oct 2014 16:49:20 +1100
Subject: [PATCH 109/291] tests: add tests for types
---
test/types.js | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 test/types.js
diff --git a/test/types.js b/test/types.js
new file mode 100644
index 000000000..4b6c12344
--- /dev/null
+++ b/test/types.js
@@ -0,0 +1,28 @@
+var assert = require('assert')
+var enforceType = require('../src/types')
+
+function CustomType() {}
+
+var types = ['Array', 'Boolean', 'Buffer', 'Number', 'String', CustomType]
+var values = [[], true, new Buffer(1), 1234, 'foobar', new CustomType()]
+
+describe('enforceType', function() {
+ types.forEach(function(type, i) {
+ describe(type, function() {
+ values.forEach(function(value, j) {
+ if (j === i) {
+ it('passes for ' + types[j], function() {
+ enforceType(type, value)
+ })
+
+ } else {
+ it('fails for ' + types[j], function() {
+ assert.throws(function() {
+ enforceType(type, value)
+ }, new RegExp('Expected ' + (type.name || type) + ', got '))
+ })
+ }
+ })
+ })
+ })
+})
From 01a96e887c9bb0de172d23135d2cf3644ab9e9fb Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 7 Oct 2014 16:50:37 +1100
Subject: [PATCH 110/291] types: use the idiomatic equivalents
---
src/types.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/types.js b/src/types.js
index dfcde9fcb..257156be1 100644
--- a/src/types.js
+++ b/src/types.js
@@ -2,7 +2,7 @@ module.exports = function enforce(type, value) {
switch (type) {
// http://jsperf.com/array-typecheck-2
case 'Array': {
- if (value != null && value.constructor === Array) return
+ if (Array.isArray(value)) return
break
}
@@ -25,7 +25,7 @@ module.exports = function enforce(type, value) {
// http://jsperf.com/string-typecheck-2
case 'String': {
- if (value != null && value.constructor === String) return
+ if (typeof value === 'string') return
break
}
From 967e724b479b37db1b9656d18b300344628c3cbe Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 7 Oct 2014 16:57:49 +1100
Subject: [PATCH 111/291] types: remove JSPerf references
---
src/types.js | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/types.js b/src/types.js
index 257156be1..ddbf13dde 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,12 +1,10 @@
module.exports = function enforce(type, value) {
switch (type) {
- // http://jsperf.com/array-typecheck-2
case 'Array': {
if (Array.isArray(value)) return
break
}
- // http://jsperf.com/boolean-typecheck
case 'Boolean': {
if (typeof value === 'boolean') return
break
@@ -17,13 +15,11 @@ module.exports = function enforce(type, value) {
break
}
- // http://jsperf.com/number-constructor-v-isnan
case 'Number': {
if (typeof value === 'number') return
break
}
- // http://jsperf.com/string-typecheck-2
case 'String': {
if (typeof value === 'string') return
break
From eb4e8884d94b7d01947e62ef5ea833f4dfb1a3f5 Mon Sep 17 00:00:00 2001
From: Wei Lu
Date: Tue, 7 Oct 2014 00:08:18 -0700
Subject: [PATCH 112/291] loose instanceof: check constructor function name
instead
---
src/types.js | 2 +-
test/types.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/types.js b/src/types.js
index ddbf13dde..501934f0a 100644
--- a/src/types.js
+++ b/src/types.js
@@ -26,7 +26,7 @@ module.exports = function enforce(type, value) {
}
default: {
- if (value instanceof type) return
+ if (value.constructor.toString().match(/function (.*?)\(/)[1] === type.name) return
}
}
diff --git a/test/types.js b/test/types.js
index 4b6c12344..fe1d149c7 100644
--- a/test/types.js
+++ b/test/types.js
@@ -1,7 +1,7 @@
var assert = require('assert')
var enforceType = require('../src/types')
-function CustomType() {}
+function CustomType() { return "ensure non-greedy match".toUpperCase() }
var types = ['Array', 'Boolean', 'Buffer', 'Number', 'String', CustomType]
var values = [[], true, new Buffer(1), 1234, 'foobar', new CustomType()]
From b55b10c6b69117ae9ad1a87a06767cbee99eb5a3 Mon Sep 17 00:00:00 2001
From: Wei Lu
Date: Wed, 8 Oct 2014 09:26:45 -0700
Subject: [PATCH 113/291] types: replace Function.name with an IE compatible
alternative
---
src/types.js | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/types.js b/src/types.js
index 501934f0a..5f885d0c5 100644
--- a/src/types.js
+++ b/src/types.js
@@ -26,9 +26,15 @@ module.exports = function enforce(type, value) {
}
default: {
- if (value.constructor.toString().match(/function (.*?)\(/)[1] === type.name) return
+ if (getName(value.constructor) === getName(type)) return
}
}
- throw new TypeError('Expected ' + (type.name || type) + ', got ' + value)
+ throw new TypeError('Expected ' + (getName(type) || type) + ', got ' + value)
+}
+
+function getName(fn) {
+ // Why not fn.name: https://kangax.github.io/compat-table/es6/#function_name_property
+ var match = fn.toString().match(/function (.*?)\(/)
+ return match ? match[1] : null
}
From 8bdf61d7f0b668426619ce2c35ead95cc1a9ef10 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 9 Oct 2014 11:27:52 +1100
Subject: [PATCH 114/291] package: update crypto-browserify to 3.2.6
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 194dc7ee7..6a41a26ec 100644
--- a/package.json
+++ b/package.json
@@ -75,7 +75,7 @@
"dependencies": {
"bigi": "^1.1.0",
"bs58check": "1.0.3",
- "crypto-browserify": "3.2.4",
+ "crypto-browserify": "^3.2.6",
"ecurve": "1.0.0"
}
}
From 7fb45aefb6d0814829cc566f36014b8b98459fe0 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 9 Oct 2014 11:28:32 +1100
Subject: [PATCH 115/291] 1.1.4
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 6a41a26ec..cc5335a3e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.3",
+ "version": "1.1.4",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 1b57f0871d33a7627359019f9b771515de180ca5 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 10 Oct 2014 19:23:40 +1100
Subject: [PATCH 116/291] message: remove duplicate require
---
src/message.js | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/message.js b/src/message.js
index 4bb96a361..35ce866c4 100644
--- a/src/message.js
+++ b/src/message.js
@@ -1,12 +1,10 @@
-/// Implements Bitcoin's feature for signing arbitrary messages.
-var Address = require('./address')
-var BigInteger = require('bigi')
var bufferutils = require('./bufferutils')
var crypto = require('./crypto')
var ecdsa = require('./ecdsa')
var networks = require('./networks')
var Address = require('./address')
+var BigInteger = require('bigi')
var ECPubKey = require('./ecpubkey')
var ECSignature = require('./ecsignature')
From 98bc1685b3127c62498c83d6bf6a76be382243d4 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 10 Oct 2014 19:24:16 +1100
Subject: [PATCH 117/291] message: remove unnecessary verbosity
---
src/message.js | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/src/message.js b/src/message.js
index 35ce866c4..76ba3f0aa 100644
--- a/src/message.js
+++ b/src/message.js
@@ -3,7 +3,6 @@ var crypto = require('./crypto')
var ecdsa = require('./ecdsa')
var networks = require('./networks')
-var Address = require('./address')
var BigInteger = require('bigi')
var ECPubKey = require('./ecpubkey')
var ECSignature = require('./ecsignature')
@@ -38,10 +37,6 @@ function verify(address, signature, message, network) {
signature = new Buffer(signature, 'base64')
}
- if (address instanceof Address) {
- address = address.toString()
- }
-
network = network || networks.bitcoin
var hash = magicHash(message, network)
@@ -50,7 +45,7 @@ function verify(address, signature, message, network) {
var Q = ecdsa.recoverPubKey(ecparams, e, parsed.signature, parsed.i)
var pubKey = new ECPubKey(Q, parsed.compressed)
- return pubKey.getAddress(network).toString() === address
+ return pubKey.getAddress(network).toString() === address.toString()
}
module.exports = {
From 10630873ebaa42381c5871e20336fbfb46564ac8 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 11 Oct 2014 13:47:32 +1100
Subject: [PATCH 118/291] tests: add tests for ecdsa.verify
---
src/ecdsa.js | 16 ++++++++--------
test/ecdsa.js | 10 +++++++---
test/fixtures/ecdsa.json | 18 +++++++++---------
3 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/src/ecdsa.js b/src/ecdsa.js
index 7b9db0b3b..75450dcfd 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -76,14 +76,6 @@ function sign(curve, hash, d) {
return new ECSignature(r, s)
}
-function verify(curve, hash, signature, Q) {
- // 1.4.2 H = Hash(M), already done by the user
- // 1.4.3 e = H
- var e = BigInteger.fromBuffer(hash)
-
- return verifyRaw(curve, e, signature, Q)
-}
-
function verifyRaw(curve, e, signature, Q) {
var n = curve.n
var G = curve.G
@@ -114,6 +106,14 @@ function verifyRaw(curve, e, signature, Q) {
return v.equals(r)
}
+function verify(curve, hash, signature, Q) {
+ // 1.4.2 H = Hash(M), already done by the user
+ // 1.4.3 e = H
+ var e = BigInteger.fromBuffer(hash)
+
+ return verifyRaw(curve, e, signature, Q)
+}
+
/**
* Recover a public key from a signature.
*
diff --git a/test/ecdsa.js b/test/ecdsa.js
index 84c0b44a3..58a00762b 100644
--- a/test/ecdsa.js
+++ b/test/ecdsa.js
@@ -115,31 +115,35 @@ describe('ecdsa', function() {
})
})
- describe('verifyRaw', function() {
+ describe('verify/verifyRaw', function() {
fixtures.valid.forEach(function(f) {
it('verifies a valid signature for \"' + f.message + '\"', function() {
var d = BigInteger.fromHex(f.d)
- var e = BigInteger.fromBuffer(crypto.sha256(f.message))
+ var H = crypto.sha256(f.message)
+ var e = BigInteger.fromBuffer(H)
var signature = new ECSignature(
new BigInteger(f.signature.r),
new BigInteger(f.signature.s)
)
var Q = curve.G.multiply(d)
+ assert(ecdsa.verify(curve, H, signature, Q))
assert(ecdsa.verifyRaw(curve, e, signature, Q))
})
})
fixtures.invalid.verifyRaw.forEach(function(f) {
it('fails to verify with ' + f.description, function() {
+ var H = crypto.sha256(f.message)
+ var e = BigInteger.fromBuffer(H)
var d = BigInteger.fromHex(f.d)
- var e = BigInteger.fromHex(f.e)
var signature = new ECSignature(
new BigInteger(f.signature.r),
new BigInteger(f.signature.s)
)
var Q = curve.G.multiply(d)
+ assert.equal(ecdsa.verify(curve, H, signature, Q), false)
assert.equal(ecdsa.verifyRaw(curve, e, signature, Q), false)
})
})
diff --git a/test/fixtures/ecdsa.json b/test/fixtures/ecdsa.json
index ea53d7c00..faad86415 100644
--- a/test/fixtures/ecdsa.json
+++ b/test/fixtures/ecdsa.json
@@ -148,7 +148,7 @@
{
"description": "The wrong signature",
"d": "01",
- "e": "06ef2b193b83b3d701f765f1db34672ab84897e1252343cc2197829af3a30456",
+ "message": "foo",
"signature": {
"r": "38341707918488238920692284707283974715538935465589664377561695343399725051885",
"s": "3180566392414476763164587487324397066658063772201694230600609996154610926757"
@@ -157,7 +157,7 @@
{
"description": "Invalid r value (< 0)",
"d": "01",
- "e": "01",
+ "message": "foo",
"signature": {
"r": "-01",
"s": "02"
@@ -166,7 +166,7 @@
{
"description": "Invalid r value (== 0)",
"d": "01",
- "e": "01",
+ "message": "foo",
"signature": {
"r": "00",
"s": "02"
@@ -175,7 +175,7 @@
{
"description": "Invalid r value (>= n)",
"d": "01",
- "e": "01",
+ "message": "foo",
"signature": {
"r": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
"s": "02"
@@ -184,7 +184,7 @@
{
"description": "Invalid s value (< 0)",
"d": "01",
- "e": "01",
+ "message": "foo",
"signature": {
"r": "02",
"s": "-01"
@@ -193,7 +193,7 @@
{
"description": "Invalid s value (== 0)",
"d": "01",
- "e": "01",
+ "message": "foo",
"signature": {
"r": "02",
"s": "00"
@@ -202,7 +202,7 @@
{
"description": "Invalid s value (>= n)",
"d": "01",
- "e": "01",
+ "message": "foo",
"signature": {
"r": "02",
"s": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
@@ -211,7 +211,7 @@
{
"description": "Invalid r, s values (r = s = -n)",
"d": "01",
- "e": "01",
+ "message": "foo",
"signature": {
"r": "-115792089237316195423570985008687907852837564279074904382605163141518161494337",
"s": "-115792089237316195423570985008687907852837564279074904382605163141518161494337"
@@ -219,4 +219,4 @@
}
]
}
-}
+}
\ No newline at end of file
From 6dc3b4cc1e270ea2a649d501b40813ccd6fc3ca5 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 17:58:24 +1100
Subject: [PATCH 119/291] tests: add unknown network HDNode version fixture
---
test/fixtures/hdnode.json | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/fixtures/hdnode.json b/test/fixtures/hdnode.json
index 86040a3cc..0f25c3f2a 100644
--- a/test/fixtures/hdnode.json
+++ b/test/fixtures/hdnode.json
@@ -196,6 +196,10 @@
{
"exception": "Invalid checksum",
"string": "xprvQQQQQQQQQQQQQQQQCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"
+ },
+ {
+ "exception": "Could not find version 0",
+ "string": "1111111111111adADjFaSNPxwXqLjHLj4mBfYxuewDPbw9hEj1uaXCzMxRPXDFF3cUoezTFYom4sEmEVSQmENPPR315cFk9YUFVek73wE9"
}
],
"fromBuffer": [
From 5f2e0af4d0eed43e2239d7637ef8b06802988ba2 Mon Sep 17 00:00:00 2001
From: Rodolfo Novak
Date: Mon, 13 Oct 2014 14:59:04 -0400
Subject: [PATCH 120/291] Add: Coinkite and fixed alphabetic order.
---
README.md | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 48b3a2301..923e5712f 100644
--- a/README.md
+++ b/README.md
@@ -130,19 +130,20 @@ console.log("multisigP2SH:", multisigAddress)
## Projects utilizing BitcoinJS
-- [Coinpunk](https://coinpunk.com)
-- [Hive Wallet](https://www.hivewallet.com)
-- [Justchain Exchange](https://justcoin.com)
-- [Skyhook ATM](http://projectskyhook.com)
+
- [BitAddress](https://www.bitaddress.org)
- [Blockchain.info](https://blockchain.info/wallet)
- [Brainwallet](https://brainwallet.github.io)
+- [Coinkite](https://coinkite.com)
+- [Coinpunk](https://coinpunk.com)
- [Dark Wallet](https://darkwallet.unsystem.net)
+- [DecentralBank](http://decentralbank.co)
- [Dogechain Wallet](https://dogechain.info)
- [GreenAddress](https://greenaddress.it)
-- [DecentralBank](http://decentralbank.co)
+- [Hive Wallet](https://www.hivewallet.com)
+- [Justchain Exchange](https://justcoin.com)
- [Quickcoin](https://wallet.quickcoin.co)
-
+- [Skyhook ATM](http://projectskyhook.com)
## Contributors
From 8a6a8b1dfa92320f01c1d497f29ee7848505abd6 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 14 Oct 2014 13:04:27 +1100
Subject: [PATCH 121/291] README: fix QuickCoin capitalization
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 923e5712f..24c5d5cc2 100644
--- a/README.md
+++ b/README.md
@@ -142,9 +142,10 @@ console.log("multisigP2SH:", multisigAddress)
- [GreenAddress](https://greenaddress.it)
- [Hive Wallet](https://www.hivewallet.com)
- [Justchain Exchange](https://justcoin.com)
-- [Quickcoin](https://wallet.quickcoin.co)
+- [QuickCoin](https://wallet.quickcoin.co)
- [Skyhook ATM](http://projectskyhook.com)
+
## Contributors
Stefan Thomas is the inventor and creator of this project. His pioneering work made Bitcoin web wallets possible.
From bc2048dfcaf3c3e36336a57114c1d87b4f8e612f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 18:36:46 +1100
Subject: [PATCH 122/291] scripts: remove out-of-date comments
---
src/scripts.js | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index 911fd1c33..8ed78f805 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -2,16 +2,6 @@ var assert = require('assert')
var enforceType = require('./types')
var opcodes = require('./opcodes')
-// FIXME: use ECPubKey, currently the circular dependency breaks everything.
-//
-// Solutions:
-// * Remove ECPubKey.getAddress
-// - Minimal change, but likely unpopular
-// * Move all script related functionality out of Address
-// - Means a lot of changes to Transaction/Wallet
-// * Ignore it (existing solution)
-// * Some form of hackery with commonjs
-//
var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')
@@ -56,7 +46,6 @@ function isCanonicalPubKey(buffer) {
if (!Buffer.isBuffer(buffer)) return false
try {
- // FIXME: boo
ecurve.Point.decodeFrom(curve, buffer)
} catch (e) {
if (!(e.message.match(/Invalid sequence (length|tag)/))) throw e
From 407d15869a9605aed525a86de80cde839665fbbf Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 18:37:50 +1100
Subject: [PATCH 123/291] scripts: s/opcodes/ops
---
src/scripts.js | 64 +++++++++++++++++++++++++-------------------------
1 file changed, 32 insertions(+), 32 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index 8ed78f805..fdec7b174 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -1,6 +1,6 @@
var assert = require('assert')
var enforceType = require('./types')
-var opcodes = require('./opcodes')
+var ops = require('./opcodes')
var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')
@@ -78,12 +78,12 @@ function isPubKeyHashInput() {
function isPubKeyHashOutput() {
return this.chunks.length === 5 &&
- this.chunks[0] === opcodes.OP_DUP &&
- this.chunks[1] === opcodes.OP_HASH160 &&
+ this.chunks[0] === ops.OP_DUP &&
+ this.chunks[1] === ops.OP_HASH160 &&
Buffer.isBuffer(this.chunks[2]) &&
this.chunks[2].length === 20 &&
- this.chunks[3] === opcodes.OP_EQUALVERIFY &&
- this.chunks[4] === opcodes.OP_CHECKSIG
+ this.chunks[3] === ops.OP_EQUALVERIFY &&
+ this.chunks[4] === ops.OP_CHECKSIG
}
function isPubKeyInput() {
@@ -94,7 +94,7 @@ function isPubKeyInput() {
function isPubKeyOutput() {
return this.chunks.length === 2 &&
isCanonicalPubKey(this.chunks[0]) &&
- this.chunks[1] === opcodes.OP_CHECKSIG
+ this.chunks[1] === ops.OP_CHECKSIG
}
function isScriptHashInput() {
@@ -111,33 +111,33 @@ function isScriptHashInput() {
function isScriptHashOutput() {
return this.chunks.length === 3 &&
- this.chunks[0] === opcodes.OP_HASH160 &&
+ this.chunks[0] === ops.OP_HASH160 &&
Buffer.isBuffer(this.chunks[1]) &&
this.chunks[1].length === 20 &&
- this.chunks[2] === opcodes.OP_EQUAL
+ this.chunks[2] === ops.OP_EQUAL
}
function isMultisigInput() {
- return this.chunks[0] === opcodes.OP_0 &&
+ return this.chunks[0] === ops.OP_0 &&
this.chunks.slice(1).every(isCanonicalSignature)
}
function isMultisigOutput() {
if (this.chunks < 4) return false
- if (this.chunks[this.chunks.length - 1] !== opcodes.OP_CHECKMULTISIG) return false
+ if (this.chunks[this.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false
var mOp = this.chunks[0]
- if (mOp === opcodes.OP_0) return false
- if (mOp < opcodes.OP_1) return false
- if (mOp > opcodes.OP_16) return false
+ if (mOp === ops.OP_0) return false
+ if (mOp < ops.OP_1) return false
+ if (mOp > ops.OP_16) return false
var nOp = this.chunks[this.chunks.length - 2]
- if (nOp === opcodes.OP_0) return false
- if (nOp < opcodes.OP_1) return false
- if (nOp > opcodes.OP_16) return false
+ if (nOp === ops.OP_0) return false
+ if (nOp < ops.OP_1) return false
+ if (nOp > ops.OP_16) return false
- var m = mOp - (opcodes.OP_1 - 1)
- var n = nOp - (opcodes.OP_1 - 1)
+ var m = mOp - (ops.OP_1 - 1)
+ var n = nOp - (ops.OP_1 - 1)
if (n < m) return false
var pubKeys = this.chunks.slice(1, -2)
@@ -147,7 +147,7 @@ function isMultisigOutput() {
}
function isNulldataOutput() {
- return this.chunks[0] === opcodes.OP_RETURN
+ return this.chunks[0] === ops.OP_RETURN
}
// Standard Script Templates
@@ -155,7 +155,7 @@ function isNulldataOutput() {
function pubKeyOutput(pubKey) {
return Script.fromChunks([
pubKey.toBuffer(),
- opcodes.OP_CHECKSIG
+ ops.OP_CHECKSIG
])
}
@@ -164,11 +164,11 @@ function pubKeyHashOutput(hash) {
enforceType('Buffer', hash)
return Script.fromChunks([
- opcodes.OP_DUP,
- opcodes.OP_HASH160,
+ ops.OP_DUP,
+ ops.OP_HASH160,
hash,
- opcodes.OP_EQUALVERIFY,
- opcodes.OP_CHECKSIG
+ ops.OP_EQUALVERIFY,
+ ops.OP_CHECKSIG
])
}
@@ -177,9 +177,9 @@ function scriptHashOutput(hash) {
enforceType('Buffer', hash)
return Script.fromChunks([
- opcodes.OP_HASH160,
+ ops.OP_HASH160,
hash,
- opcodes.OP_EQUAL
+ ops.OP_EQUAL
])
}
@@ -195,10 +195,10 @@ function multisigOutput(m, pubKeys) {
var n = pubKeys.length
return Script.fromChunks([].concat(
- (opcodes.OP_1 - 1) + m,
+ (ops.OP_1 - 1) + m,
pubKeyBuffers,
- (opcodes.OP_1 - 1) + n,
- opcodes.OP_CHECKMULTISIG
+ (ops.OP_1 - 1) + n,
+ ops.OP_CHECKMULTISIG
))
}
@@ -231,14 +231,14 @@ function multisigInput(signatures, scriptPubKey) {
var mOp = scriptPubKey.chunks[0]
var nOp = scriptPubKey.chunks[scriptPubKey.chunks.length - 2]
- var m = mOp - (opcodes.OP_1 - 1)
- var n = nOp - (opcodes.OP_1 - 1)
+ var m = mOp - (ops.OP_1 - 1)
+ var n = nOp - (ops.OP_1 - 1)
assert(signatures.length >= m, 'Not enough signatures provided')
assert(signatures.length <= n, 'Too many signatures provided')
}
- return Script.fromChunks([].concat(opcodes.OP_0, signatures))
+ return Script.fromChunks([].concat(ops.OP_0, signatures))
}
module.exports = {
From b7febc1bd807c2fe25f99b509654b43d7294de15 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 18:38:54 +1100
Subject: [PATCH 124/291] scripts: re-order classify functions
---
src/scripts.js | 68 +++++++++++++++++++++++++-------------------------
1 file changed, 34 insertions(+), 34 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index fdec7b174..fafb91eca 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -8,40 +8,6 @@ var curve = ecurve.getCurveByName('secp256k1')
var ECSignature = require('./ecsignature')
var Script = require('./script')
-function classifyOutput(script) {
- enforceType(Script, script)
-
- if (isPubKeyHashOutput.call(script)) {
- return 'pubkeyhash'
- } else if (isScriptHashOutput.call(script)) {
- return 'scripthash'
- } else if (isMultisigOutput.call(script)) {
- return 'multisig'
- } else if (isPubKeyOutput.call(script)) {
- return 'pubkey'
- } else if (isNulldataOutput.call(script)) {
- return 'nulldata'
- } else {
- return 'nonstandard'
- }
-}
-
-function classifyInput(script) {
- enforceType(Script, script)
-
- if (isPubKeyHashInput.call(script)) {
- return 'pubkeyhash'
- } else if (isScriptHashInput.call(script)) {
- return 'scripthash'
- } else if (isMultisigInput.call(script)) {
- return 'multisig'
- } else if (isPubKeyInput.call(script)) {
- return 'pubkey'
- } else {
- return 'nonstandard'
- }
-}
-
function isCanonicalPubKey(buffer) {
if (!Buffer.isBuffer(buffer)) return false
@@ -150,6 +116,40 @@ function isNulldataOutput() {
return this.chunks[0] === ops.OP_RETURN
}
+function classifyOutput(script) {
+ enforceType(Script, script)
+
+ if (isPubKeyHashOutput.call(script)) {
+ return 'pubkeyhash'
+ } else if (isScriptHashOutput.call(script)) {
+ return 'scripthash'
+ } else if (isMultisigOutput.call(script)) {
+ return 'multisig'
+ } else if (isPubKeyOutput.call(script)) {
+ return 'pubkey'
+ } else if (isNulldataOutput.call(script)) {
+ return 'nulldata'
+ } else {
+ return 'nonstandard'
+ }
+}
+
+function classifyInput(script) {
+ enforceType(Script, script)
+
+ if (isPubKeyHashInput.call(script)) {
+ return 'pubkeyhash'
+ } else if (isScriptHashInput.call(script)) {
+ return 'scripthash'
+ } else if (isMultisigInput.call(script)) {
+ return 'multisig'
+ } else if (isPubKeyInput.call(script)) {
+ return 'pubkey'
+ } else {
+ return 'nonstandard'
+ }
+}
+
// Standard Script Templates
// {pubKey} OP_CHECKSIG
function pubKeyOutput(pubKey) {
From 1a20c0db39a98c85bb699975cad828e779f0271a Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 18:46:50 +1100
Subject: [PATCH 125/291] scripts: avoid unnecessary this context
---
src/scripts.js | 100 ++++++++++++++++++++++++-------------------------
1 file changed, 50 insertions(+), 50 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index fafb91eca..74942f23a 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -36,68 +36,68 @@ function isCanonicalSignature(buffer) {
return true
}
-function isPubKeyHashInput() {
- return this.chunks.length === 2 &&
- isCanonicalSignature(this.chunks[0]) &&
- isCanonicalPubKey(this.chunks[1])
+function isPubKeyHashInput(script) {
+ return script.chunks.length === 2 &&
+ isCanonicalSignature(script.chunks[0]) &&
+ isCanonicalPubKey(script.chunks[1])
}
-function isPubKeyHashOutput() {
- return this.chunks.length === 5 &&
- this.chunks[0] === ops.OP_DUP &&
- this.chunks[1] === ops.OP_HASH160 &&
- Buffer.isBuffer(this.chunks[2]) &&
- this.chunks[2].length === 20 &&
- this.chunks[3] === ops.OP_EQUALVERIFY &&
- this.chunks[4] === ops.OP_CHECKSIG
+function isPubKeyHashOutput(script) {
+ return script.chunks.length === 5 &&
+ script.chunks[0] === ops.OP_DUP &&
+ script.chunks[1] === ops.OP_HASH160 &&
+ Buffer.isBuffer(script.chunks[2]) &&
+ script.chunks[2].length === 20 &&
+ script.chunks[3] === ops.OP_EQUALVERIFY &&
+ script.chunks[4] === ops.OP_CHECKSIG
}
-function isPubKeyInput() {
- return this.chunks.length === 1 &&
- isCanonicalSignature(this.chunks[0])
+function isPubKeyInput(script) {
+ return script.chunks.length === 1 &&
+ isCanonicalSignature(script.chunks[0])
}
-function isPubKeyOutput() {
- return this.chunks.length === 2 &&
- isCanonicalPubKey(this.chunks[0]) &&
- this.chunks[1] === ops.OP_CHECKSIG
+function isPubKeyOutput(script) {
+ return script.chunks.length === 2 &&
+ isCanonicalPubKey(script.chunks[0]) &&
+ script.chunks[1] === ops.OP_CHECKSIG
}
-function isScriptHashInput() {
- if (this.chunks.length < 2) return false
- var lastChunk = this.chunks[this.chunks.length - 1]
+function isScriptHashInput(script) {
+ if (script.chunks.length < 2) return false
+ var lastChunk = script.chunks[script.chunks.length - 1]
if (!Buffer.isBuffer(lastChunk)) return false
- var scriptSig = Script.fromChunks(this.chunks.slice(0, -1))
+ var scriptSig = Script.fromChunks(script.chunks.slice(0, -1))
var scriptPubKey = Script.fromBuffer(lastChunk)
return classifyInput(scriptSig) === classifyOutput(scriptPubKey)
}
-function isScriptHashOutput() {
- return this.chunks.length === 3 &&
- this.chunks[0] === ops.OP_HASH160 &&
- Buffer.isBuffer(this.chunks[1]) &&
- this.chunks[1].length === 20 &&
- this.chunks[2] === ops.OP_EQUAL
+function isScriptHashOutput(script) {
+ return script.chunks.length === 3 &&
+ script.chunks[0] === ops.OP_HASH160 &&
+ Buffer.isBuffer(script.chunks[1]) &&
+ script.chunks[1].length === 20 &&
+ script.chunks[2] === ops.OP_EQUAL
}
-function isMultisigInput() {
- return this.chunks[0] === ops.OP_0 &&
- this.chunks.slice(1).every(isCanonicalSignature)
+function isMultisigInput(script) {
+ return script.chunks[0] === ops.OP_0 &&
+ script.chunks.slice(1).every(isCanonicalSignature)
}
-function isMultisigOutput() {
- if (this.chunks < 4) return false
- if (this.chunks[this.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false
+function isMultisigOutput(script) {
+ if (script.chunks < 4) return false
+ if (script.chunks[script.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false
- var mOp = this.chunks[0]
+ var mOp = script.chunks[0]
if (mOp === ops.OP_0) return false
if (mOp < ops.OP_1) return false
if (mOp > ops.OP_16) return false
- var nOp = this.chunks[this.chunks.length - 2]
+ var nOp = script.chunks[script.chunks.length - 2]
if (nOp === ops.OP_0) return false
if (nOp < ops.OP_1) return false
if (nOp > ops.OP_16) return false
@@ -106,28 +106,28 @@ function isMultisigOutput() {
var n = nOp - (ops.OP_1 - 1)
if (n < m) return false
- var pubKeys = this.chunks.slice(1, -2)
+ var pubKeys = script.chunks.slice(1, -2)
if (n < pubKeys.length) return false
return pubKeys.every(isCanonicalPubKey)
}
-function isNulldataOutput() {
- return this.chunks[0] === ops.OP_RETURN
+function isNulldataOutput(script) {
+ return script.chunks[0] === ops.OP_RETURN
}
function classifyOutput(script) {
enforceType(Script, script)
- if (isPubKeyHashOutput.call(script)) {
+ if (isPubKeyHashOutput(script)) {
return 'pubkeyhash'
- } else if (isScriptHashOutput.call(script)) {
+ } else if (isScriptHashOutput(script)) {
return 'scripthash'
- } else if (isMultisigOutput.call(script)) {
+ } else if (isMultisigOutput(script)) {
return 'multisig'
- } else if (isPubKeyOutput.call(script)) {
+ } else if (isPubKeyOutput(script)) {
return 'pubkey'
- } else if (isNulldataOutput.call(script)) {
+ } else if (isNulldataOutput(script)) {
return 'nulldata'
} else {
return 'nonstandard'
@@ -137,13 +137,13 @@ function classifyOutput(script) {
function classifyInput(script) {
enforceType(Script, script)
- if (isPubKeyHashInput.call(script)) {
+ if (isPubKeyHashInput(script)) {
return 'pubkeyhash'
- } else if (isScriptHashInput.call(script)) {
+ } else if (isScriptHashInput(script)) {
return 'scripthash'
- } else if (isMultisigInput.call(script)) {
+ } else if (isMultisigInput(script)) {
return 'multisig'
- } else if (isPubKeyInput.call(script)) {
+ } else if (isPubKeyInput(script)) {
return 'pubkey'
} else {
return 'nonstandard'
@@ -227,7 +227,7 @@ function scriptHashInput(scriptSig, scriptPubKey) {
// OP_0 [signatures ...]
function multisigInput(signatures, scriptPubKey) {
if (scriptPubKey) {
- assert(isMultisigOutput.call(scriptPubKey))
+ assert(isMultisigOutput(scriptPubKey))
var mOp = scriptPubKey.chunks[0]
var nOp = scriptPubKey.chunks[scriptPubKey.chunks.length - 2]
From b65e70b29c159949a3f98260c2cef57562ab8acb Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 18:53:07 +1100
Subject: [PATCH 126/291] scripts: remove explict else branch
---
src/scripts.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index 74942f23a..7d77b16bf 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -129,9 +129,9 @@ function classifyOutput(script) {
return 'pubkey'
} else if (isNulldataOutput(script)) {
return 'nulldata'
- } else {
- return 'nonstandard'
}
+
+ return 'nonstandard'
}
function classifyInput(script) {
@@ -145,9 +145,9 @@ function classifyInput(script) {
return 'multisig'
} else if (isPubKeyInput(script)) {
return 'pubkey'
- } else {
- return 'nonstandard'
}
+
+ return 'nonstandard'
}
// Standard Script Templates
From 27a99436df06003f3c6a6bae1b98fc3386cd1830 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 19:34:26 +1100
Subject: [PATCH 127/291] tests: cover all multisigOutput branchs
---
test/fixtures/scripts.json | 38 +++++++++++++++++++++++++++++---------
1 file changed, 29 insertions(+), 9 deletions(-)
diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json
index e264a4ab0..aa5d29e89 100644
--- a/test/fixtures/scripts.json
+++ b/test/fixtures/scripts.json
@@ -53,24 +53,44 @@
"invalid": {
"classify": [
{
- "description": "multisig output : m > n",
- "scriptPubKey": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_1 OP_CHECKMULTISIG"
+ "description": "multisig output : OP_CHECKMULTISIG not found",
+ "scriptPubKey": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_HASH160"
+ },
+ {
+ "description": "multisig output : less than 4 chunks",
+ "scriptPubKey": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_HASH160"
+ },
+ {
+ "description": "multisig output : m === 0",
+ "scriptPubKey": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG"
+ },
+ {
+ "description": "multisig output : m < OP_1",
+ "scriptPubKey": "OP_1NEGATE 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG"
+ },
+ {
+ "description": "multisig output : m > OP_16",
+ "scriptPubKey": "OP_NOP 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG"
},
{
"description": "multisig output : n === 0",
- "scriptPubKey": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_0 OP_CHECKMULTISIG"
+ "scriptPubKey": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_0 OP_CHECKMULTISIG"
},
{
- "description": "multisig output : not (m <= len(pubKeys) <= n)",
- "scriptPubKey": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_2 OP_CHECKMULTISIG"
+ "description": "multisig output : n < OP_1",
+ "scriptPubKey": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_1NEGATE OP_CHECKMULTISIG"
},
{
- "description": "multisig output : m not a small int",
- "scriptPubKey": "OP_HASH160 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_1 OP_CHECKMULTISIG"
+ "description": "multisig output : n > OP_16",
+ "scriptPubKey": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_NOP OP_CHECKMULTISIG"
},
{
- "description": "multisig output : n not a small int",
- "scriptPubKey": "OP_1 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_HASH160 OP_CHECKMULTISIG"
+ "description": "multisig output : n < m",
+ "scriptPubKey": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_1 OP_CHECKMULTISIG"
+ },
+ {
+ "description": "multisig output : n < len(pubKeys)",
+ "scriptPubKey": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_2 OP_CHECKMULTISIG"
},
{
"description": "multisig output : non-canonical pubKey (bad length)",
From ddb24ee6153f4a0d77d2e44f42222d6175f4c2ac Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 19:46:20 +1100
Subject: [PATCH 128/291] scripts: check chunks length properly
---
src/scripts.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/scripts.js b/src/scripts.js
index 7d77b16bf..b7c4dd596 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -89,7 +89,7 @@ function isMultisigInput(script) {
}
function isMultisigOutput(script) {
- if (script.chunks < 4) return false
+ if (script.chunks.length < 4) return false
if (script.chunks[script.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false
var mOp = script.chunks[0]
From f3138dcb6859b880e7e025586b96085d11cb2c30 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 19:51:13 +1100
Subject: [PATCH 129/291] tests: test non-standard pathway for classifyInput
---
test/fixtures/scripts.json | 4 ++++
test/scripts.js | 13 +++++++++++++
2 files changed, 17 insertions(+)
diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json
index aa5d29e89..cd6947074 100644
--- a/test/fixtures/scripts.json
+++ b/test/fixtures/scripts.json
@@ -95,6 +95,10 @@
{
"description": "multisig output : non-canonical pubKey (bad length)",
"scriptPubKey": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffff OP_1 OP_CHECKMULTISIG"
+ },
+ {
+ "description": "pubKeyHash input : extraneous data",
+ "scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 ffffffff"
}
],
"multisig": [
diff --git a/test/scripts.js b/test/scripts.js
index b50ec3a1f..9709ec9df 100644
--- a/test/scripts.js
+++ b/test/scripts.js
@@ -19,6 +19,17 @@ describe('Scripts', function() {
assert.equal(type, f.type)
})
})
+
+ fixtures.invalid.classify.forEach(function(f) {
+ if (!f.scriptSig) return
+
+ it('returns nonstandard for ' + f.description, function() {
+ var script = Script.fromASM(f.scriptSig)
+ var type = scripts.classifyInput(script)
+
+ assert.equal(type, 'nonstandard')
+ })
+ })
})
describe('classifyOutput', function() {
@@ -34,6 +45,8 @@ describe('Scripts', function() {
})
fixtures.invalid.classify.forEach(function(f) {
+ if (!f.scriptPubKey) return
+
it('returns nonstandard for ' + f.description, function() {
var script = Script.fromASM(f.scriptPubKey)
var type = scripts.classifyOutput(script)
From f9a5c47d95debfa2159d9c1db105493f3e66e605 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 19:59:21 +1100
Subject: [PATCH 130/291] tests: add OP_RETURN scripts fixture
---
test/fixtures/scripts.json | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json
index cd6947074..238c85c7b 100644
--- a/test/fixtures/scripts.json
+++ b/test/fixtures/scripts.json
@@ -48,6 +48,10 @@
"redeemScriptSig": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
"scriptSig": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae",
"scriptPubKey": "OP_HASH160 722ff0bc2c3f47b35c20df646c395594da24e90e OP_EQUAL"
+ },
+ {
+ "type": "nulldata",
+ "scriptPubKey": "OP_RETURN ffffffffffffffffffffffffffffffffffffffff"
}
],
"invalid": {
From f6e340f64ca1c97e0ca1ed0c1e1c010316828179 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 20:04:42 +1100
Subject: [PATCH 131/291] tests: add scriptHash redeemScript non-data fixture
---
test/fixtures/scripts.json | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json
index 238c85c7b..65d63ccb3 100644
--- a/test/fixtures/scripts.json
+++ b/test/fixtures/scripts.json
@@ -103,6 +103,10 @@
{
"description": "pubKeyHash input : extraneous data",
"scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 ffffffff"
+ },
+ {
+ "description": "scriptHash input : redeemScript not data",
+ "scriptSig": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 OP_RESERVED"
}
],
"multisig": [
From ab57630f2022c9b0d2b2145d7024223b50ec4f9e Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 20:30:23 +1100
Subject: [PATCH 132/291] tests: add non-canonical signature test
---
test/fixtures/scripts.json | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json
index 65d63ccb3..4afdc970b 100644
--- a/test/fixtures/scripts.json
+++ b/test/fixtures/scripts.json
@@ -107,6 +107,10 @@
{
"description": "scriptHash input : redeemScript not data",
"scriptSig": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 OP_RESERVED"
+ },
+ {
+ "description": "pubKey input : non-canonical signature",
+ "scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf7593ffffffffffffffff"
}
],
"multisig": [
From 9340a8a7c1ed58afc57ccba66ef85e4b05ac068f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 13:13:03 +1100
Subject: [PATCH 133/291] package: 1.1.5
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index cc5335a3e..cc2347052 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.4",
+ "version": "1.1.5",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 561f52b20702fa59d8546114edef3d9bdecda3b9 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 18:04:57 +1100
Subject: [PATCH 134/291] index: re-expose base58check until 2.0.0
---
src/index.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/index.js b/src/index.js
index 0ab57e2cf..9be80f619 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,5 +1,6 @@
module.exports = {
Address: require('./address'),
+ base58check: require('bs58check'),
bufferutils: require('./bufferutils'),
crypto: require('./crypto'),
ecdsa: require('./ecdsa'),
From 13f07a7e55827de7bf86296f88395584b49ff610 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 18:05:29 +1100
Subject: [PATCH 135/291] 1.1.6
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index cc2347052..1ef96e82a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.5",
+ "version": "1.1.6",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From ef1eb049051a9a0a0e4c5ab2703dbc111b17ecde Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 15 Sep 2014 14:39:15 +1000
Subject: [PATCH 136/291] HDNode: move var declaration out of branches
---
src/hdnode.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/hdnode.js b/src/hdnode.js
index 018b913e4..226416d77 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -106,18 +106,18 @@ HDNode.fromBuffer = function(buffer, __ignoreDeprecation) {
// 32 bytes: the chain code
var chainCode = buffer.slice(13, 45)
- var hd
+ var data, hd
// 33 bytes: private key data (0x00 + k)
if (params.isPrivate) {
assert.strictEqual(buffer.readUInt8(45), 0x00, 'Invalid private key')
- var data = buffer.slice(46, 78)
+ data = buffer.slice(46, 78)
var d = BigInteger.fromBuffer(data)
hd = new HDNode(d, chainCode, params.network)
// 33 bytes: public key data (0x02 + X or 0x03 + X)
} else {
- var data = buffer.slice(45, 78)
+ data = buffer.slice(45, 78)
var Q = ecurve.Point.decodeFrom(curve, data)
assert.equal(Q.compressed, true, 'Invalid public key')
From 307ceb902690f0e6bb774a1567cdf4b6abb658be Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 19:08:39 +1100
Subject: [PATCH 137/291] HDNode: use === over ==
---
src/hdnode.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/hdnode.js b/src/hdnode.js
index 226416d77..9f0828e2c 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -167,7 +167,7 @@ HDNode.prototype.toBase58 = function(isPrivate) {
// FIXME: remove in 2.x.y
HDNode.prototype.toBuffer = function(isPrivate, __ignoreDeprecation) {
- if (isPrivate == undefined) {
+ if (isPrivate === undefined) {
isPrivate = !!this.privKey
// FIXME: remove in 2.x.y
From 395ef6ed85b1f12096cd14ff984ed6a20b13866b Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 19:42:05 +1100
Subject: [PATCH 138/291] base58check: add deprecation warnings
---
src/base58check.js | 18 ++++++++++++++++++
src/index.js | 2 +-
test/base58check.js | 25 +++++++++++++++++++++++++
3 files changed, 44 insertions(+), 1 deletion(-)
create mode 100644 src/base58check.js
create mode 100644 test/base58check.js
diff --git a/src/base58check.js b/src/base58check.js
new file mode 100644
index 000000000..2e91a4336
--- /dev/null
+++ b/src/base58check.js
@@ -0,0 +1,18 @@
+var bs58check = require('bs58check')
+
+function decode() {
+ console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.');
+
+ bs58check.decode.apply(undefined, arguments)
+}
+
+function encode() {
+ console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.');
+
+ bs58check.encode.apply(undefined, arguments)
+}
+
+module.exports = {
+ decode: decode,
+ encode: encode
+}
diff --git a/src/index.js b/src/index.js
index 9be80f619..85f0631b3 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,6 @@
module.exports = {
Address: require('./address'),
- base58check: require('bs58check'),
+ base58check: require('./bs58check'),
bufferutils: require('./bufferutils'),
crypto: require('./crypto'),
ecdsa: require('./ecdsa'),
diff --git a/test/base58check.js b/test/base58check.js
new file mode 100644
index 000000000..09e937804
--- /dev/null
+++ b/test/base58check.js
@@ -0,0 +1,25 @@
+var base58check = require('../src/base58check')
+var bs58check = require('bs58check')
+var sinon = require('sinon')
+
+describe('base58check', function() {
+ var param
+
+ beforeEach(function() {
+ param = {}
+ })
+
+ it('wraps bs58check.decode', sinon.test(function() {
+ this.mock(bs58check).expects('decode')
+ .once().calledWith(param)
+
+ base58check.decode(param)
+ }))
+
+ it('wraps bs58check.encode', sinon.test(function() {
+ this.mock(bs58check).expects('encode')
+ .once().calledWith(param)
+
+ base58check.encode(param)
+ }))
+})
From 87c3d4fd5eed0961fc29c5529d05143b7ae6feb1 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 19:42:08 +1100
Subject: [PATCH 139/291] 1.1.7
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 1ef96e82a..9cc64fdef 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.6",
+ "version": "1.1.7",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 7f5b4b791b9c4732444b9967f73e4e4e202904ec Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 22:10:46 +1100
Subject: [PATCH 140/291] index: fix base58check path
---
src/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/index.js b/src/index.js
index 85f0631b3..3761d2773 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,6 @@
module.exports = {
Address: require('./address'),
- base58check: require('./bs58check'),
+ base58check: require('./base58check'),
bufferutils: require('./bufferutils'),
crypto: require('./crypto'),
ecdsa: require('./ecdsa'),
From 49ab51c22778f592c296289ca82984b7830c30ad Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 22:11:01 +1100
Subject: [PATCH 141/291] 1.1.8
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 9cc64fdef..8e95220bb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.7",
+ "version": "1.1.8",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 27a3230662e8b8daec710f5d366ea12c51360370 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 22:36:10 +1100
Subject: [PATCH 142/291] base58check: fix wrapper and tests
---
src/base58check.js | 4 ++--
test/base58check.js | 9 +++++----
test/bitcoin.core.js | 22 ++++++++++++----------
3 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/src/base58check.js b/src/base58check.js
index 2e91a4336..8108a0b05 100644
--- a/src/base58check.js
+++ b/src/base58check.js
@@ -3,13 +3,13 @@ var bs58check = require('bs58check')
function decode() {
console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.');
- bs58check.decode.apply(undefined, arguments)
+ return bs58check.decode.apply(undefined, arguments)
}
function encode() {
console.warn('bs58check will be removed in 2.0.0. require("bs58check") instead.');
- bs58check.encode.apply(undefined, arguments)
+ return bs58check.encode.apply(undefined, arguments)
}
module.exports = {
diff --git a/test/base58check.js b/test/base58check.js
index 09e937804..8b704048e 100644
--- a/test/base58check.js
+++ b/test/base58check.js
@@ -1,3 +1,4 @@
+var assert = require('assert')
var base58check = require('../src/base58check')
var bs58check = require('bs58check')
var sinon = require('sinon')
@@ -11,15 +12,15 @@ describe('base58check', function() {
it('wraps bs58check.decode', sinon.test(function() {
this.mock(bs58check).expects('decode')
- .once().calledWith(param)
+ .once().calledWith(param).returns('foo')
- base58check.decode(param)
+ assert.equal(base58check.decode(param), 'foo')
}))
it('wraps bs58check.encode', sinon.test(function() {
this.mock(bs58check).expects('encode')
- .once().calledWith(param)
+ .once().calledWith(param).returns('foo')
- base58check.encode(param)
+ assert.equal(base58check.encode(param), 'foo')
}))
})
diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js
index 3560c8155..2dc76fca7 100644
--- a/test/bitcoin.core.js
+++ b/test/bitcoin.core.js
@@ -1,14 +1,16 @@
var assert = require('assert')
-var base58 = require('bs58')
-var base58check = require('bs58check')
var networks = require('../src/networks')
-var Address = require('../src/address')
-var BigInteger = require('bigi')
-var ECKey = require('../src/eckey')
-var ECSignature = require('../src/ecsignature')
-var Transaction = require('../src/transaction')
-var Script = require('../src/script')
+var base58 = require('bs58')
+//var base58check = require('bs58check')
+
+var Bitcoin = require('../')
+var Address = Bitcoin.Address
+var base58check = Bitcoin.base58check
+var ECKey = Bitcoin.ECKey
+var ECSignature = Bitcoin.ECSignature
+var Transaction = Bitcoin.Transaction
+var Script = Bitcoin.Script
var base58_encode_decode = require("./fixtures/core/base58_encode_decode.json")
var base58_keys_invalid = require("./fixtures/core/base58_keys_invalid.json")
@@ -120,8 +122,8 @@ describe('Bitcoin-core', function() {
it('throws on ' + string, function() {
assert.throws(function() {
- var privKey = ECKey.fromWIF(string)
- var version = base58check.decode(string).version
+ ECKey.fromWIF(string)
+ var version = base58check.decode(string).readUInt8(0)
assert.notEqual(allowedNetworks.indexOf(version), -1, 'Invalid network')
}, /Invalid (checksum|compression flag|network|WIF payload)/)
From 48a2d3cde54c573a222d4074ecf5ff1607afdeb4 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 22:36:23 +1100
Subject: [PATCH 143/291] 1.1.9
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 8e95220bb..ad651c572 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.8",
+ "version": "1.1.9",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From efcad257510a021317be9cd3e3ab2defb9de80f1 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 22:42:21 +1100
Subject: [PATCH 144/291] tests: amend base58check mock
---
test/base58check.js | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/test/base58check.js b/test/base58check.js
index 8b704048e..030fb09c0 100644
--- a/test/base58check.js
+++ b/test/base58check.js
@@ -11,15 +11,17 @@ describe('base58check', function() {
})
it('wraps bs58check.decode', sinon.test(function() {
- this.mock(bs58check).expects('decode')
- .once().calledWith(param).returns('foo')
+ var expectation = this.mock(bs58check).expects('decode')
+ expectation.once().calledWith(param)
+ expectation.onCall(0).returns('foo')
assert.equal(base58check.decode(param), 'foo')
}))
it('wraps bs58check.encode', sinon.test(function() {
- this.mock(bs58check).expects('encode')
- .once().calledWith(param).returns('foo')
+ var expectation = this.mock(bs58check).expects('encode')
+ expectation.once().calledWith(param)
+ expectation.onCall(0).returns('foo')
assert.equal(base58check.encode(param), 'foo')
}))
From 22c67adcf921533a599ed36c959c6d7fc8e1e64e Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 22:42:45 +1100
Subject: [PATCH 145/291] 1.1.10
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index ad651c572..989c74738 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.9",
+ "version": "1.1.10",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 4854e4ad0ac2ad8a17e89d5b19b881048619dbab Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 23:06:04 +1100
Subject: [PATCH 146/291] tests: bitcoin core tests should act only the public
API
---
test/bitcoin.core.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js
index 2dc76fca7..4b716d9cb 100644
--- a/test/bitcoin.core.js
+++ b/test/bitcoin.core.js
@@ -1,5 +1,4 @@
var assert = require('assert')
-var networks = require('../src/networks')
var base58 = require('bs58')
//var base58check = require('bs58check')
@@ -7,6 +6,7 @@ var base58 = require('bs58')
var Bitcoin = require('../')
var Address = Bitcoin.Address
var base58check = Bitcoin.base58check
+var networks = Bitcoin.networks
var ECKey = Bitcoin.ECKey
var ECSignature = Bitcoin.ECSignature
var Transaction = Bitcoin.Transaction
@@ -191,7 +191,7 @@ describe('Bitcoin-core', function() {
if (!e.message.match(/not yet supported/)) throw e
}
- if (actualHash != undefined) {
+ if (actualHash !== undefined) {
// Test data is big-endian
Array.prototype.reverse.call(actualHash)
From cba6c7a7b245435ee1088df8d250f7b32990fc20 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 15 Oct 2014 23:06:24 +1100
Subject: [PATCH 147/291] tests: remove unused variable
---
test/integration/p2sh.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/integration/p2sh.js b/test/integration/p2sh.js
index 3d474068e..0b975b6a2 100644
--- a/test/integration/p2sh.js
+++ b/test/integration/p2sh.js
@@ -57,7 +57,7 @@ describe('Bitcoin-js', function() {
})
// broadcast our transaction
- helloblock.transactions.propagate(txb.build().toHex(), function(err, res) {
+ helloblock.transactions.propagate(txb.build().toHex(), function(err) {
// no err means that the transaction has been successfully propagated
if (err) return done(err)
From 9510af10e3e9e789ffa4378d977f37e10b3efa26 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 16 Oct 2014 01:25:39 +1100
Subject: [PATCH 148/291] EC*Key: add .curve static property for public API
---
src/eckey.js | 13 ++++++++-----
src/ecpubkey.js | 9 ++++++---
test/eckey.js | 16 ++++++++++++++++
test/ecpubkey.js | 15 +++++++++++++++
4 files changed, 45 insertions(+), 8 deletions(-)
diff --git a/src/eckey.js b/src/eckey.js
index 23cd43d03..501384dcd 100644
--- a/src/eckey.js
+++ b/src/eckey.js
@@ -9,18 +9,21 @@ var BigInteger = require('bigi')
var ECPubKey = require('./ecpubkey')
var ecurve = require('ecurve')
-var curve = ecurve.getCurveByName('secp256k1')
+var secp256k1 = ecurve.getCurveByName('secp256k1')
function ECKey(d, compressed) {
assert(d.signum() > 0, 'Private key must be greater than 0')
- assert(d.compareTo(curve.n) < 0, 'Private key must be less than the curve order')
+ assert(d.compareTo(ECKey.curve.n) < 0, 'Private key must be less than the curve order')
- var Q = curve.G.multiply(d)
+ var Q = ECKey.curve.G.multiply(d)
this.d = d
this.pub = new ECPubKey(Q, compressed)
}
+// Constants
+ECKey.curve = secp256k1
+
// Static constructors
ECKey.fromWIF = function(string) {
var payload = base58check.decode(string)
@@ -51,7 +54,7 @@ ECKey.makeRandom = function(compressed, rng) {
assert.equal(buffer.length, 32, 'Expected 256-bit Buffer from RNG')
var d = BigInteger.fromBuffer(buffer)
- d = d.mod(curve.n)
+ d = d.mod(ECKey.curve.n)
return new ECKey(d, compressed)
}
@@ -75,7 +78,7 @@ ECKey.prototype.toWIF = function(network) {
// Operations
ECKey.prototype.sign = function(hash) {
- return ecdsa.sign(curve, hash, this.d)
+ return ecdsa.sign(ECKey.curve, hash, this.d)
}
module.exports = ECKey
diff --git a/src/ecpubkey.js b/src/ecpubkey.js
index 840fa5069..e2b25bc03 100644
--- a/src/ecpubkey.js
+++ b/src/ecpubkey.js
@@ -6,7 +6,7 @@ var networks = require('./networks')
var Address = require('./address')
var ecurve = require('ecurve')
-var curve = ecurve.getCurveByName('secp256k1')
+var secp256k1 = ecurve.getCurveByName('secp256k1')
function ECPubKey(Q, compressed) {
if (compressed === undefined) compressed = true
@@ -18,9 +18,12 @@ function ECPubKey(Q, compressed) {
this.Q = Q
}
+// Constants
+ECPubKey.curve = secp256k1
+
// Static constructors
ECPubKey.fromBuffer = function(buffer) {
- var Q = ecurve.Point.decodeFrom(curve, buffer)
+ var Q = ecurve.Point.decodeFrom(ECPubKey.curve, buffer)
return new ECPubKey(Q, Q.compressed)
}
@@ -36,7 +39,7 @@ ECPubKey.prototype.getAddress = function(network) {
}
ECPubKey.prototype.verify = function(hash, signature) {
- return ecdsa.verify(curve, hash, signature, this.Q)
+ return ecdsa.verify(ECPubKey.curve, hash, signature, this.Q)
}
// Export functions
diff --git a/test/eckey.js b/test/eckey.js
index 849dd7ed1..271e5f75a 100644
--- a/test/eckey.js
+++ b/test/eckey.js
@@ -1,5 +1,6 @@
var assert = require('assert')
var crypto = require('crypto')
+var ecurve = require('ecurve')
var networks = require('../src/networks')
var sinon = require('sinon')
@@ -42,6 +43,21 @@ describe('ECKey', function() {
})
})
+ it('uses the secp256k1 curve by default', function() {
+ var secp256k1 = ecurve.getCurveByName('secp256k1')
+
+ for (var property in secp256k1) {
+ // FIXME: circular structures in ecurve
+ if (property === 'G') continue
+ if (property === 'infinity') continue
+
+ var actual = ECKey.curve[property]
+ var expected = secp256k1[property]
+
+ assert.deepEqual(actual, expected)
+ }
+ })
+
describe('fromWIF', function() {
fixtures.valid.forEach(function(f) {
f.WIFs.forEach(function(wif) {
diff --git a/test/ecpubkey.js b/test/ecpubkey.js
index 35302f51d..bf4ac5a52 100644
--- a/test/ecpubkey.js
+++ b/test/ecpubkey.js
@@ -35,6 +35,21 @@ describe('ECPubKey', function() {
})
})
+ it('uses the secp256k1 curve by default', function() {
+ var secp256k1 = ecurve.getCurveByName('secp256k1')
+
+ for (var property in secp256k1) {
+ // FIXME: circular structures in ecurve
+ if (property === 'G') continue
+ if (property === 'infinity') continue
+
+ var actual = ECPubKey.curve[property]
+ var expected = secp256k1[property]
+
+ assert.deepEqual(actual, expected)
+ }
+ })
+
describe('fromHex/toHex', function() {
it('supports compressed points', function() {
var pubKey = ECPubKey.fromHex(fixtures.compressed.hex)
From cfcfe59520f1c24d6b1174dbf769d778a5484fce Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 16 Oct 2014 01:26:20 +1100
Subject: [PATCH 149/291] 1.2.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 989c74738..5ee2ec037 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.1.10",
+ "version": "1.2.0",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 5d5dcd3d734fefc06944bbbf241f3cba28d001f7 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 17 Oct 2014 13:24:47 +1100
Subject: [PATCH 150/291] remove unused base58 fixtures
---
test/fixtures/base58.json | 74 ---------------------------------------
1 file changed, 74 deletions(-)
delete mode 100644 test/fixtures/base58.json
diff --git a/test/fixtures/base58.json b/test/fixtures/base58.json
deleted file mode 100644
index a9b3705df..000000000
--- a/test/fixtures/base58.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "valid": [
- {
- "hex": "",
- "string": ""
- },
- {
- "hex": "61",
- "string": "2g"
- },
- {
- "hex": "626262",
- "string": "a3gV"
- },
- {
- "hex": "636363",
- "string": "aPEr"
- },
- {
- "hex": "73696d706c792061206c6f6e6720737472696e67",
- "string": "2cFupjhnEsSn59qHXstmK2ffpLv2"
- },
- {
- "hex": "00eb15231dfceb60925886b67d065299925915aeb172c06647",
- "string": "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"
- },
- {
- "hex": "516b6fcd0f",
- "string": "ABnLTmg"
- },
- {
- "hex": "bf4f89001e670274dd",
- "string": "3SEo3LWLoPntC"
- },
- {
- "hex": "572e4794",
- "string": "3EFU7m"
- },
- {
- "hex": "ecac89cad93923c02321",
- "string": "EJDM8drfXA6uyA"
- },
- {
- "hex": "10c8511e",
- "string": "Rt5zm"
- },
- {
- "hex": "00000000000000000000",
- "string": "1111111111"
- }
- ],
- "invalid": [
- {
- "description": "non-base58 string",
- "string": "invalid"
- },
- {
- "description": "non-base58 alphabet",
- "string": "c2F0b3NoaQo="
- },
- {
- "description": "leading whitespace",
- "string": " 1111111111"
- },
- {
- "description": "trailing whitespace",
- "string": "1111111111 "
- },
- {
- "description": "unexpected character after whitespace",
- "string": " \t\n\u000b\f\r skip \r\f\u000b\n\t a"
- }
- ]
-}
From 062540e3d9cbe8b70bdef7dfdd12f6aed07ab435 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 16 Oct 2014 15:25:43 +1100
Subject: [PATCH 151/291] Transaction: optional script for addInput
---
src/transaction.js | 6 ++++--
test/transaction.js | 15 +++++++++++++--
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index 72ab8428e..62ac33ec3 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -32,8 +32,9 @@ Transaction.SIGHASH_ANYONECANPAY = 0x80
*
* Note that this method does not sign the created input.
*/
-Transaction.prototype.addInput = function(hash, index, sequence) {
+Transaction.prototype.addInput = function(hash, index, sequence, script) {
if (sequence === undefined) sequence = Transaction.DEFAULT_SEQUENCE
+ script = script || Script.EMPTY
if (typeof hash === 'string') {
// TxId hex is big-endian, we need little-endian
@@ -47,6 +48,7 @@ Transaction.prototype.addInput = function(hash, index, sequence) {
enforceType('Buffer', hash)
enforceType('Number', index)
enforceType('Number', sequence)
+ enforceType(Script, script)
assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
@@ -54,7 +56,7 @@ Transaction.prototype.addInput = function(hash, index, sequence) {
return (this.ins.push({
hash: hash,
index: index,
- script: Script.EMPTY,
+ script: script,
sequence: sequence
}) - 1)
}
diff --git a/test/transaction.js b/test/transaction.js
index fc2711d39..3bd01927e 100644
--- a/test/transaction.js
+++ b/test/transaction.js
@@ -5,6 +5,7 @@ var scripts = require('../src/scripts')
var Address = require('../src/address')
var ECKey = require('../src/eckey')
var Transaction = require('../src/transaction')
+var Script = require('../src/script')
var fixtures = require('./fixtures/transaction')
@@ -96,20 +97,30 @@ describe('Transaction', function() {
assert.equal(tx.ins[0].sequence, Transaction.DEFAULT_SEQUENCE)
})
+ it('defaults to empty script', function() {
+ var tx = new Transaction()
+ tx.addInput(prevTxHash, 0)
+
+ assert.equal(tx.ins[0].script, Script.EMPTY)
+ })
+
fixtures.valid.forEach(function(f) {
it('should add the inputs for ' + f.txid + ' correctly', function() {
var tx = new Transaction()
f.raw.ins.forEach(function(txIn, i) {
- var j = tx.addInput(txIn.hash, txIn.index, txIn.sequence)
+ var script = txIn.script ? Script.fromHex(txIn.script) : Script.EMPTY
+ var j = tx.addInput(txIn.hash, txIn.index, txIn.sequence, script)
assert.equal(i, j)
assert.deepEqual(tx.ins[i].hash, txIn.hash)
assert.equal(tx.ins[i].index, txIn.index)
var sequence = txIn.sequence
- if (sequence == undefined) sequence = Transaction.DEFAULT_SEQUENCE
+ if (sequence === undefined) sequence = Transaction.DEFAULT_SEQUENCE
+
assert.equal(tx.ins[i].sequence, sequence)
+ assert.equal(tx.ins[i].script, script)
})
})
})
From 2234e496d19ec4d9a2eae051d5346d555231a86a Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 16 Oct 2014 15:30:12 +1100
Subject: [PATCH 152/291] Transaction: simplify fromBuffer verbosity
---
src/transaction.js | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index 62ac33ec3..c71d65ad0 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -113,14 +113,17 @@ Transaction.prototype.toBuffer = function () {
slice.copy(buffer, offset)
offset += slice.length
}
+
function writeUInt32(i) {
buffer.writeUInt32LE(i, offset)
offset += 4
}
+
function writeUInt64(i) {
bufferutils.writeUInt64LE(buffer, i, offset)
offset += 8
}
+
function writeVarInt(i) {
var n = bufferutils.writeVarInt(buffer, i, offset)
offset += n
@@ -247,50 +250,47 @@ Transaction.fromBuffer = function(buffer) {
offset += n
return buffer.slice(offset - n, offset)
}
+
function readUInt32() {
var i = buffer.readUInt32LE(offset)
offset += 4
return i
}
+
function readUInt64() {
var i = bufferutils.readUInt64LE(buffer, offset)
offset += 8
return i
}
+
function readVarInt() {
var vi = bufferutils.readVarInt(buffer, offset)
offset += vi.size
return vi.number
}
+ function readScript() {
+ return Script.fromBuffer(readSlice(readVarInt()))
+ }
+
var tx = new Transaction()
tx.version = readUInt32()
var vinLen = readVarInt()
for (var i = 0; i < vinLen; ++i) {
- var hash = readSlice(32)
- var vout = readUInt32()
- var scriptLen = readVarInt()
- var script = readSlice(scriptLen)
- var sequence = readUInt32()
-
tx.ins.push({
- hash: hash,
- index: vout,
- script: Script.fromBuffer(script),
- sequence: sequence
+ hash: readSlice(32),
+ index: readUInt32(),
+ script: readScript(),
+ sequence: readUInt32()
})
}
var voutLen = readVarInt()
for (i = 0; i < voutLen; ++i) {
- var value = readUInt64()
- var scriptLen = readVarInt()
- var script = readSlice(scriptLen)
-
tx.outs.push({
- value: value,
- script: Script.fromBuffer(script)
+ value: readUInt64(),
+ script: readScript(),
})
}
From 929d926774ad4ea0b45f06312a10e1ada2edfb7f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 17 Oct 2014 14:22:22 +1100
Subject: [PATCH 153/291] tests: make use of the default behaviour
---
test/transaction.js | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/test/transaction.js b/test/transaction.js
index 3bd01927e..d07061adb 100644
--- a/test/transaction.js
+++ b/test/transaction.js
@@ -1,5 +1,4 @@
var assert = require('assert')
-var networks = require('../src/networks')
var scripts = require('../src/scripts')
var Address = require('../src/address')
@@ -109,7 +108,7 @@ describe('Transaction', function() {
var tx = new Transaction()
f.raw.ins.forEach(function(txIn, i) {
- var script = txIn.script ? Script.fromHex(txIn.script) : Script.EMPTY
+ var script = txIn.script ? Script.fromHex(txIn.script) : undefined
var j = tx.addInput(txIn.hash, txIn.index, txIn.sequence, script)
assert.equal(i, j)
@@ -120,7 +119,7 @@ describe('Transaction', function() {
if (sequence === undefined) sequence = Transaction.DEFAULT_SEQUENCE
assert.equal(tx.ins[i].sequence, sequence)
- assert.equal(tx.ins[i].script, script)
+ assert.equal(tx.ins[i].script, script || Script.EMPTY)
})
})
})
From 27e69ba71603defcbcbda8f7b7958016941eabfc Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 17 Oct 2014 14:30:16 +1100
Subject: [PATCH 154/291] README: s/Multsig/Multisig
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 24c5d5cc2..133b082e7 100644
--- a/README.md
+++ b/README.md
@@ -110,7 +110,7 @@ console.log(tx.toHex())
```
-### Creating a P2SH Multsig Address
+### Creating a P2SH Multisig Address
``` javascript
var bitcoin = require('bitcoinjs-lib')
From ea66edeb5cbeec285c3bf9e3a022f6f49c8f96d5 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 19 Oct 2014 12:29:40 +1100
Subject: [PATCH 155/291] scripts: add dataOutput convenience function
---
src/scripts.js | 5 +++++
test/fixtures/scripts.json | 3 ++-
test/scripts.js | 15 +++++++++++++++
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/src/scripts.js b/src/scripts.js
index b7c4dd596..d768ae2b0 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -241,9 +241,14 @@ function multisigInput(signatures, scriptPubKey) {
return Script.fromChunks([].concat(ops.OP_0, signatures))
}
+function dataOutput(data) {
+ return Script.fromChunks([ops.OP_RETURN, data])
+}
+
module.exports = {
classifyInput: classifyInput,
classifyOutput: classifyOutput,
+ dataOutput: dataOutput,
multisigInput: multisigInput,
multisigOutput: multisigOutput,
pubKeyHashInput: pubKeyHashInput,
diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json
index 4afdc970b..86a7390a0 100644
--- a/test/fixtures/scripts.json
+++ b/test/fixtures/scripts.json
@@ -51,7 +51,8 @@
},
{
"type": "nulldata",
- "scriptPubKey": "OP_RETURN ffffffffffffffffffffffffffffffffffffffff"
+ "data": "deadffffffffffffffffffffffffffffffffbeef",
+ "scriptPubKey": "OP_RETURN deadffffffffffffffffffffffffffffffffbeef"
}
],
"invalid": {
diff --git a/test/scripts.js b/test/scripts.js
index 9709ec9df..60b4026ae 100644
--- a/test/scripts.js
+++ b/test/scripts.js
@@ -184,4 +184,19 @@ describe('Scripts', function() {
})
})
})
+
+ describe('data', function() {
+ fixtures.valid.forEach(function(f) {
+ if (f.type !== 'nulldata') return
+
+ var data = new Buffer(f.data, 'hex')
+ var scriptPubKey = scripts.dataOutput(data)
+
+ describe('output script', function() {
+ it('is generated correctly for ' + f.scriptPubKey, function() {
+ assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
+ })
+ })
+ })
+ })
})
From 43f724cb0b515cefec0ec9afe51fc7658ad31ad1 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 19 Oct 2014 01:10:20 +1100
Subject: [PATCH 156/291] integration tests: add brainwallet/README examples
---
test/integration/brainwallet.js | 31 +++++++++++++++++++++++
test/integration/readme.js | 44 +++++++++++++++++++++++++++++++++
2 files changed, 75 insertions(+)
create mode 100644 test/integration/brainwallet.js
create mode 100644 test/integration/readme.js
diff --git a/test/integration/brainwallet.js b/test/integration/brainwallet.js
new file mode 100644
index 000000000..251696ba0
--- /dev/null
+++ b/test/integration/brainwallet.js
@@ -0,0 +1,31 @@
+var assert = require('assert')
+
+var bigi = require('bigi')
+var bitcoin = require('../../')
+
+describe('bitcoinjs-lib (brainwallet examples)', function() {
+ it('can initialize a ECKey from a sha256 hash', function() {
+ var hash = bitcoin.crypto.sha256('correct horse battery staple')
+ var d = bigi.fromBuffer(hash)
+
+ var key = new bitcoin.ECKey(d)
+
+ assert.equal(key.pub.getAddress().toString(), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8')
+ })
+
+ it('can sign a bitcoin message', function() {
+ var key = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
+ var message = 'This is an example of a signed message.'
+
+ var signature = bitcoin.Message.sign(key, message)
+ assert.equal(signature.toString('base64'), 'G9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk=')
+ })
+
+ it('can verify a bitcoin message', function() {
+ var address = '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN'
+ var signature = 'HJLQlDWLyb1Ef8bQKEISzFbDAKctIlaqOpGbrk3YVtRsjmC61lpE5ErkPRUFtDKtx98vHFGUWlFhsh3DiW6N0rE'
+ var message = 'This is an example of a signed message.'
+
+ assert(bitcoin.Message.verify(address, signature, message))
+ })
+})
diff --git a/test/integration/readme.js b/test/integration/readme.js
new file mode 100644
index 000000000..0a32a0056
--- /dev/null
+++ b/test/integration/readme.js
@@ -0,0 +1,44 @@
+var assert = require('assert')
+
+var bitcoin = require('../../')
+
+describe('bitcoinjs-lib (README)', function() {
+ it('can generate a Bitcoin address from a WIF private key', function() {
+ var key = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
+
+ assert.equal(key.pub.getAddress().toString(), '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31')
+ })
+
+ it('can create a Transaction', function() {
+ var tx = new bitcoin.TransactionBuilder()
+
+ // Add the input (who is paying) of the form [previous transaction hash, index of the output to use]
+ tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0)
+
+ // Add the output (who to pay to) of the form [payee's address, amount in satoshis]
+ tx.addOutput("1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK", 15000)
+
+ // Initialize a private key using WIF
+ var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy")
+
+ // Sign the first input with the new key
+ tx.sign(0, key)
+
+ assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000')
+ })
+
+ it('can create a P2SH Multisig Address', function() {
+ var privKeys = [
+ 'Kwv4iik3zSrMoR8RztogbMzV3i3CFRHjFPyQ8SME88g8c7fB4ouL',
+ 'KyahXPPP45jSmWVSd9687wPhqEAtRZCNfP3ENyZyV7CJ5gWWWWW1',
+ 'KzGaNk5adgZsjfsaWqwrCZhQn63BkQiKUWrCYBLTNspoDZ1d83F3'
+ ].map(bitcoin.ECKey.fromWIF)
+ var pubKeys = privKeys.map(function(x) { return x.pub })
+
+ var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3
+ var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
+ var p2shAddress = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
+
+ assert.equal(p2shAddress, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7')
+ })
+})
From ddc947323e1bde67a003dc0242f57a24e3047c57 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 19 Oct 2014 01:11:19 +1100
Subject: [PATCH 157/291] integration tests: refactor helloblock P2SH spending
test
---
test/integration/helloblock.js | 68 +++++++++++++++++++++++++++++++
test/integration/p2sh.js | 74 ----------------------------------
2 files changed, 68 insertions(+), 74 deletions(-)
create mode 100644 test/integration/helloblock.js
delete mode 100644 test/integration/p2sh.js
diff --git a/test/integration/helloblock.js b/test/integration/helloblock.js
new file mode 100644
index 000000000..7cd04dda0
--- /dev/null
+++ b/test/integration/helloblock.js
@@ -0,0 +1,68 @@
+var assert = require('assert')
+
+var bitcoin = require('../../')
+var networks = bitcoin.networks
+var scripts = bitcoin.scripts
+
+var Address = bitcoin.Address
+var ECKey = bitcoin.ECKey
+var TransactionBuilder = bitcoin.TransactionBuilder
+
+var helloblock = require('helloblock-js')({
+ network: 'testnet'
+})
+
+describe('bitcoinjs-lib (helloblock)', function() {
+ this.timeout(20000)
+
+ it('can spend from a 2-of-2 address', function(done) {
+ var privKeys = [
+ '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx',
+ '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT'
+ ].map(ECKey.fromWIF)
+ var pubKeys = privKeys.map(function(x) { return x.pub })
+
+ var redeemScript = scripts.multisigOutput(2, pubKeys)
+ var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash())
+ var p2shAddress = Address.fromOutputScript(scriptPubKey, networks.testnet).toString()
+
+ // Attempt to send funds to the source address
+ helloblock.faucet.withdraw(p2shAddress, 2e4, function(err) {
+ if (err) return done(err)
+
+ // get latest unspents from the p2shAddress
+ helloblock.addresses.getUnspents(p2shAddress, function(err, res, unspents) {
+ if (err) return done(err)
+
+ // use the oldest unspent
+ var unspent = unspents[unspents.length - 1]
+ var spendAmount = Math.min(unspent.value, 1e4)
+
+ // make a random destination address
+ var targetAddress = ECKey.makeRandom().pub.getAddress(networks.testnet).toString()
+
+ var txb = new TransactionBuilder()
+ txb.addInput(unspent.txHash, unspent.index)
+ txb.addOutput(targetAddress, spendAmount)
+
+ privKeys.forEach(function(privKey) {
+ txb.sign(0, privKey, redeemScript)
+ })
+
+ // broadcast our transaction
+ helloblock.transactions.propagate(txb.build().toHex(), function(err) {
+ // no err means that the transaction has been successfully propagated
+ if (err) return done(err)
+
+ // check that the funds (spendAmount Satoshis) indeed arrived at the intended address
+ helloblock.addresses.get(targetAddress, function(err, res, addrInfo) {
+ if (err) return done(err)
+
+ assert.equal(addrInfo.balance, spendAmount)
+ done()
+ })
+ })
+ })
+ })
+ })
+})
diff --git a/test/integration/p2sh.js b/test/integration/p2sh.js
deleted file mode 100644
index 0b975b6a2..000000000
--- a/test/integration/p2sh.js
+++ /dev/null
@@ -1,74 +0,0 @@
-var assert = require('assert')
-
-var bitcoin = require('../../')
-var networks = bitcoin.networks
-var scripts = bitcoin.scripts
-
-var Address = bitcoin.Address
-var ECKey = bitcoin.ECKey
-var TransactionBuilder = bitcoin.TransactionBuilder
-
-var helloblock = require('helloblock-js')({
- network: 'testnet'
-})
-
-describe('Bitcoin-js', function() {
- this.timeout(10000)
-
- it('can spend from a 2-of-2 address', function(done) {
- var privKeys = [
- '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx',
- '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT'
- ].map(function(wif) {
- return ECKey.fromWIF(wif)
- })
-
- var coldAmount = 2e4
- var outputAmount = 1e4
-
- var pubKeys = privKeys.map(function(eck) { return eck.pub })
- var redeemScript = scripts.multisigOutput(2, pubKeys)
- var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash())
-
- var multisigAddress = Address.fromOutputScript(scriptPubKey, networks.testnet).toString()
-
- // Attempt to send funds to the source address, providing some unspents for later
- helloblock.faucet.withdraw(multisigAddress, coldAmount, function(err) {
- if (err) return done(err)
- })
-
- // make a random private key
- var targetAddress = ECKey.makeRandom().pub.getAddress(networks.testnet).toString()
-
- // get latest unspents from the multisigAddress
- helloblock.addresses.getUnspents(multisigAddress, function(err, res, unspents) {
- if (err) return done(err)
-
- // use the oldest unspent
- var unspent = unspents[unspents.length - 1]
- var spendAmount = Math.min(unspent.value, outputAmount)
-
- var txb = new TransactionBuilder()
- txb.addInput(unspent.txHash, unspent.index)
- txb.addOutput(targetAddress, spendAmount)
-
- privKeys.forEach(function(privKey) {
- txb.sign(0, privKey, redeemScript)
- })
-
- // broadcast our transaction
- helloblock.transactions.propagate(txb.build().toHex(), function(err) {
- // no err means that the transaction has been successfully propagated
- if (err) return done(err)
-
- // Check that the funds (spendAmount Satoshis) indeed arrived at the intended address
- helloblock.addresses.get(targetAddress, function(err, res, addrInfo) {
- if (err) return done(err)
-
- assert.equal(addrInfo.balance, spendAmount)
- done()
- })
- })
- })
- })
-})
From ccd0bb54366b0e7dee3d1fd78adf1bba665d9f69 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 19 Oct 2014 12:29:55 +1100
Subject: [PATCH 158/291] integration tests: add example OP_RETURN transaction
---
test/integration/readme.js | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/test/integration/readme.js b/test/integration/readme.js
index 0a32a0056..cd4bf8cf1 100644
--- a/test/integration/readme.js
+++ b/test/integration/readme.js
@@ -10,21 +10,28 @@ describe('bitcoinjs-lib (README)', function() {
})
it('can create a Transaction', function() {
+ var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy")
var tx = new bitcoin.TransactionBuilder()
- // Add the input (who is paying) of the form [previous transaction hash, index of the output to use]
tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0)
-
- // Add the output (who to pay to) of the form [payee's address, amount in satoshis]
tx.addOutput("1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK", 15000)
+ tx.sign(0, key)
+
+ assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000')
+ })
- // Initialize a private key using WIF
+ it('can create an OP_RETURN transaction', function() {
var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy")
+ var tx = new bitcoin.TransactionBuilder()
+
+ var data = new Buffer('cafedeadbeef', 'hex')
+ var dataScript = bitcoin.scripts.dataOutput(data)
- // Sign the first input with the new key
+ tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0)
+ tx.addOutput(dataScript, 1000)
tx.sign(0, key)
- assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000')
+ assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006a4730440220578f9df41a0e5c5052ad6eef46d005b41f966c7fda01d5f71e9c65026c9025c002202e0159ea0db47ca1bf7713e3a08bbba8cc4fdd90a2eff12591c42049c7cad6c30121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01e803000000000000086a06cafedeadbeef00000000')
})
it('can create a P2SH Multisig Address', function() {
From 6db700c214a470bfd5411ab2b2ee8a60b4ccc2d7 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 19 Oct 2014 13:37:15 +1100
Subject: [PATCH 159/291] integration tests: add stealth address example
---
test/integration/darkwallet.js | 39 ++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 test/integration/darkwallet.js
diff --git a/test/integration/darkwallet.js b/test/integration/darkwallet.js
new file mode 100644
index 000000000..e07b9aad7
--- /dev/null
+++ b/test/integration/darkwallet.js
@@ -0,0 +1,39 @@
+var assert = require('assert')
+
+var bigi = require('bigi')
+var bitcoin = require('../../')
+
+describe('bitcoinjs-lib (darkwallet examples)', function() {
+ it('can generate a single-key stealth address', function() {
+ var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
+ var sender = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') // XXX: ephemeral, must be random to preserve privacy
+
+ var G = bitcoin.ECKey.curve.G
+ var d = receiver.d // secret (receiver only)
+ var Q = receiver.pub.Q // shared
+
+ var e = sender.d // secret (sender only)
+ var P = sender.pub.Q // shared
+
+ // derived shared secret
+ var eQ = Q.multiply(e) // sender
+ var dP = P.multiply(d) // receiver
+ assert.deepEqual(eQ.getEncoded(), dP.getEncoded())
+
+ var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
+ var cG = G.multiply(c)
+
+ // derived public key
+ var QprimeS = Q.add(cG)
+ var QprimeR = G.multiply(d.add(c))
+ assert.deepEqual(QprimeR.getEncoded(), QprimeS.getEncoded())
+
+ // derived shared-secret address
+ var address = new bitcoin.ECPubKey(QprimeS).getAddress().toString()
+
+ assert.equal(address, '1EwCNJNZM5q58YPPTnjR1H5BvYRNeyZi47')
+ })
+
+ // TODO
+ it.skip('can generate a dual-key stealth address', function() {})
+})
From a3a4d2a0d9fd7a6600982a803cf5871c916e3aeb Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 24 Oct 2014 13:58:32 +1100
Subject: [PATCH 160/291] Transaction: re-order functions for consistency
---
src/transaction.js | 240 ++++++++++++++++++++++-----------------------
1 file changed, 120 insertions(+), 120 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index c71d65ad0..bc94d4e80 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -22,6 +22,66 @@ Transaction.SIGHASH_NONE = 0x02
Transaction.SIGHASH_SINGLE = 0x03
Transaction.SIGHASH_ANYONECANPAY = 0x80
+Transaction.fromBuffer = function(buffer) {
+ var offset = 0
+ function readSlice(n) {
+ offset += n
+ return buffer.slice(offset - n, offset)
+ }
+
+ function readUInt32() {
+ var i = buffer.readUInt32LE(offset)
+ offset += 4
+ return i
+ }
+
+ function readUInt64() {
+ var i = bufferutils.readUInt64LE(buffer, offset)
+ offset += 8
+ return i
+ }
+
+ function readVarInt() {
+ var vi = bufferutils.readVarInt(buffer, offset)
+ offset += vi.size
+ return vi.number
+ }
+
+ function readScript() {
+ return Script.fromBuffer(readSlice(readVarInt()))
+ }
+
+ var tx = new Transaction()
+ tx.version = readUInt32()
+
+ var vinLen = readVarInt()
+ for (var i = 0; i < vinLen; ++i) {
+ tx.ins.push({
+ hash: readSlice(32),
+ index: readUInt32(),
+ script: readScript(),
+ sequence: readUInt32()
+ })
+ }
+
+ var voutLen = readVarInt()
+ for (i = 0; i < voutLen; ++i) {
+ tx.outs.push({
+ value: readUInt64(),
+ script: readScript(),
+ })
+ }
+
+ tx.locktime = readUInt32()
+ assert.equal(offset, buffer.length, 'Transaction has unexpected data')
+
+ return tx
+}
+
+Transaction.fromHex = function(hex) {
+ return Transaction.fromBuffer(new Buffer(hex, 'hex'))
+}
+
/**
* Create a new txin.
*
@@ -91,69 +151,28 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) {
}) - 1)
}
-Transaction.prototype.toBuffer = function () {
- var txInSize = this.ins.reduce(function(a, x) {
- return a + (40 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
- }, 0)
-
- var txOutSize = this.outs.reduce(function(a, x) {
- return a + (8 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
- }, 0)
-
- var buffer = new Buffer(
- 8 +
- bufferutils.varIntSize(this.ins.length) +
- bufferutils.varIntSize(this.outs.length) +
- txInSize +
- txOutSize
- )
-
- var offset = 0
- function writeSlice(slice) {
- slice.copy(buffer, offset)
- offset += slice.length
- }
-
- function writeUInt32(i) {
- buffer.writeUInt32LE(i, offset)
- offset += 4
- }
-
- function writeUInt64(i) {
- bufferutils.writeUInt64LE(buffer, i, offset)
- offset += 8
- }
-
- function writeVarInt(i) {
- var n = bufferutils.writeVarInt(buffer, i, offset)
- offset += n
- }
-
- writeUInt32(this.version)
- writeVarInt(this.ins.length)
+Transaction.prototype.clone = function () {
+ var newTx = new Transaction()
+ newTx.version = this.version
+ newTx.locktime = this.locktime
- this.ins.forEach(function(txin) {
- writeSlice(txin.hash)
- writeUInt32(txin.index)
- writeVarInt(txin.script.buffer.length)
- writeSlice(txin.script.buffer)
- writeUInt32(txin.sequence)
+ newTx.ins = this.ins.map(function(txin) {
+ return {
+ hash: txin.hash,
+ index: txin.index,
+ script: txin.script,
+ sequence: txin.sequence
+ }
})
- writeVarInt(this.outs.length)
- this.outs.forEach(function(txout) {
- writeUInt64(txout.value)
- writeVarInt(txout.script.buffer.length)
- writeSlice(txout.script.buffer)
+ newTx.outs = this.outs.map(function(txout) {
+ return {
+ script: txout.script,
+ value: txout.value
+ }
})
- writeUInt32(this.locktime)
-
- return buffer
-}
-
-Transaction.prototype.toHex = function() {
- return this.toBuffer().toString('hex')
+ return newTx
}
/**
@@ -220,88 +239,69 @@ Transaction.prototype.getId = function () {
return bufferutils.reverse(this.getHash()).toString('hex')
}
-Transaction.prototype.clone = function () {
- var newTx = new Transaction()
- newTx.version = this.version
- newTx.locktime = this.locktime
-
- newTx.ins = this.ins.map(function(txin) {
- return {
- hash: txin.hash,
- index: txin.index,
- script: txin.script,
- sequence: txin.sequence
- }
- })
+Transaction.prototype.toBuffer = function () {
+ var txInSize = this.ins.reduce(function(a, x) {
+ return a + (40 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
+ }, 0)
- newTx.outs = this.outs.map(function(txout) {
- return {
- script: txout.script,
- value: txout.value
- }
- })
+ var txOutSize = this.outs.reduce(function(a, x) {
+ return a + (8 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
+ }, 0)
- return newTx
-}
+ var buffer = new Buffer(
+ 8 +
+ bufferutils.varIntSize(this.ins.length) +
+ bufferutils.varIntSize(this.outs.length) +
+ txInSize +
+ txOutSize
+ )
-Transaction.fromBuffer = function(buffer) {
var offset = 0
- function readSlice(n) {
- offset += n
- return buffer.slice(offset - n, offset)
+ function writeSlice(slice) {
+ slice.copy(buffer, offset)
+ offset += slice.length
}
- function readUInt32() {
- var i = buffer.readUInt32LE(offset)
+ function writeUInt32(i) {
+ buffer.writeUInt32LE(i, offset)
offset += 4
- return i
}
- function readUInt64() {
- var i = bufferutils.readUInt64LE(buffer, offset)
+ function writeUInt64(i) {
+ bufferutils.writeUInt64LE(buffer, i, offset)
offset += 8
- return i
}
- function readVarInt() {
- var vi = bufferutils.readVarInt(buffer, offset)
- offset += vi.size
- return vi.number
- }
-
- function readScript() {
- return Script.fromBuffer(readSlice(readVarInt()))
+ function writeVarInt(i) {
+ var n = bufferutils.writeVarInt(buffer, i, offset)
+ offset += n
}
- var tx = new Transaction()
- tx.version = readUInt32()
+ writeUInt32(this.version)
+ writeVarInt(this.ins.length)
- var vinLen = readVarInt()
- for (var i = 0; i < vinLen; ++i) {
- tx.ins.push({
- hash: readSlice(32),
- index: readUInt32(),
- script: readScript(),
- sequence: readUInt32()
- })
- }
+ this.ins.forEach(function(txin) {
+ writeSlice(txin.hash)
+ writeUInt32(txin.index)
+ writeVarInt(txin.script.buffer.length)
+ writeSlice(txin.script.buffer)
+ writeUInt32(txin.sequence)
+ })
- var voutLen = readVarInt()
- for (i = 0; i < voutLen; ++i) {
- tx.outs.push({
- value: readUInt64(),
- script: readScript(),
- })
- }
+ writeVarInt(this.outs.length)
+ this.outs.forEach(function(txout) {
+ writeUInt64(txout.value)
+ writeVarInt(txout.script.buffer.length)
+ writeSlice(txout.script.buffer)
+ })
- tx.locktime = readUInt32()
- assert.equal(offset, buffer.length, 'Transaction has unexpected data')
+ writeUInt32(this.locktime)
- return tx
+ return buffer
}
-Transaction.fromHex = function(hex) {
- return Transaction.fromBuffer(new Buffer(hex, 'hex'))
+Transaction.prototype.toHex = function() {
+ return this.toBuffer().toString('hex')
}
Transaction.prototype.setInputScript = function(index, script) {
From 4283fc26f8634e1e32c6270acbe7c47651e1d0aa Mon Sep 17 00:00:00 2001
From: Jonygame
Date: Fri, 24 Oct 2014 19:30:38 +0200
Subject: [PATCH 161/291] Added Gamerscoin Support
---
src/networks.js | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/src/networks.js b/src/networks.js
index 4d4948533..4756d7ff3 100644
--- a/src/networks.js
+++ b/src/networks.js
@@ -15,6 +15,20 @@ var networks = {
feePerKb: 10000, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/main.cpp#L53
estimateFee: estimateFee('bitcoin')
},
+ gamerscoin: {
+ magicPrefix: '\x19Gamerscoin Signed Message:\n',
+ bip32: {
+ public: 0x019da462,
+ private: 0x019d9cfe
+ },
+ pubKeyHash: 0x26,
+ scriptHash: 0x05,
+ wif: 0xA6,
+ dustThreshold: 0, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L358-L363
+ dustSoftThreshold: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L51
+ feePerKb: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L54
+ estimateFee: estimateFee('gamerscoin')
+ },
dogecoin: {
magicPrefix: '\x19Dogecoin Signed Message:\n',
bip32: {
From 5ee3203473a018bea34e8b731643a9ecd106a0ca Mon Sep 17 00:00:00 2001
From: Julian Yap
Date: Sun, 16 Nov 2014 02:29:55 -1000
Subject: [PATCH 162/291] Add Jumbucks support
---
src/networks.js | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/src/networks.js b/src/networks.js
index 4756d7ff3..25d3baf91 100644
--- a/src/networks.js
+++ b/src/networks.js
@@ -98,6 +98,20 @@ var networks = {
feePerKb: 100000,
estimateFee: estimateFee('viacointestnet')
},
+ jumbucks: {
+ magicPrefix: '\x19Jumbucks Signed Message:\n',
+ bip32: {
+ public: 0x037a689a,
+ private: 0x037a6460
+ },
+ pubKeyHash: 0x2b,
+ scriptHash: 0x05,
+ wif: 0xab,
+ dustThreshold: 0,
+ dustSoftThreshold: 10000,
+ feePerKb: 10000,
+ estimateFee: estimateFee('jumbucks')
+ },
zetacoin: {
magicPrefix: '\x18Zetacoin Signed Message:\n',
bip32: {
From a6febb0bedcfff2228f33170e042e75d8c2410db Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 24 Nov 2014 21:02:19 +1100
Subject: [PATCH 163/291] integration tests: add more basic examples
---
test/integration/readme.js | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/test/integration/readme.js b/test/integration/readme.js
index cd4bf8cf1..524ab3ea5 100644
--- a/test/integration/readme.js
+++ b/test/integration/readme.js
@@ -1,12 +1,27 @@
var assert = require('assert')
var bitcoin = require('../../')
+var crypto = require('crypto')
+var sinon = require('sinon')
describe('bitcoinjs-lib (README)', function() {
- it('can generate a Bitcoin address from a WIF private key', function() {
+ it('can generate a random bitcoin address', sinon.test(function() {
+ // for testing only
+ this.mock(crypto).expects('randomBytes')
+ .onCall(0).returns(new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'))
+
+ // generate random key
+ var key = bitcoin.ECKey.makeRandom()
+ var address = key.pub.getAddress().toString()
+
+ assert.equal(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64')
+ }))
+
+ it('can import a WIF encoded private key', function() {
var key = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
+ var address = key.pub.getAddress().toString()
- assert.equal(key.pub.getAddress().toString(), '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31')
+ assert.equal(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31')
})
it('can create a Transaction', function() {
@@ -35,17 +50,16 @@ describe('bitcoinjs-lib (README)', function() {
})
it('can create a P2SH Multisig Address', function() {
- var privKeys = [
- 'Kwv4iik3zSrMoR8RztogbMzV3i3CFRHjFPyQ8SME88g8c7fB4ouL',
- 'KyahXPPP45jSmWVSd9687wPhqEAtRZCNfP3ENyZyV7CJ5gWWWWW1',
- 'KzGaNk5adgZsjfsaWqwrCZhQn63BkQiKUWrCYBLTNspoDZ1d83F3'
- ].map(bitcoin.ECKey.fromWIF)
- var pubKeys = privKeys.map(function(x) { return x.pub })
+ var pubKeys = [
+ '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
+ '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
+ '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9'
+ ].map(bitcoin.ECPubKey.fromHex)
var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3
var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
- var p2shAddress = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
+ var address = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
- assert.equal(p2shAddress, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7')
+ assert.equal(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7')
})
})
From f81a47a8b93d7906c37dd459c80fa7fe33e6ced3 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 24 Nov 2014 21:15:28 +1100
Subject: [PATCH 164/291] integration tests: rename all files to
basic/advanced/multisig
---
test/integration/advanced.js | 71 ++++++++++++++++++++++
test/integration/{readme.js => basic.js} | 40 ++++---------
test/integration/brainwallet.js | 31 ----------
test/integration/darkwallet.js | 39 ------------
test/integration/helloblock.js | 68 ---------------------
test/integration/multisig.js | 76 ++++++++++++++++++++++++
6 files changed, 158 insertions(+), 167 deletions(-)
create mode 100644 test/integration/advanced.js
rename test/integration/{readme.js => basic.js} (51%)
delete mode 100644 test/integration/brainwallet.js
delete mode 100644 test/integration/darkwallet.js
delete mode 100644 test/integration/helloblock.js
create mode 100644 test/integration/multisig.js
diff --git a/test/integration/advanced.js b/test/integration/advanced.js
new file mode 100644
index 000000000..da2e7fd8b
--- /dev/null
+++ b/test/integration/advanced.js
@@ -0,0 +1,71 @@
+var assert = require('assert')
+
+var bigi = require('bigi')
+var bitcoin = require('../../')
+
+describe('bitcoinjs-lib (advanced)', function() {
+ it('can sign a bitcoin message', function() {
+ var key = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
+ var message = 'This is an example of a signed message.'
+
+ var signature = bitcoin.Message.sign(key, message)
+ assert.equal(signature.toString('base64'), 'G9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk=')
+ })
+
+ it('can verify a bitcoin message', function() {
+ var address = '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN'
+ var signature = 'HJLQlDWLyb1Ef8bQKEISzFbDAKctIlaqOpGbrk3YVtRsjmC61lpE5ErkPRUFtDKtx98vHFGUWlFhsh3DiW6N0rE'
+ var message = 'This is an example of a signed message.'
+
+ assert(bitcoin.Message.verify(address, signature, message))
+ })
+
+ it('can generate a single-key stealth address', function() {
+ var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
+
+ // XXX: ephemeral, must be random (and secret to sender) to preserve privacy
+ var sender = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
+
+ var G = bitcoin.ECKey.curve.G
+ var d = receiver.d // secret (receiver only)
+ var Q = receiver.pub.Q // shared
+
+ var e = sender.d // secret (sender only)
+ var P = sender.pub.Q // shared
+
+ // derived shared secret
+ var eQ = Q.multiply(e) // sender
+ var dP = P.multiply(d) // receiver
+ assert.deepEqual(eQ.getEncoded(), dP.getEncoded())
+
+ var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
+ var cG = G.multiply(c)
+
+ // derived public key
+ var QprimeS = Q.add(cG)
+ var QprimeR = G.multiply(d.add(c))
+ assert.deepEqual(QprimeR.getEncoded(), QprimeS.getEncoded())
+
+ // derived shared-secret address
+ var address = new bitcoin.ECPubKey(QprimeS).getAddress().toString()
+
+ assert.equal(address, '1EwCNJNZM5q58YPPTnjR1H5BvYRNeyZi47')
+ })
+
+ // TODO
+ it.skip('can generate a dual-key stealth address', function() {})
+
+ it('can create an OP_RETURN transaction', function() {
+ var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy")
+ var tx = new bitcoin.TransactionBuilder()
+
+ var data = new Buffer('cafedeadbeef', 'hex')
+ var dataScript = bitcoin.scripts.dataOutput(data)
+
+ tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0)
+ tx.addOutput(dataScript, 1000)
+ tx.sign(0, key)
+
+ assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006a4730440220578f9df41a0e5c5052ad6eef46d005b41f966c7fda01d5f71e9c65026c9025c002202e0159ea0db47ca1bf7713e3a08bbba8cc4fdd90a2eff12591c42049c7cad6c30121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01e803000000000000086a06cafedeadbeef00000000')
+ })
+})
diff --git a/test/integration/readme.js b/test/integration/basic.js
similarity index 51%
rename from test/integration/readme.js
rename to test/integration/basic.js
index 524ab3ea5..2066b557e 100644
--- a/test/integration/readme.js
+++ b/test/integration/basic.js
@@ -1,10 +1,11 @@
var assert = require('assert')
+var bigi = require('bigi')
var bitcoin = require('../../')
var crypto = require('crypto')
var sinon = require('sinon')
-describe('bitcoinjs-lib (README)', function() {
+describe('bitcoinjs-lib (basic)', function() {
it('can generate a random bitcoin address', sinon.test(function() {
// for testing only
this.mock(crypto).expects('randomBytes')
@@ -17,6 +18,15 @@ describe('bitcoinjs-lib (README)', function() {
assert.equal(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64')
}))
+ it('can initialize a ECKey from a sha256 hash', function() {
+ var hash = bitcoin.crypto.sha256('correct horse battery staple')
+ var d = bigi.fromBuffer(hash)
+
+ var key = new bitcoin.ECKey(d)
+
+ assert.equal(key.pub.getAddress().toString(), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8')
+ })
+
it('can import a WIF encoded private key', function() {
var key = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
var address = key.pub.getAddress().toString()
@@ -34,32 +44,4 @@ describe('bitcoinjs-lib (README)', function() {
assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000')
})
-
- it('can create an OP_RETURN transaction', function() {
- var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy")
- var tx = new bitcoin.TransactionBuilder()
-
- var data = new Buffer('cafedeadbeef', 'hex')
- var dataScript = bitcoin.scripts.dataOutput(data)
-
- tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0)
- tx.addOutput(dataScript, 1000)
- tx.sign(0, key)
-
- assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006a4730440220578f9df41a0e5c5052ad6eef46d005b41f966c7fda01d5f71e9c65026c9025c002202e0159ea0db47ca1bf7713e3a08bbba8cc4fdd90a2eff12591c42049c7cad6c30121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01e803000000000000086a06cafedeadbeef00000000')
- })
-
- it('can create a P2SH Multisig Address', function() {
- var pubKeys = [
- '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
- '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
- '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9'
- ].map(bitcoin.ECPubKey.fromHex)
-
- var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3
- var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
- var address = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
-
- assert.equal(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7')
- })
})
diff --git a/test/integration/brainwallet.js b/test/integration/brainwallet.js
deleted file mode 100644
index 251696ba0..000000000
--- a/test/integration/brainwallet.js
+++ /dev/null
@@ -1,31 +0,0 @@
-var assert = require('assert')
-
-var bigi = require('bigi')
-var bitcoin = require('../../')
-
-describe('bitcoinjs-lib (brainwallet examples)', function() {
- it('can initialize a ECKey from a sha256 hash', function() {
- var hash = bitcoin.crypto.sha256('correct horse battery staple')
- var d = bigi.fromBuffer(hash)
-
- var key = new bitcoin.ECKey(d)
-
- assert.equal(key.pub.getAddress().toString(), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8')
- })
-
- it('can sign a bitcoin message', function() {
- var key = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
- var message = 'This is an example of a signed message.'
-
- var signature = bitcoin.Message.sign(key, message)
- assert.equal(signature.toString('base64'), 'G9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk=')
- })
-
- it('can verify a bitcoin message', function() {
- var address = '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN'
- var signature = 'HJLQlDWLyb1Ef8bQKEISzFbDAKctIlaqOpGbrk3YVtRsjmC61lpE5ErkPRUFtDKtx98vHFGUWlFhsh3DiW6N0rE'
- var message = 'This is an example of a signed message.'
-
- assert(bitcoin.Message.verify(address, signature, message))
- })
-})
diff --git a/test/integration/darkwallet.js b/test/integration/darkwallet.js
deleted file mode 100644
index e07b9aad7..000000000
--- a/test/integration/darkwallet.js
+++ /dev/null
@@ -1,39 +0,0 @@
-var assert = require('assert')
-
-var bigi = require('bigi')
-var bitcoin = require('../../')
-
-describe('bitcoinjs-lib (darkwallet examples)', function() {
- it('can generate a single-key stealth address', function() {
- var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
- var sender = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') // XXX: ephemeral, must be random to preserve privacy
-
- var G = bitcoin.ECKey.curve.G
- var d = receiver.d // secret (receiver only)
- var Q = receiver.pub.Q // shared
-
- var e = sender.d // secret (sender only)
- var P = sender.pub.Q // shared
-
- // derived shared secret
- var eQ = Q.multiply(e) // sender
- var dP = P.multiply(d) // receiver
- assert.deepEqual(eQ.getEncoded(), dP.getEncoded())
-
- var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
- var cG = G.multiply(c)
-
- // derived public key
- var QprimeS = Q.add(cG)
- var QprimeR = G.multiply(d.add(c))
- assert.deepEqual(QprimeR.getEncoded(), QprimeS.getEncoded())
-
- // derived shared-secret address
- var address = new bitcoin.ECPubKey(QprimeS).getAddress().toString()
-
- assert.equal(address, '1EwCNJNZM5q58YPPTnjR1H5BvYRNeyZi47')
- })
-
- // TODO
- it.skip('can generate a dual-key stealth address', function() {})
-})
diff --git a/test/integration/helloblock.js b/test/integration/helloblock.js
deleted file mode 100644
index 7cd04dda0..000000000
--- a/test/integration/helloblock.js
+++ /dev/null
@@ -1,68 +0,0 @@
-var assert = require('assert')
-
-var bitcoin = require('../../')
-var networks = bitcoin.networks
-var scripts = bitcoin.scripts
-
-var Address = bitcoin.Address
-var ECKey = bitcoin.ECKey
-var TransactionBuilder = bitcoin.TransactionBuilder
-
-var helloblock = require('helloblock-js')({
- network: 'testnet'
-})
-
-describe('bitcoinjs-lib (helloblock)', function() {
- this.timeout(20000)
-
- it('can spend from a 2-of-2 address', function(done) {
- var privKeys = [
- '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx',
- '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT'
- ].map(ECKey.fromWIF)
- var pubKeys = privKeys.map(function(x) { return x.pub })
-
- var redeemScript = scripts.multisigOutput(2, pubKeys)
- var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash())
- var p2shAddress = Address.fromOutputScript(scriptPubKey, networks.testnet).toString()
-
- // Attempt to send funds to the source address
- helloblock.faucet.withdraw(p2shAddress, 2e4, function(err) {
- if (err) return done(err)
-
- // get latest unspents from the p2shAddress
- helloblock.addresses.getUnspents(p2shAddress, function(err, res, unspents) {
- if (err) return done(err)
-
- // use the oldest unspent
- var unspent = unspents[unspents.length - 1]
- var spendAmount = Math.min(unspent.value, 1e4)
-
- // make a random destination address
- var targetAddress = ECKey.makeRandom().pub.getAddress(networks.testnet).toString()
-
- var txb = new TransactionBuilder()
- txb.addInput(unspent.txHash, unspent.index)
- txb.addOutput(targetAddress, spendAmount)
-
- privKeys.forEach(function(privKey) {
- txb.sign(0, privKey, redeemScript)
- })
-
- // broadcast our transaction
- helloblock.transactions.propagate(txb.build().toHex(), function(err) {
- // no err means that the transaction has been successfully propagated
- if (err) return done(err)
-
- // check that the funds (spendAmount Satoshis) indeed arrived at the intended address
- helloblock.addresses.get(targetAddress, function(err, res, addrInfo) {
- if (err) return done(err)
-
- assert.equal(addrInfo.balance, spendAmount)
- done()
- })
- })
- })
- })
- })
-})
diff --git a/test/integration/multisig.js b/test/integration/multisig.js
new file mode 100644
index 000000000..05bec9edf
--- /dev/null
+++ b/test/integration/multisig.js
@@ -0,0 +1,76 @@
+var assert = require('assert')
+
+var bitcoin = require('../../')
+
+var helloblock = require('helloblock-js')({
+ network: 'testnet'
+})
+
+describe('bitcoinjs-lib (multisig)', function() {
+ it('can create a 2-of-3 multisig P2SH address', function() {
+ var pubKeys = [
+ '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
+ '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
+ '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9'
+ ].map(bitcoin.ECPubKey.fromHex)
+
+ var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3
+ var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
+ var address = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
+
+ assert.equal(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7')
+ })
+
+ it('can spend from a 2-of-2 multsig P2SH address', function(done) {
+ var privKeys = [
+ '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx',
+ '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT'
+ ].map(bitcoin.ECKey.fromWIF)
+ var pubKeys = privKeys.map(function(x) { return x.pub })
+
+ var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 2
+ var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
+ var address = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
+
+ // Attempt to send funds to the source address
+ helloblock.faucet.withdraw(address, 2e4, function(err) {
+ if (err) return done(err)
+
+ // get latest unspents from the address
+ helloblock.addresses.getUnspents(address, function(err, res, unspents) {
+ if (err) return done(err)
+
+ // filter small unspents
+ unspents = unspents.filter(function(unspent) { return unspent.value > 1e4 })
+
+ // use the oldest unspent
+ var unspent = unspents.pop()
+
+ // make a random destination address
+ var targetAddress = bitcoin.ECKey.makeRandom().pub.getAddress(bitcoin.networks.testnet).toString()
+
+ var txb = new bitcoin.TransactionBuilder()
+ txb.addInput(unspent.txHash, unspent.index)
+ txb.addOutput(targetAddress, 1e4)
+
+ // sign w/ each private key
+ privKeys.forEach(function(privKey) {
+ txb.sign(0, privKey, redeemScript)
+ })
+
+ // broadcast our transaction
+ helloblock.transactions.propagate(txb.build().toHex(), function(err) {
+ if (err) return done(err)
+
+ // check that the funds (1e4 Satoshis) indeed arrived at the intended address
+ helloblock.addresses.get(targetAddress, function(err, res, addrInfo) {
+ if (err) return done(err)
+
+ assert.equal(addrInfo.balance, 1e4)
+ done()
+ })
+ })
+ })
+ })
+ })
+})
From ec517376c257b1274a59f97ee8a46579031ddecc Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 25 Nov 2014 14:07:30 +1100
Subject: [PATCH 165/291] integration tests: test description rephrasing
---
test/integration/advanced.js | 4 ++--
test/integration/basic.js | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/integration/advanced.js b/test/integration/advanced.js
index da2e7fd8b..6fd0d7266 100644
--- a/test/integration/advanced.js
+++ b/test/integration/advanced.js
@@ -4,7 +4,7 @@ var bigi = require('bigi')
var bitcoin = require('../../')
describe('bitcoinjs-lib (advanced)', function() {
- it('can sign a bitcoin message', function() {
+ it('can sign a Bitcoin message', function() {
var key = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
var message = 'This is an example of a signed message.'
@@ -12,7 +12,7 @@ describe('bitcoinjs-lib (advanced)', function() {
assert.equal(signature.toString('base64'), 'G9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk=')
})
- it('can verify a bitcoin message', function() {
+ it('can verify a Bitcoin message', function() {
var address = '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN'
var signature = 'HJLQlDWLyb1Ef8bQKEISzFbDAKctIlaqOpGbrk3YVtRsjmC61lpE5ErkPRUFtDKtx98vHFGUWlFhsh3DiW6N0rE'
var message = 'This is an example of a signed message.'
diff --git a/test/integration/basic.js b/test/integration/basic.js
index 2066b557e..c14c3c916 100644
--- a/test/integration/basic.js
+++ b/test/integration/basic.js
@@ -18,7 +18,7 @@ describe('bitcoinjs-lib (basic)', function() {
assert.equal(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64')
}))
- it('can initialize a ECKey from a sha256 hash', function() {
+ it('can generate an address from a SHA256 hash', function() {
var hash = bitcoin.crypto.sha256('correct horse battery staple')
var d = bigi.fromBuffer(hash)
@@ -27,7 +27,7 @@ describe('bitcoinjs-lib (basic)', function() {
assert.equal(key.pub.getAddress().toString(), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8')
})
- it('can import a WIF encoded private key', function() {
+ it('can import an address via WIF', function() {
var key = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
var address = key.pub.getAddress().toString()
From d9c716cc293b11eb606acb7d154072b1bcd8f1c0 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 25 Nov 2014 14:07:40 +1100
Subject: [PATCH 166/291] README: remove examples and link to integration tests
---
README.md | 73 +++++++++++--------------------------------------------
1 file changed, 14 insertions(+), 59 deletions(-)
diff --git a/README.md b/README.md
index 133b082e7..13f4a9b7c 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ A continued implementation of the original `0.1.3` version used by over a millio
## Should I use this in production?
+
If you are thinking of using the master branch of this library in production, *stop*.
Master is not stable; it is our development branch, and only tagged releases may be classified as stable.
@@ -64,73 +65,27 @@ From NPM:
After loading this file in your browser, you will be able to use the global `bitcoin` object.
-## Usage
-
-These examples assume you are running bitcoinjs-lib in the browser.
-
-
-### Generating a Bitcoin address
-
-```javascript
-
-key = bitcoin.ECKey.makeRandom()
-
-// Print your private key (in WIF format)
-console.log(key.toWIF())
-// => Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct
-
-// Print your public key (toString defaults to a Bitcoin address)
-console.log(key.pub.getAddress().toString())
-// => 14bZ7YWde4KdRb5YN7GYkToz3EHVCvRxkF
-```
-
-
-### Creating a Transaction
-
-```javascript
-tx = new bitcoin.Transaction()
+## Examples
-// Add the input (who is paying) of the form [previous transaction hash, index of the output to use]
-tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0)
+The below examples are implemented as integration tests, but should be very easy to follow. Pull requests welcome.
-// Add the output (who to pay to) of the form [payee's address, amount in satoshis]
-tx.addOutput("1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK", 15000)
+- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L9)
+- [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L21)
+- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L30)
+- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L37)
-// Initialize a private key using WIF
-key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy")
+- [Sign a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L7)
+- [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L15)
+- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L23)
+- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L56)
+- [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L58)
-// Sign the first input with the new key
-tx.sign(0, key)
-
-// Print transaction serialized as hex
-console.log(tx.toHex())
-// => 0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000008a47304402200169f1f844936dc60df54e812345f5dd3e6681fea52e33c25154ad9cc23a330402204381ed8e73d74a95b15f312f33d5a0072c7a12dd6c3294df6e8efbe4aff27426014104e75628573696aed32d7656fb35e9c71ea08eb6492837e13d2662b9a36821d0fff992692fd14d74fdec20fae29128ba12653249cbeef521fc5eba84dde0689f27ffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000
-
-// You could now push the transaction onto the Bitcoin network manually (see https://blockchain.info/pushtx)
-```
-
-
-### Creating a P2SH Multisig Address
-
-``` javascript
-var bitcoin = require('bitcoinjs-lib')
-
-var privKeys = [bitcoin.ECKey.makeRandom(), bitcoin.ECKey.makeRandom(), bitcoin.ECKey.makeRandom()]
-var pubKeys = privKeys.map(function(x) { return x.pub })
-
-var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3
-var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
-
-var multisigAddress = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
-
-console.log("multisigP2SH:", multisigAddress)
-// => multisigP2SH: 35k9EWv2F1X5JKXHSF1DhTm7Ybdiwx4RkD
-```
+- [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/multisig.js#L10)
+- [Spend from a 2-of-2 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/multisig.js#L24)
## Projects utilizing BitcoinJS
-
- [BitAddress](https://www.bitaddress.org)
- [Blockchain.info](https://blockchain.info/wallet)
- [Brainwallet](https://brainwallet.github.io)
From 67e97f70d422b0fd613130c577584c550e2b57bf Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 25 Nov 2014 14:21:10 +1100
Subject: [PATCH 167/291] integration tests: fix 2-of-2 spend address network
---
test/integration/basic.js | 1 -
test/integration/multisig.js | 6 ++----
2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/test/integration/basic.js b/test/integration/basic.js
index c14c3c916..8e0b3d86a 100644
--- a/test/integration/basic.js
+++ b/test/integration/basic.js
@@ -1,5 +1,4 @@
var assert = require('assert')
-
var bigi = require('bigi')
var bitcoin = require('../../')
var crypto = require('crypto')
diff --git a/test/integration/multisig.js b/test/integration/multisig.js
index 05bec9edf..13fb115e4 100644
--- a/test/integration/multisig.js
+++ b/test/integration/multisig.js
@@ -1,7 +1,5 @@
var assert = require('assert')
-
var bitcoin = require('../../')
-
var helloblock = require('helloblock-js')({
network: 'testnet'
})
@@ -30,14 +28,14 @@ describe('bitcoinjs-lib (multisig)', function() {
var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 2
var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
- var address = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
+ var address = bitcoin.Address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet).toString()
// Attempt to send funds to the source address
helloblock.faucet.withdraw(address, 2e4, function(err) {
if (err) return done(err)
// get latest unspents from the address
- helloblock.addresses.getUnspents(address, function(err, res, unspents) {
+ helloblock.addresses.getUnspents(address, function(err, _, unspents) {
if (err) return done(err)
// filter small unspents
From 37a1c93d8af94d40503de9aa53950a9c524b6ab7 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 25 Nov 2014 14:21:48 +1100
Subject: [PATCH 168/291] integration tests: merge #312 test equivalent
---
test/integration/advanced.js | 55 ++++++++++++++++++++++++++++++------
1 file changed, 46 insertions(+), 9 deletions(-)
diff --git a/test/integration/advanced.js b/test/integration/advanced.js
index 6fd0d7266..f4479a5e1 100644
--- a/test/integration/advanced.js
+++ b/test/integration/advanced.js
@@ -1,7 +1,9 @@
var assert = require('assert')
-
var bigi = require('bigi')
var bitcoin = require('../../')
+var helloblock = require('helloblock-js')({
+ network: 'testnet'
+})
describe('bitcoinjs-lib (advanced)', function() {
it('can sign a Bitcoin message', function() {
@@ -55,17 +57,52 @@ describe('bitcoinjs-lib (advanced)', function() {
// TODO
it.skip('can generate a dual-key stealth address', function() {})
- it('can create an OP_RETURN transaction', function() {
+ it('can create an OP_RETURN transaction', function(done) {
+ this.timeout(20000)
+
var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy")
- var tx = new bitcoin.TransactionBuilder()
+ var address = key.pub.getAddress(bitcoin.networks.testnet).toString()
+
+ helloblock.faucet.withdraw(address, 2e4, function(err) {
+ if (err) return done(err)
+
+ helloblock.addresses.getUnspents(address, function(err, _, unspents) {
+ if (err) return done(err)
+
+ // filter small unspents
+ unspents = unspents.filter(function(unspent) { return unspent.value > 1e4 })
+
+ // use the oldest unspent
+ var unspent = unspents.pop()
+
+ var tx = new bitcoin.TransactionBuilder()
+
+ var data = new Buffer('cafedeadbeef', 'hex')
+ var dataScript = bitcoin.scripts.dataOutput(data)
+
+ tx.addInput(unspent.txHash, unspent.index)
+ tx.addOutput(dataScript, 1000)
+ tx.sign(0, key)
+
+ helloblock.transactions.propagate(tx.build().toHex(), function(err) {
+ if (err) return done(err)
+
+ // check that the message was propagated
+ helloblock.addresses.getTransactions(address, function(err, res, transactions) {
+ if (err) return done(err)
- var data = new Buffer('cafedeadbeef', 'hex')
- var dataScript = bitcoin.scripts.dataOutput(data)
+ var transaction = transactions[0]
+ var output = transaction.outputs[0]
+ var dataScript2 = bitcoin.Script.fromHex(output.scriptPubKey)
+ var data2 = dataScript2.chunks[1]
- tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0)
- tx.addOutput(dataScript, 1000)
- tx.sign(0, key)
+ assert.deepEqual(dataScript, dataScript2)
+ assert.deepEqual(data, data2)
- assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006a4730440220578f9df41a0e5c5052ad6eef46d005b41f966c7fda01d5f71e9c65026c9025c002202e0159ea0db47ca1bf7713e3a08bbba8cc4fdd90a2eff12591c42049c7cad6c30121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01e803000000000000086a06cafedeadbeef00000000')
+ done()
+ })
+ })
+ })
+ })
})
})
From 7e7071b1859a33c9da7ca8d912de770498860a18 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 25 Nov 2014 14:24:05 +1100
Subject: [PATCH 169/291] integration tests: add timeout for 2-of-2 spend
---
test/integration/multisig.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/test/integration/multisig.js b/test/integration/multisig.js
index 13fb115e4..60f46c9ad 100644
--- a/test/integration/multisig.js
+++ b/test/integration/multisig.js
@@ -20,6 +20,8 @@ describe('bitcoinjs-lib (multisig)', function() {
})
it('can spend from a 2-of-2 multsig P2SH address', function(done) {
+ this.timeout(20000)
+
var privKeys = [
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx',
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT'
From 126567b56d1ea30a68314aaf044a062aedb42b7f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 25 Nov 2014 14:30:55 +1100
Subject: [PATCH 170/291] README: fix test line numbers
---
README.md | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/README.md b/README.md
index 13f4a9b7c..0bdb1fcec 100644
--- a/README.md
+++ b/README.md
@@ -69,19 +69,17 @@ After loading this file in your browser, you will be able to use the global `bit
The below examples are implemented as integration tests, but should be very easy to follow. Pull requests welcome.
-- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L9)
-- [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L21)
-- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L30)
-- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L37)
-
-- [Sign a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L7)
-- [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L15)
-- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L23)
-- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L56)
-- [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L58)
-
-- [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/multisig.js#L10)
-- [Spend from a 2-of-2 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/multisig.js#L24)
+- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L8)
+- [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L20)
+- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L29)
+- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L36)
+- [Sign a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L9)
+- [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L17)
+- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L25)
+- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L58)
+- [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L60)
+- [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/multisig.js#L8)
+- [Spend from a 2-of-2 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/multisig.js#L22)
## Projects utilizing BitcoinJS
From e547ea3140a1ac107468677ff94108aee5d3dcf3 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 25 Nov 2014 14:32:47 +1100
Subject: [PATCH 171/291] README: s/inttests/master/
---
README.md | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 0bdb1fcec..e64353e1e 100644
--- a/README.md
+++ b/README.md
@@ -69,17 +69,17 @@ After loading this file in your browser, you will be able to use the global `bit
The below examples are implemented as integration tests, but should be very easy to follow. Pull requests welcome.
-- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L8)
-- [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L20)
-- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L29)
-- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/basic.js#L36)
-- [Sign a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L9)
-- [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L17)
-- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L25)
-- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L58)
-- [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/advanced.js#L60)
-- [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/multisig.js#L8)
-- [Spend from a 2-of-2 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/inttests/test/integration/multisig.js#L22)
+- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L8)
+- [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L20)
+- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L29)
+- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L36)
+- [Sign a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L9)
+- [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L17)
+- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L25)
+- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L58)
+- [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L60)
+- [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L8)
+- [Spend from a 2-of-2 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L22)
## Projects utilizing BitcoinJS
From 78d26c2e26cbba372a8938374de9c563b2ab6ca6 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 25 Nov 2014 14:57:51 +1100
Subject: [PATCH 172/291] Wallet: add 2.0.0 deprecation message
---
src/wallet.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/wallet.js b/src/wallet.js
index 799bc8118..f7068ff29 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -10,6 +10,8 @@ var TransactionBuilder = require('./transaction_builder')
var Script = require('./script')
function Wallet(seed, network) {
+ console.warn('Wallet is deprecated and will be removed in 2.0.0, see #296')
+
seed = seed || crypto.randomBytes(32)
network = network || networks.bitcoin
From d869d6d7a7ac8b8a60d37dc2976988b70837369e Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 26 Nov 2014 14:21:51 +1100
Subject: [PATCH 173/291] 1.3.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 5ee2ec037..51e251e3c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.2.0",
+ "version": "1.3.0",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 5a1aef363225e1f6ab34c95b4c2f0b74cb37da1f Mon Sep 17 00:00:00 2001
From: John Russell
Date: Wed, 26 Nov 2014 10:05:18 -0800
Subject: [PATCH 174/291] Add Robocoin to projects utilizing BitcoinJS
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index e64353e1e..ab345d194 100644
--- a/README.md
+++ b/README.md
@@ -96,6 +96,7 @@ The below examples are implemented as integration tests, but should be very easy
- [Hive Wallet](https://www.hivewallet.com)
- [Justchain Exchange](https://justcoin.com)
- [QuickCoin](https://wallet.quickcoin.co)
+- [Robocoin](https://wallet.robocoin.com)
- [Skyhook ATM](http://projectskyhook.com)
From c00be27192d72f53cc1aed4920a37507246d8037 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 27 Nov 2014 16:29:24 +1100
Subject: [PATCH 175/291] networks: prioritize bitcoin/testnet
---
src/networks.js | 72 ++++++++++++++++++++++++-------------------------
1 file changed, 36 insertions(+), 36 deletions(-)
diff --git a/src/networks.js b/src/networks.js
index 25d3baf91..db5aab6ee 100644
--- a/src/networks.js
+++ b/src/networks.js
@@ -15,33 +15,18 @@ var networks = {
feePerKb: 10000, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/main.cpp#L53
estimateFee: estimateFee('bitcoin')
},
- gamerscoin: {
- magicPrefix: '\x19Gamerscoin Signed Message:\n',
- bip32: {
- public: 0x019da462,
- private: 0x019d9cfe
- },
- pubKeyHash: 0x26,
- scriptHash: 0x05,
- wif: 0xA6,
- dustThreshold: 0, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L358-L363
- dustSoftThreshold: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L51
- feePerKb: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L54
- estimateFee: estimateFee('gamerscoin')
- },
- dogecoin: {
- magicPrefix: '\x19Dogecoin Signed Message:\n',
+ testnet: {
+ magicPrefix: '\x18Bitcoin Signed Message:\n',
bip32: {
- public: 0x02facafd,
- private: 0x02fac398
+ public: 0x043587cf,
+ private: 0x04358394
},
- pubKeyHash: 0x1e,
- scriptHash: 0x16,
- wif: 0x9e,
- dustThreshold: 0, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160
- dustSoftThreshold: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.h#L62
- feePerKb: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.cpp#L58
- estimateFee: estimateFee('dogecoin')
+ pubKeyHash: 0x6f,
+ scriptHash: 0xc4,
+ wif: 0xef,
+ dustThreshold: 546,
+ feePerKb: 10000,
+ estimateFee: estimateFee('testnet')
},
litecoin: {
magicPrefix: '\x19Litecoin Signed Message:\n',
@@ -57,18 +42,19 @@ var networks = {
feePerKb: 100000, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L56
estimateFee: estimateFee('litecoin')
},
- testnet: {
- magicPrefix: '\x18Bitcoin Signed Message:\n',
+ dogecoin: {
+ magicPrefix: '\x19Dogecoin Signed Message:\n',
bip32: {
- public: 0x043587cf,
- private: 0x04358394
+ public: 0x02facafd,
+ private: 0x02fac398
},
- pubKeyHash: 0x6f,
- scriptHash: 0xc4,
- wif: 0xef,
- dustThreshold: 546,
- feePerKb: 10000,
- estimateFee: estimateFee('testnet')
+ pubKeyHash: 0x1e,
+ scriptHash: 0x16,
+ wif: 0x9e,
+ dustThreshold: 0, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160
+ dustSoftThreshold: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.h#L62
+ feePerKb: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.cpp#L58
+ estimateFee: estimateFee('dogecoin')
},
viacoin: {
magicPrefix: '\x18Viacoin Signed Message:\n',
@@ -95,9 +81,23 @@ var networks = {
wif: 0xff,
dustThreshold: 560,
dustSoftThreshold: 100000,
- feePerKb: 100000,
+ feePerKb: 100000,
estimateFee: estimateFee('viacointestnet')
},
+ gamerscoin: {
+ magicPrefix: '\x19Gamerscoin Signed Message:\n',
+ bip32: {
+ public: 0x019da462,
+ private: 0x019d9cfe
+ },
+ pubKeyHash: 0x26,
+ scriptHash: 0x05,
+ wif: 0xA6,
+ dustThreshold: 0, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L358-L363
+ dustSoftThreshold: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L51
+ feePerKb: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L54
+ estimateFee: estimateFee('gamerscoin')
+ },
jumbucks: {
magicPrefix: '\x19Jumbucks Signed Message:\n',
bip32: {
From 936f7913db96a8616028c05f5cb976db9f731568 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 27 Nov 2014 16:31:07 +1100
Subject: [PATCH 176/291] 1.3.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 51e251e3c..a548d06a4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.3.0",
+ "version": "1.3.1",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From c0c47f076a72d93d91680dbf0d8b3dc906899bd9 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 16 Oct 2014 15:30:57 +1100
Subject: [PATCH 177/291] add block.js and tests
---
src/block.js | 149 +++++++++++++++++++++++++++++++++++++++
test/block.js | 72 +++++++++++++++++++
test/fixtures/block.json | 58 +++++++++++++++
3 files changed, 279 insertions(+)
create mode 100644 src/block.js
create mode 100644 test/block.js
create mode 100644 test/fixtures/block.json
diff --git a/src/block.js b/src/block.js
new file mode 100644
index 000000000..f25e1c582
--- /dev/null
+++ b/src/block.js
@@ -0,0 +1,149 @@
+var assert = require('assert')
+var bufferutils = require('./bufferutils')
+var crypto = require('./crypto')
+
+var Transaction = require('./transaction')
+var Script = require('./script')
+
+function Block() {
+ this.version = 1
+ this.prevHash = null
+ this.merkleRoot = null
+ this.timestamp = 0
+ this.bits = 0
+ this.nonce = 0
+}
+
+Block.fromBuffer = function(buffer) {
+ assert(buffer.length >= 80, 'Buffer too small (< 80 bytes)')
+
+ var offset = 0
+ function readSlice(n) {
+ offset += n
+ return buffer.slice(offset - n, offset)
+ }
+
+ function readUInt32() {
+ var i = buffer.readUInt32LE(offset)
+ offset += 4
+ return i
+ }
+
+ var block = new Block()
+ block.version = readUInt32()
+ block.prevHash = readSlice(32)
+ block.merkleRoot = readSlice(32)
+ block.timestamp = readUInt32()
+ block.bits = readUInt32()
+ block.nonce = readUInt32()
+
+ if (buffer.length === 80) return block
+
+ function readUInt64() {
+ var i = bufferutils.readUInt64LE(buffer, offset)
+ offset += 8
+ return i
+ }
+
+ function readVarInt() {
+ var vi = bufferutils.readVarInt(buffer, offset)
+ offset += vi.size
+ return vi.number
+ }
+
+ function readScript() {
+ return Script.fromBuffer(readSlice(readVarInt()))
+ }
+
+ function readTransaction() {
+ var tx = new Transaction()
+ tx.version = readUInt32()
+
+ var vinLen = readVarInt()
+ for (var i = 0; i < vinLen; ++i) {
+ tx.ins.push({
+ hash: readSlice(32),
+ index: readUInt32(),
+ script: readScript(),
+ sequence: readUInt32()
+ })
+ }
+
+ var voutLen = readVarInt()
+ for (i = 0; i < voutLen; ++i) {
+ tx.outs.push({
+ value: readUInt64(),
+ script: readScript(),
+ })
+ }
+
+ tx.locktime = readUInt32()
+
+ return tx
+ }
+
+ var nTransactions = readVarInt()
+ block.transactions = []
+
+ for (var i = 0; i < nTransactions; ++i) {
+ var tx = readTransaction()
+ block.transactions.push(tx)
+ }
+
+ return block
+}
+
+Block.fromHex = function(hex) {
+ return Block.fromBuffer(new Buffer(hex, 'hex'))
+}
+
+Block.prototype.toBuffer = function(headersOnly) {
+ var buffer = new Buffer(80)
+
+ var offset = 0
+ function writeSlice(slice) {
+ slice.copy(buffer, offset)
+ offset += slice.length
+ }
+
+ function writeUInt32(i) {
+ buffer.writeUInt32LE(i, offset)
+ offset += 4
+ }
+
+ writeUInt32(this.version)
+ writeSlice(this.prevHash)
+ writeSlice(this.merkleRoot)
+ writeUInt32(this.timestamp)
+ writeUInt32(this.bits)
+ writeUInt32(this.nonce)
+
+ if (headersOnly || !this.transactions) return buffer
+
+ function varIntBuffer(i) {
+ var ib = new Buffer(bufferutils.varIntSize(i))
+ bufferutils.writeVarInt(ib, i, 0)
+ return ib
+ }
+
+ var txLenBuffer = varIntBuffer(this.transactions.length)
+ var txBuffers = this.transactions.map(function(tx) {
+ return tx.toBuffer()
+ })
+
+ return Buffer.concat([buffer, txLenBuffer].concat(txBuffers))
+}
+
+Block.prototype.toHex = function(headersOnly) {
+ return this.toBuffer(headersOnly).toString('hex')
+}
+
+Block.prototype.getId = function() {
+ return bufferutils.reverse(this.getHash()).toString('hex')
+}
+
+Block.prototype.getHash = function() {
+ return crypto.hash256(this.toBuffer(true))
+}
+
+module.exports = Block
diff --git a/test/block.js b/test/block.js
new file mode 100644
index 000000000..4caeb9f48
--- /dev/null
+++ b/test/block.js
@@ -0,0 +1,72 @@
+var assert = require('assert')
+
+var Block = require('../src/block')
+
+var fixtures = require('./fixtures/block')
+
+describe('Block', function() {
+ describe('fromBuffer/fromHex', function() {
+ fixtures.valid.forEach(function(f) {
+ it('imports the block: ' + f.description + ' correctly', function() {
+ var block = Block.fromHex(f.hex)
+
+ assert.equal(block.version, f.version)
+ assert.equal(block.prevHash.toString('hex'), f.prevHash)
+ assert.equal(block.merkleRoot.toString('hex'), f.merkleRoot)
+ assert.equal(block.timestamp, f.timestamp)
+ assert.equal(block.bits, f.bits)
+ assert.equal(block.nonce, f.nonce)
+ })
+ })
+
+ fixtures.invalid.forEach(function(f) {
+ it('throws on ' + f.exception, function() {
+ assert.throws(function() {
+ Block.fromHex(f.hex)
+ }, new RegExp(f.exception))
+ })
+ })
+ })
+
+ describe('toBuffer/toHex', function() {
+ fixtures.valid.forEach(function(f) {
+ var block
+
+ beforeEach(function() {
+ block = Block.fromHex(f.hex)
+ })
+
+ it('exports the block: ' + f.description + ' correctly', function() {
+ assert.equal(block.toHex(), f.hex)
+ })
+ })
+ })
+
+ describe('getHash', function() {
+ fixtures.valid.forEach(function(f) {
+ var block
+
+ beforeEach(function() {
+ block = Block.fromHex(f.hex)
+ })
+
+ it('calculates ' + f.hash + ' for the block: ' + f.description, function() {
+ assert.equal(block.getHash().toString('hex'), f.hash)
+ })
+ })
+ })
+
+ describe('getId', function() {
+ fixtures.valid.forEach(function(f) {
+ var block
+
+ beforeEach(function() {
+ block = Block.fromHex(f.hex)
+ })
+
+ it('calculates ' + f.id + ' for the block: ' + f.description, function() {
+ assert.equal(block.getId(), f.id)
+ })
+ })
+ })
+})
diff --git a/test/fixtures/block.json b/test/fixtures/block.json
new file mode 100644
index 000000000..147a7ca2d
--- /dev/null
+++ b/test/fixtures/block.json
@@ -0,0 +1,58 @@
+{
+ "valid": [
+ {
+ "description": "Coinbase only - Headers only",
+ "hash": "55388f8f9b326bd0b8e50fbe44c1903d4be14febcfad4dffa50c846c00000000",
+ "id": "000000006c840ca5ff4dadcfeb4fe14b3d90c144be0fe5b8d06b329b8f8f3855",
+ "version": 2,
+ "prevHash": "3385c4b2a3499669987f5d04fa4127b59dbf2ee625694fa0bf08000000000000",
+ "merkleRoot": "cf52f0ed6571367818a801a169e64030d8cab1a9f17e27170a6924127e19dbb8",
+ "timestamp": 1413391595,
+ "bits": 486604799,
+ "nonce": 3760981266,
+ "hex": "020000003385c4b2a3499669987f5d04fa4127b59dbf2ee625694fa0bf08000000000000cf52f0ed6571367818a801a169e64030d8cab1a9f17e27170a6924127e19dbb8eba43e54ffff001d12052ce0"
+ },
+ {
+ "description": "Coinbase only",
+ "hash": "55388f8f9b326bd0b8e50fbe44c1903d4be14febcfad4dffa50c846c00000000",
+ "id": "000000006c840ca5ff4dadcfeb4fe14b3d90c144be0fe5b8d06b329b8f8f3855",
+ "version": 2,
+ "prevHash": "3385c4b2a3499669987f5d04fa4127b59dbf2ee625694fa0bf08000000000000",
+ "merkleRoot": "cf52f0ed6571367818a801a169e64030d8cab1a9f17e27170a6924127e19dbb8",
+ "timestamp": 1413391595,
+ "bits": 486604799,
+ "nonce": 3760981266,
+ "hex": "020000003385c4b2a3499669987f5d04fa4127b59dbf2ee625694fa0bf08000000000000cf52f0ed6571367818a801a169e64030d8cab1a9f17e27170a6924127e19dbb8eba43e54ffff001d12052ce00101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2403089904174b6e434d696e65724251521defe5cdcf04ad543ea4eb0101000000165e0000ffffffff0100f90295000000001976a9149e8985f82bc4e0f753d0492aa8d11cc39925774088ac00000000"
+ },
+ {
+ "description": "Low number of transactions",
+ "hash": "f0ca57cf84cc953194cd87de4bd9142720a056dc6f27484767f3e85e00000000",
+ "id": "000000005ee8f3674748276fdc56a0202714d94bde87cd943195cc84cf57caf0",
+ "version": 2,
+ "prevHash": "0cccf0b884a20113ea2c53a381dacc92a68ae9db1cf86525eb259f0c00000000",
+ "merkleRoot": "0ebdaf5341d911e69ab53928e3f9f46e5ece27b950f3b43eae521a602bde41d3",
+ "timestamp": 1413393997,
+ "bits": 486604799,
+ "nonce": 3126400832,
+ "hex": "020000000cccf0b884a20113ea2c53a381dacc92a68ae9db1cf86525eb259f0c000000000ebdaf5341d911e69ab53928e3f9f46e5ece27b950f3b43eae521a602bde41d34dae3e54ffff001d401759ba0a01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e030a9904026309062f503253482fffffffff01700a049500000000232103b441d74dccfe4d9a3b343149557107a68feacbe95b5ea3af63f4259b4f278b24ac0000000001000000014c959784efb5b2e8d19e2aaca588f7591c10d8f9833dfaa70db9fcaaca123ce6010000008b48304502200d4e79a0aaa162413b812aa9a5a9af18933bb9ee8adabbbe745785ecd0a41d7d022100909f15d27633127727b02a36c2986c37fda5df7ac686002dc9d0b892678b42b40141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a914ff6d383fc1eb0560b5bf63bac7988763098ee7b688acb10abba80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac0000000001000000012568651e80bd1f2c08fde0b10ef507c19ca95e0f7249d6d8b473eada36963866010000006b4830450221008be9aff4a081f7c734e2b679ca3483e205711fad2733c5f5afb8c0bb5213930a02206322d9eb1808e5633da787bf56966418169fcb0a2b964b9a35053c4859cfd35f012103bb318b00de944086fad67ab78a832eb1bf26916053ecd3b14a3f48f9fbe0821fffffffff02a8610000000000001976a91452bc36b0497a027d1c5637d8df7389a48b34245a88ac101aff03000000001976a9148e8c1d4adef86c11154fd04b5012306715fd4baf88ac00000000010000000103642c8bfac609738fb1b17f270ba2baf5df8e87108fc795070c8bf2e415210c010000006b4830450221009714a186283b0d97ae5b24f538618f96e0cca42269e69c389c9c5211bb095bcf02200e3992501e90f44a8b03b26cf9c3f2b16d73d150ddefcae607fc1e7c2dcc02c40121027ccca0e0a9c86180431340aa14038f22428b196a7a97f4c63b4afe142afb55e5ffffffff03781e0000000000001976a914a4547646725696134124fdf5b465438b940d43aa88ac781e000000000000475121027ccca0e0a9c86180431340aa14038f22428b196a7a97f4c63b4afe142afb55e5211c434e5452505254590000000000f0a6c9ae7ec80100000000000000030000000052ae035cad01000000001976a91421cd98f4b804dc07f992559cb551158a078472f688ac00000000010000000183f2c7c9ccba010eeb72a53f83a41970c2cf2e2f2deac895e917fc1a8da11aec000000006a4730440220068e182f5528c1752414bb8db48637b8e329b700018d02056d4ed01721daef9f02202bb66702d586e4ece02e70ebac251b5e5e7af0914ceda2f5efd1ed0e7fbe51030121031765feada1e5d93645b514bced2ac7135bb4d14c41c5e1f9f973803537299c20ffffffff02a0860100000000001976a91436e875fe44ff4a4b13838d73ed32b5c62722096588acb09a9600000000001976a9141d6131f1ffad58a7d091f1fab29ee36b27b091c288ac000000000100000001387daacc7861110fc52535e8a9733d40fb9c56b281708993e1678c79ed927677000000006a47304402205b082eea0f426dc753b7489df44f2b979d1cccd3b6f0ec9bb2ca002cae4cf78a02203733f049ac70354ffa8eb290c7c470352802339ddcb940659340d15fac89c880012103e1a574d02cd9d0231cf53cb2ea5bba86d570f0edc9b5cdff613a46d381103fb0ffffffff01e054e111000000001976a9140744f9fd5a3b73a656694171412182a32f2971b788ac000000000100000001be200e8543914878d90b147f5a43bfc3828af510a043a4e0512293df5ea4ad60010000006b483045022025f5128d9d2c66a32e8fb80c733054a3ab74fcba6499a84f55918e52551e8d01022100a11f183fb8da767fb16b71fbe737f062983793509fc6b8286a6a2c84f6553a690121037beaee4dcb1fdf673665256608d3ad0beacde433b117ea8f0a8d23b8a0ee8307ffffffff01e092f505000000001976a9140744f9fd5a3b73a656694171412182a32f2971b788ac0000000001000000010f5ed77b8816242642a5ba39464e48fcd1cacce6dfc27862d922407b760fadaf010000008b483045022019737d8bebf06ae5588888dcf403b456484cd8a1eef73e5890f980dc9ef88aa002210088e8d47f7c719482ae74ba6bea8a70a76bbfd72f751bb78e49a9499e931608c50141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a9145bd3695ed80d96ad480bcc3e252030e30b1c2b1c88ac015db9a80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac0000000001000000016f367591e290ecc8d36a27e00d03a789df873dda395a1c5dfc6e52ecd6d8630f020000006c493046022100e1a59d90352d278499ed252fe5318bef60aa4e6c12aea5b6308014db01370983022100e583dad2651f1cc4769e533d5f398fc49856f1d8500b75bb1970dc893231ceba0121027ccca0e0a9c86180431340aa14038f22428b196a7a97f4c63b4afe142afb55e5ffffffff0338570900000000001976a9141b0247a0ec998ce4774193e6629708a5112f3cee88ac10980200000000001976a914a4547646725696134124fdf5b465438b940d43aa88acab45a101000000001976a91421cd98f4b804dc07f992559cb551158a078472f688ac00000000010000000187bbd96b486f78f8f80a6c19d60c50637c3c56a08d96d61e941fdf7b30aa9a9c010000006b483045022100aaf951927b28c66f32e26c1ba29563fe04ba245cd5f30af7887b3881c30914320220692f588b0a31f730a70e99cf143ef09b29b2216268f15f71d7f0255842a4fd65012103d850746fc0287d8550dfba1ec81c340d3c192d10fa9c918908fc913910667f01ffffffff0280969800000000001976a9140bccecf71c0b232d9f89dabc3f2b5c4ee7170e7b88ac00000000000000001976a91418751b7839491fb642b370760c5887037d30aefc88ac00000000"
+ },
+ {
+ "description": "Medium number of transactions",
+ "hash": "0cccf0b884a20113ea2c53a381dacc92a68ae9db1cf86525eb259f0c00000000",
+ "id": "000000000c9f25eb2565f81cdbe98aa692ccda81a3532cea1301a284b8f0cc0c",
+ "version": 2,
+ "prevHash": "55388f8f9b326bd0b8e50fbe44c1903d4be14febcfad4dffa50c846c00000000",
+ "merkleRoot": "0c40f497466fe67a94dd9dd6851844097ec0e30656959ccc26efde12e119f770",
+ "timestamp": 1413392796,
+ "bits": 486604799,
+ "nonce": 1810450624,
+ "hex": "0200000055388f8f9b326bd0b8e50fbe44c1903d4be14febcfad4dffa50c846c000000000c40f497466fe67a94dd9dd6851844097ec0e30656959ccc26efde12e119f7709ca93e54ffff001dc048e96b6701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0309990402db00062f503253482fffffffff0110801f9500000000232103a552615caaf1a5f824a47fffede99bc845d182d66daf5eba55a881bb596c6530ac000000000100000001d0fe6ff5a3cdd1ebaafec5489e7cffd5e15269fc06492a1b948bc3d503725621010000006b4830450221008dbd58f7d83223f7354e6c6c4201bf0723a107b2472294c51c0e8633df026ae502201a625322146f421562e139735ad960baf084335e7df445105838ac2d4b591af2012103c1d0ed4e6a4ed6a60e87021a98bbeb838cad9474fbc3bb45df1b2152f1ecc79dffffffff0200ac23fc060000001976a914b6c4f76334fa9c78ab90a136495366d4dfd6a8bb88ac40e179ca0d0000001976a9145001e1cceab6a9a5d29360c9e38e30010638437688ac000000000100000001e4dacf5f5d9856e5cc5503639f03030cb1325e5957d45fa018de00892379f680010000006a473044022075fe3a93ee65b18b1f2c7b32051a54b55e4497e8413da313b79f134bd562c5f4022002cfd7e72c81e7e7a4d7cc20e7a357ee9bf1ea837820968126d8880b98027bb8012103f5ae0228e424648dea53ed5e913ce2627d5b920ad4154816b0778a23dec0eb74ffffffff03781e0000000000001976a9149864a73e6d46d4a0ca10c693b450a868cd72a2a188ac781e00000000000047512103f5ae0228e424648dea53ed5e913ce2627d5b920ad4154816b0778a23dec0eb74211c434e5452505254590000000000000000000000010000002650170ae70000000052ae6821052a010000001976a914460e23da200cbaab6c3ced3f4e28bfc98a63be8288ac00000000010000000c9538dede63932e2fe2982c545ea6998718d1b5605090dd58519616b453db7e5e020000006b483045022100bbd78f28b3865fc2e4f9cd803a25d479fd0d9327a4ad96a99d1d47ca3f15094e022054173cba9e535f413552dacba5c1a50c52ac48466ae01638437716ae49d2ef960121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffffb59e4f1a7ebdbdff556b31302dd8a91a33d77b3957ae6ca72b489748afdbe9b2010000006b4830450221009c28408dd0164c3bd5c1b79540c916e851625826de9086fb8450e7bd439715b602207f90e0e898bd4c83c78cb4c1c9374e5257ace1ec854ffe8ac40198f2581bf74d0121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff91dd9ba2209e55d744ddee54086dc30593841c27f1103afbbecc27fd39e0fa36010000006b483045022062dae6848b1a56a90f4ef78f820685c4502bf265db2df71217f9473115f56fd8022100eba07d1665f5d51a9aafeffe2f6fc8a14088d638480718bbfaafed724b6c4e050121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff805e418a77068a845f6f9fc1b70e786cd69fb7ba0a377b732fac7468ac5f38fe010000006c493046022100a4bf26f55c6ab6ed7a93d2b2ea7d61fffef97240d2aa898bc1e66a23ee4e9c420221009b4d8e4105d7d7d0e518b8588f241c3768406747a16238d19ca3ac9be91a6e790121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff352e5fee82e0bc6602f384cf70955516a7704408c0ffe1e9cf8653f83834df0a000000006b483045022009bf389f60989afc68ce3c95bbbb101cc459e8563560726a2ad96fb3d78c28e6022100ca37cb90c653202004ec55df1719714ecc2d93ac4a79e1d01ce6e28499edada00121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff7dd3e25567c59fb11ff5d51e1df5721e791ce45177ffe1b03bde5f6f381530a6000000006c493046022100c1c4cd0032c8b492f8cb1cee933119ffe3af098ac9a83af6dff8beddb9f025770221009f397a74a31e2864b49ab52ba05df6a91434a4796aee8615854f5fab38645e330121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff4f1dccb3840dc9b283f40bcedde013952b5f63de3cd55637bdb107cddde18e90010000006c493046022100acca38436760d65b1255001c8e28e4b56a465ae0ced00339dc4624a9ace4ad8e022100d41a6a2176b0448ac0a42bd1c9c66b1b1d2fffbe27aeb78815f3ebe66fd40bc60121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff55f0f7040e86dc63abb338fe084aef5eb6212a94eee96511dd1e7dc1a0276e25000000006a4730440220249ba7396f8c00bde4c1175b6d23ddd6b0b316472a09a7c257d692305de7c97502206f8700e708155ea0ea7f21666b849c8c458555d6eba1f2efa33402619bef61a00121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffffad66cade8d08afb220204659a195c8b5d0ee3835d943b5f1e696ddbca24e6a46000000006c493046022100e7c30711e1824bbac03e4797fb989b1de1097868714933734fcbb5bf64861b5f022100892eddbb854a0415628a1b03f0adb45cb47b397cba03ff00536cab86c3f4c6e90121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff6c2fd410949b573b0f9ecf05f93c1e5bd23333d25a219dcf59e9422049d04369000000006b483045022100f38eb4802ae149ca498b6d0f9398e1724d659f75f6ce953868d3761b0b1bc4c50220067a29a68bc1ac0c85489949e069ed336d33b0b5c437bfb85733dcf971362e0a0121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff3d78262970277034a0d6fe72724be0901875e5a6998d52e9d086d4548adbb194000000006b483045022100d0f74329ebbc2377707143ac5f6a9c88e99cbd610fdd60a5d79229a69fadfaff022033c07ab93c23a41b9fc88a330e9c5a7b904f80085400ee21bdd217675de68cdb0121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffffa5ab972cc8ca1f10df69bc3ca1b05f68b23414b6f9efc486d8732a1ede6da29c000000006a47304402206d3d945226f41fee7f266c57089c96e1d75aa5c03675357617cd6781e38e5c3b022064f3f32221c26a9b4e33d3d78625210942c508d679c999e385d0d58fefa330350121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff02009ce4a6000000001976a9149864a73e6d46d4a0ca10c693b450a868cd72a2a188ac20114e00000000001976a9146c39ee7c8f3a5ffa6121b0304a7a0de9d3d9a15288ac000000000100000009f09b59178c8494f17e829c5c06295492024cfc97cd5286435bf3ffc8c0420809020000006c493046022100f0cacaeded00fb8f4c84f999f2052b6c4ab6ec5b41e5ef6223beb7fb33adfc1a02210084a5ca4e74ee0ff13d1e6840f6cc8d210e6d2411cec6b336a968ab62bc6ebe04012103a4ab022465616cca59be2fabce9601fd8226b681b05d62cfd61a1653da0cb59dffffffff46b64a680c290c0eeddabc01d4de0dc736400b615324262348bfa0ba9fba249d000000006c4930460221008e6d830527e941d79a6fafc832a58173e7de92614275263b2746753f605a9d69022100baf17b1a870e0ee617aeffe726fe02a45c8fe19c09840b01851c64be2363fcd1012103a4ab022465616cca59be2fabce9601fd8226b681b05d62cfd61a1653da0cb59dfffffffffe5db21f92158086e8a062f5d458c8652895815b0b550f8847e1c544b59a205f000000006a473044022017e1890c25400567aedc52fd0c87eb1411bd19b47e44411438eef2c7cfffb6bb022077f93849ed0fad655b48ddbab1c0b0dc0c704184000bcef7b22b6303956a9571012103a4ab022465616cca59be2fabce9601fd8226b681b05d62cfd61a1653da0cb59dffffffff794c2f1b57dd6f54fe53bdb7220ec59b57f4114786e820355ecdb16f6d66dfbf000000006b483045022100b3cdad56c0451610957f474f1e21f30440cfbc4e8da8bf1e0e6b2df7df268f13022000f17c04a04d0b5f1daf4a11e78d581387d8371b690a435deafd9e5d425a57e4012103a4ab022465616cca59be2fabce9601fd8226b681b05d62cfd61a1653da0cb59dffffffff09b1e86b31fd61037056116b96fd7e09edf83c414808d50975cf307cf1859c53000000006a473044022012887712278e9ec9fe936bdab5b46fbe4aa7232a37201e6f4871949ac32b47470220427b8ca31f60d45dbe892d5dad571c3e9844827894d0816520ff59e15ff47e03012103a4ab022465616cca59be2fabce9601fd8226b681b05d62cfd61a1653da0cb59dffffffff559bda6c35d2bea892e02d1bd1a8ceb6cfb8ec6da4c5e64095aa6ece16da9fa2000000006b4830450220376f947fd4f6a34a6962af5f6a6b90aae828ff68a2312f0ed4abbdbb10311455022100ac3d53e42df05c62cf1874744a70d9f9a88a20cbb7fa9e3bc2f008fc0cf747a8012103a4ab022465616cca59be2fabce9601fd8226b681b05d62cfd61a1653da0cb59dffffffff3bb1a45cb905a09a7fa335455e4a2403bdd3e2e07aa9de8e858f2df282e841ae000000006b4830450220058a3cda301167c4030eb8793870f2fc8b62b17ccbf04e35e733e2db1d9a33410221009163811a84710f73d043e6c72b932d257f566760752d13abeddcda878f4bffc1012103a4ab022465616cca59be2fabce9601fd8226b681b05d62cfd61a1653da0cb59dffffffff73e038fd3ca63a87cb5f754e87151d5d4690005907d1fec8a585ac01269ed3ec000000006a47304402207c0f6cbce98127749da512ee7368dcb8973c5b5fe254a2b667a08636acda487f02202be9c33b4d49e6c3615116a0633cbd6fcfb8606dab768b66baae83069a6a5f79012103a4ab022465616cca59be2fabce9601fd8226b681b05d62cfd61a1653da0cb59dffffffff9538dede63932e2fe2982c545ea6998718d1b5605090dd58519616b453db7e5e000000006b483045022100e2212e01176bced817130de9031785a25e41fb8f40449ea4b8ff74ef59badaa102207458caeafa0d38b6e9f5d13c8bf95b16c7a075a2b0e6225b025954a2e71a72e2012103a4ab022465616cca59be2fabce9601fd8226b681b05d62cfd61a1653da0cb59dffffffff01d8defd09000000001976a9147f6394009ab59c0ff5f5cda27ddf2fddfae4167988ac000000000100000004cbaef29b3dadd2016ef2e3e646dc75ef97438bbd22ca1ccc775172519d22962a010000006a4730440220329e18e737bc060d43596d2326edb43ed445b89e7ecb19682a2a59f4c50589ef022005fef3ad6601070ccaff7bae890259b6a7754284a54d00598c2d46e0c0c4a1730121037dcd7819ce02547f96a93deaf7ea5c6244d79f13c21a855be672eb28af964c16ffffffffa634945cbb12e719a9997387202aa589a4318f8416804aac1674d14ee5ad1e1c000000006b483045022100ed0d21ee6bf1a288525f8beb39596f844201bc2287aa1993bc3d6a67d246d33602206130710bf1ef50655c9dfa1713f28eba4e03d3084e2d317802e1a15347fa647b0121037dcd7819ce02547f96a93deaf7ea5c6244d79f13c21a855be672eb28af964c16ffffffff1fe00780bc3e272f758f6892b7eebc58798e2c253685720e944c484657b045db000000006a47304402200df0e0c3bab3e8d9c784237fb81ffd7fffe1dd56b4d026e1f423a0658732836b0220209c70ef792bb0912b4cad295ea53075f224f8121d0204fce5e3ed16b40b39c10121039e3480be13ca86714045e1d28da159e0b3647d4bfb51dcebd8b33985a47a51c9ffffffff06d9254a072fb767bf04fbc22f76332826f5b63532b1d11daa731605ef7a54ed000000006a4730440220636fc2e4e2ab68dbfacce1bc0741d6f2106a581b65077a2e2e08e3536a0436a302201a2a1967b4e990832fc03d5647e6f2512d12dc99fdf6a0a5fc125787a5305e490121037dcd7819ce02547f96a93deaf7ea5c6244d79f13c21a855be672eb28af964c16ffffffff01e84a867d000000001976a9140744f9fd5a3b73a656694171412182a32f2971b788ac000000000100000001b57bd3ac69dcbc285633cb4cf12c765c019e51f910c631fc1c74ad660dc5e7b201000000da0048304502204aa9b763abccd2409d63c618381c87b844dd7e7db093e14e37c8301272cd0be9022100fb59b59c39c2c4314ff2f08d1ab3fed224caf141e29605973b45c24a2540ccd50147304402202bc760c7f98446731f6aa2bbc0e3913229724e228bf8acc7f42f16107be158290220336e90a92a5aa6cd0d386895f4cdf8ec9ad313d9a458b7ca9d9193fee92abf210147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9145bee13302ba496c3b2d3ccc89202fd76831228dc8768a4a6280100000017a9148ce5408cfeaddb7ccb2545ded41ef478109454848700000000010000000149c6ab2ace8003a6a1b5bf67e6e0fa897e1d2d2608172255f45bfb324532a09e01000000da004730440220214317cad717a1cd6baa040c52e697d4cd2b17ac4c85e18c6f258e412778bdb202205707884f09b4afb60063520004e8af694c6dbc7f6e111cf40ec0e0079041cb8601483045022100e2c9b18f26892a97b0008b8176b1d68f464994640d0208761e321390c4ce47b0022016e9d87c32d36e2add90a89abaa585eb164a756ded0136937e93fef3982ec5a70147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914c4c9057cfe2b9083b6533f51f747ae3c77c5c3da87405e97280100000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000017a22d9a45dc865bee7642eb16c60ec0a6717d8554772e0640a705c12e549018501000000dc00483045022100839f66f053917dd03a84a949b4bb539f8fc06c95ac0aafc9e78f6cc040ab419f022001eac1a450ca2613d6ce47db4a548565bb70886dcc555b495b77ed2a7140fd5901493046022100d35e6c8f71eed0114f8787d078a17310483a36100eb6cd7c9a0fb7eefce4e0b5022100d7640cdf302734a1a8e2ea81f3bb6319652134234859725a4f16ba780495f4e00147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914d1e450d11ce446fc45d57001351842aa3b810cde8768a4a6280100000017a9148ce5408cfeaddb7ccb2545ded41ef4781094548487000000000100000001ac7c2b917cf245c06be4d59250bd433f367387c727b46616ad2594de8396105601000000dc00493046022100dc62b5a197b6bf7cc90d5d0f87fa97499e3bd456a7f8bdfef40df55d6a41b6d802210081db312d90ef3353aefdab24c58391c2337412b889a0160982e6312a9430c77001483045022100b5e89e670ad5aaa51ab412fbaa6718586fdb1b298fb3920ea90b4732c38063050220307721a03a54b4362abfdfc4d994b020e42a5b869c85fc089b9498d9d5ddc7550147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914a49d822d44e0ef8d20022843032de6bc420b2f5e8768a4a6280100000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000018f30d8ad625b6605299ed2f66a6b28e2912b4391937f7329ce2424ed178d7a3101000000dc00483045022005bcbe24a3511f401be2f94f5ec9414050d7b5d4c8a9c262d6a438a080559c09022100f6c5f4422bd702ba4fdc403c342c0796a6c4b34b236f15362827636448f02a1c01493046022100aef5108bafd191e519bd633460d334bc3ce662f513fecaf3a8d48ee93c3c2c04022100df30ec6fecf165cc187194b82c534b102d62c66e97c21291d8192b5b00a3b2aa0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9141ce06aa7fb344bfffa8252abb5100777a8baa5068768a4a6280100000017a9148ce5408cfeaddb7ccb2545ded41ef4781094548487000000000100000001054b9393e69e0d71bfd194558ec2182e38167e0a7256ceb0869ccacc3a5acf8d01000000dc0048304502207d21bee5933283111d4af205e3366e0ec8497e77553570737de9631c9554ef7f022100d284bd8ec48c58b879ac1e7f39ddc9e62ceae440636e9179602a666b6bd1a36d01493046022100af4c6387b30b0050af7ee32d7b900ba6e6051aaa41c876d54fbab95bde62d583022100c3893f9bea39253ec1997717ed50f4797522b41ca5732364d506be31342a82e40147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914edb50dd706eba79f59fed2980843190799abc74187405e97280100000017a9148ce5408cfeaddb7ccb2545ded41ef4781094548487000000000100000001dfbc1c58a49e3a41a6d3ac9891124f49631f8a590a8abf788e971a59a155352c01000000dc00493046022100e04d51aed1ceee5b3dd16977f32fcb0ecca486b15483b792ccbf72fd444e93ea022100c6c1ef150716597a57d5efb3859c3a519b6099f8fcd76fd88dee51d9de6deefd01483045022100a0adc0d0ee2f333a0377ed97f233944b5017be97869f1ad3c0a4f63b7583bff0022019f9033576e8a1557e8c341290e04378ce8c11b59451aa1c99b36875f04b4a760147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9148821c06dd300e0c5e715a7c4764bcff9725447778768a4a6280100000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000016fd309077d56f72e8e479c41c20181edabef98b64a6b67412edbf24025d5a53a01000000db00483045022067574c4d4ab1a0c8ec6a8af7ece7ea7239612f447e06c7332049692694dc3bd0022100a04b4c0d3159c6b32087971d6ec50818d74136472cd671df9b3991ab72a127e101483045022011357745d9e0516b8d11f38959e1d16fb6135f43c52235c541bd50f0ab4af3e5022100a2b34b41173d7c2de383559264aaf67fdf4cb3a59de1774e809a9c362da72f2e0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914765d0d258d3d0e6a59bfee9bfbb20596518b95d08768a4a6280100000017a9148ce5408cfeaddb7ccb2545ded41ef478109454848700000000010000000284f9f2e4e397cce58c844dcf5ec258dcae775d5bb6c8e1bb9bd0f53f127f7cea010000006b483045022100a6e72fc5e8a0e07853b9015874d8e40e6861185ba440fa4d79ffe925206133d5022006fb2812553d16e46559ba2260536e5809c9e8e420ea98033b85d91f3726a3ae012103e5481d0ff7e3d8ce9190647281f5475724b349444ada4bbe8faacebf92ee94f7fffffffff93a9a177906a0ef7ef0232ccc9a2933a99b3369b996c39f8afdff5a0b95188d000000006b483045022100dca4ecdf7c3449c434fa0cf32193afe1aced32c7491e9cdaac592a61bb3ad8180220143cfc0cf38b68531699bbb8a6723205376cecdd254e33711b73c7b5fac9db0d012103e5481d0ff7e3d8ce9190647281f5475724b349444ada4bbe8faacebf92ee94f7ffffffff020065cd1d000000001976a91472b06fb7c4eadb3c789cf719f7799baeca7e760788acbf874711000000001976a9140744f9fd5a3b73a656694171412182a32f2971b788ac00000000010000000240a16cc443545b1ae809148704511609154d4a9d8dbe31dcd54bdee791eecf7f010000006a47304402207efad34302f84d50c02836b684670f4a94fd13983e23351de3b29441234204d40220242f0522da0602877f7d25f71b8a261db67eee197bd991961714eed2a63121f4012103e5481d0ff7e3d8ce9190647281f5475724b349444ada4bbe8faacebf92ee94f7ffffffff12aacb63b4b92d7ed823e660c33ca21e68322a2c6e7aebbcf7b1213f545baca3010000006b483045022100ab60c956a9ba34c406833c9311ab09ef7970ffafcb06ffa8d8a92f31a74a983d02200eaebf14c4b5ba4c8f48a4771dfd8e03ec2d14ae11d8ad3d9d487a738946344a012103e5481d0ff7e3d8ce9190647281f5475724b349444ada4bbe8faacebf92ee94f7ffffffff020065cd1d000000001976a914ee2af5db7aa20a3ba7626a94cdb2da48c0701b4188acd753ee35000000001976a9140744f9fd5a3b73a656694171412182a32f2971b788ac0000000001000000015adb3c14dbd5a07721af2b787c85a95c4cb133dd17f9063dc129ac849067813b01000000dc00483045022100c8fad8eece220e207e2dbdda58b8952a1dbc704d65665af4de527fb01b3734d60220085531162e2448ac58c769c60187a013aef46d26288dd97113e71e0b888ebd3401493046022100a55e1af65f9cdcfccf05c15e536c3d491831a3eda3fba686c7eeaec276f1d3cd022100ca4e818f811d3635710226623c892c0b31cd7740b8e74d4a0d7a59dfc1a76c0b0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914c07e34dff7613b421fd17ae714ac2915cdcc54de8780a5e2ce0000000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000010b121a3f08fbdf2e8ba32c5f60953eecf80dd67e121fb14d4209ffa0c4c2ec0f010000008c493046022100875bf2629f2cf6acdc2302f657ba7aca44eddd5fe37dd754b8a6fba8c47f4fd7022100bfcf0ed84925391c96c75caa5a914f786430bdc29ded3634e043aff339fa08ee0141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a914db2045e8f7c6327732dd242c865e0e418910644188ac9162c9a80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac0000000001000000017419cb2cdb61340f43882c2e034bcc919fcc742444ec41406e72f7897ce64aa0000000006a47304402205144fb84c7af6981c727ee6866ddc9a37a5ed49557dcd1042721ec2d78b7c71f02207968261f681fc3a0531bebf366cb92c88e454325a4a2c98cf3dd66dacf0363920121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833ffffffff03781e0000000000001976a9149864a73e6d46d4a0ca10c693b450a868cd72a2a188ac781e000000000000475121037af2e06061b54cdfe3657bbc8496d69000b822e2db0c86ccbe376346a700b833211c434e545250525459000000000000000000000001000000dd0aff99340000000052ae80329800000000001976a9146c39ee7c8f3a5ffa6121b0304a7a0de9d3d9a15288ac000000000100000001b4702c4f28336cff691596e14170507ed9d64b732cf519a61287acb2edd773c2010000006a4730440220050fc133e55a1bd033b84931e1b62569f98737f099593c784609e03bacf231a1022029afb388fbe52e7819d9dac0d73cd0ed2035d9f917bae304ff224ce144198f40012103e86cf84b12237867a327cfa3f34cee931db055a06312b4bef003bb784b4ca74fffffffff0200688909000000001976a91449eee8f4d96e60d8bbfcc9f82747c4496ce33b9888ac406c026c030000001976a91443dd90e9647903ea668e4ea3f5feb8469630d5a188ac000000000100000001d22f69c205c88c4f52f7e148ca579f5cb3a93cc5e52689594e0f33306ac8694b000000006a473044022021fe708e2fc6d0dd2bbf7d022860f5e8c68e6b1fd6306fc3079360a48afbbd6d02203fd0d67f89e3cced810028ee8b48c47b9078438e99b0bfb4386f57afe9d3d23e012102ddda164bba2b1435b04a8205ca5eefb5115270e6d19f6daf8960211b17df086cffffffff0100e1f505000000001976a914eba91c185a67b207f461c7661ff36890fd43e38888ac0000000001000000017aaef574e423163a2fffa556544bd9483ba415e023d56bb40a9e3a9f805e934e000000006b4830450221008db13e8a38e3c10b41f740eff8b5f5789c1c134d68d97cf4b3ab1fd72d3c8a76022061972edc83147ac6cce1d03272a0afbcceec3fe840b43170e6acd427d6423653012103c117f27c03a87e09ae1b0c6f49d2ab79c1c199580a1d0ff2fd682e227a60c427ffffffff0100e1f505000000001976a914ebf067bf6053b3834f6154fecdf31ba28bcb0e7e88ac000000000100000001f0ba13339fb4d5f722a02bb31383427014d967cca259fc51ba6b1209129d09eb000000006a47304402201382d8ed4c3948a33da4131910d060b79e74afd2d890a9f99bcd5358bb6d5f6802204720beb06bb6f1a51528941e587d547e2efbe0b3f96c8d19edf71ca09dddff0c01210222e624e056d0de15bb97e28c7fb8c149dee686f3027f17a032617152c7676d09ffffffff0100e1f505000000001976a9146d2276d2ff9bdc3e3da97c2761bdac3d3104241388ac0000000001000000010df8c6a9c06786b269b6db1dcff3b766fbb13532352d48ae175245594178f949000000006a47304402204715e1ba8c869d7574cd4f4ad4ffe7eda44b3e4c11640e03dbcdf538afcb2bc80220614d5a17c60e84e1bf38e0d2d2a4c7fef7a91a2a42466bc8cbfcf0b48a650761012102c9bf3691bbd97c2a6bcb8610f547cac3ee169f5d59e947069d85f2f35df1a6beffffffff0100e1f505000000001976a9140693c924d0650fd0cbe51d87de977faf13c6a29088ac000000000100000003bd698ace3161ce9e9bd493c24dd43e78fb61f079c4aa047932244d8c9948c2b8010000006b48304502206e82747317df2734e5f2c74514c575ddb7d79ec928649fd1734ae11d53703c4402210094f7f303c2ead5b0fb33b9d7663e4a0bc2711390ac5b8d742bf0bc747b16cf100121025c25273e23fc94e9bdef68279ce4b2eda49dbf09635af064b8bc89061c2d334cffffffff06d9254a072fb767bf04fbc22f76332826f5b63532b1d11daa731605ef7a54ed010000006c493046022100a67df7840a93b3f19d8fbad4383557585017fcff853b488292c626ed155e3b350221009b3aecea5f29b7420ec53b0d119996a569e421a752b1fe30efdebb9f158b498d0121022ee4f8d242ad07274e4deccf0523dcbf6da2e55cdac0f92e8a79e40c721a7350ffffffffcbaef29b3dadd2016ef2e3e646dc75ef97438bbd22ca1ccc775172519d22962a000000006b483045022045df4b9c83159061ba910a07886a5eb312fd244faa963cddf6dd5af20b685bf3022100dc29ca5952f74934d589b838bf785042e78b638756fc92e71d3ef8e4bec8aa8c0121039b1a29bea54d0482295ebef1d023c686dc156722bba16bf317b38636bb1717b2ffffffff01a834f20d000000001976a9140744f9fd5a3b73a656694171412182a32f2971b788ac00000000010000000136e0ee46b394e3e665ad264d6b0e813f510ebd49c9cf4ee9fea66394a3cdd516000000006a4730440220547205d8dc30ae833b82cf0acc2c76079e9344ceea410bef3dba06b96ae2f0fc02206a3b175b1229079b64892d99bccffbe8cccf9ce634a11e6cdccb2d740a89c938012102c6052392f63433a8874a85e632960df44f901bbcb81e75e91c502eafe8437b88ffffffff0239660902000000001976a914e31b53d30d08216f5b7e8b8fb153f424f0cf2c2d88ac7493f901000000001976a914474a84925c770102eaa92c509e95812507f3f7d188ac0000000001000000015559373139aeb2fa33fcf78ba3e571663b20486cfb7d896528f97091975c5605000000006b4830450221009112b1958627956e05b5468f60931317b83dccdb9c91a195f49ceac2fd42bba7022005b57df3119060ffe82d478d834dc3d6b4c743787aee2801dc3cc504578ef3af0121020f4f9616ef316d44aed4f0fa971cf32e455b8f82e90a7a9c54dfe37d5c3ec135ffffffff02c9658b01000000001976a914066d59ecda788373e3206282d5255777b92a893188ac69256002000000001976a91418db620c4ec4593d76fdc6d4a30a531d08ca959a88ac00000000010000000262ee525e057cd877f7ceca8b3d3dcbd977fcfc993e6c1edb8577e707b4b5f61f000000006a4730440220292a063728cadfadd7cba2599cf5cd0460e9295fac92f50fe73da9c1c949979d022079794d70e84787a720b535cb1122cdf8c76486c7466ea6d12032784cd2776e230121030fdb4faabae84b19a7b192ed101ea5c8bbe5067acef3caf3553d23d1328fe74bffffffff2eae185b608e4598ee77e575f2ed39cd1cea745549aaf0288bc4e9cf696abeaf000000006b483045022100d338cf96525cf590a9f67046bb669f0636614b2ed9b85f07ae4db15c8d03ad8b022001ccf28b1733b03a218a5a6f1aeba5e35f424e39578730e50d927a574a6835c2012103612de64d269ed8a44f4fd3b5584ae7e5620909b5991d20b534525ed1b54ebc1cffffffff0220c15500000000001976a914f091a6cb3afa861e0dea0139dd26c60ea21cb8f388ac50690f00000000001976a914e8255ec318662f530c71ecb9ec1bfdb98ae7e45088ac0000000001000000016ad4fa5b8f91a88aed9fe60c2954b839d0d3f8345deb5f31ca6abb66e0213d3e000000006b48304502210093612fd6c14ff3f01f88e1f96d579b20af951c38fc3f96334c7f55a9f2df2d2b02201279f695bcd933bc2bd89a6849111a9987058a24cdc11b2838e0ebfdd702c9a3012103d850746fc0287d8550dfba1ec81c340d3c192d10fa9c918908fc913910667f01ffffffff0280969800000000001976a91421620cd6d05d98cd15d2c7957d3c07bcf9731f8d88ac80969800000000001976a91418751b7839491fb642b370760c5887037d30aefc88ac00000000010000000214b9b3fd8986001e9dffafcbd08b5cf96d893b326eca48e1a6e600875ba7c1d6000000006a4730440220771ac11af98c9f3356c72c57e6d7b61d0ec6b1fd472c879e72f3b65adef3bd9c022006184aadbd78eb46494771b7a8636273c4a43b2369e57a921fe1966a4f684fd9012103e4b47eb68ccad5cf770836ba84d7450767432eda7ad62aea7c593db7a133cea8fffffffff53570346a73aa9ceed9ccc525985b06f412babf2d7441e52db9db6cc83551d2610000006b483045022100a67e312945d4b56a559352c743e4a981aba2856469697dc629db85f0e4f2e54302206ed43173e5e65af5df9e55303ac9689d63f458d9554e4fd37035aa8547736ef501210253244eaa74d1b79c722e062a98a7ca2be46e7a26edd948b5b5b141c5f1d15475ffffffff0296ef0800000000001976a91414da5dde04bc5bf7358984bcb227ed431419ef4d88acaa520600000000001976a91491859a64a061038dee95e6be293c7a9849db22ff88ac000000000100000002a186000a255c2cf7b6ccb4ec2774365629a6687c55643387e89ada264c5fd65c000000006a47304402203e1d65edfa06295a66899d5f3c5494fbe109c473afdb699ecda484e70f77e1e0022063a0c24b65b5c54aaaaac006161ac77bb4cfc402fe955654e993c1bb39e82fc0012102a7fc839c0427d33a1158f5b1d60d6d88fe6a790a838c6255cdb15f1a417af601ffffffffe0f8c952e4dfe597864519f34b292bb4b0094978b8f7bcbf0066d55b5198e934570000006a473044022008d5f4cca8362a1735a62e6ca1c95626fc9e9add2bbd24ec19d3eadca1791c9f02205ca558bd7cc3131ca6a4f89a86f78e83298dc98bc7a3ce1b109d020a398dffa1012103f9b986f00ef7410d06f50eaf324deb4513f83079ab7a42acdf470c12bb078adaffffffff02908e0800000000001976a9147605eab76b8020350291bd3d22d8999d991a757688acb0b30600000000001976a91414da5dde04bc5bf7358984bcb227ed431419ef4d88ac0000000001000000010bb8f053cdf88a3048c9dc92f014cecf514e1841c5cbc6eb21218ffe60b4706c010000006a473044022071eb972e731146779d208e378a521e098bd063143ddd3b10271f1d1a94e934ef022068a48334b2a92c52e97de4c1a41acf777ad68fa76fd2917cbe32eefcd057ae2a012103f29b04e608b2e2247969d0488dfec01a2ad4b83ba7bbf3c5ba4460c5782acf41ffffffff0210270000000000001976a91417a149e8da478715292c372a8dee19453f72293888ac605af405000000001976a914dae4b5b55ef3219a9a79cd0143379e73ad3185e288ac00000000010000000195fb54d349c2d732001dd6f3b373cd3880e28c9e421af34801f1a6d2b88a41a8010000006b483045022100cab333e2c20a2003b410a2f013800b3107fdf0d6c42bd3235369beabae73ed6102205ce3c234ff199a2d742e83a00420a3f071d68f6732a6dfc141e2b86f8b988afe012103f54d81de4eec9215803c88d4097bd6990523e5a69ca6c20aff080f94d8925f39ffffffff023074f105000000001976a91400a469197c35da3fa892ff221c22840c2d15ce8788ac10270000000000001976a914f1c5145f86267d64199a22e2c420d022eb56575d88ac00000000010000000136e0ee46b394e3e665ad264d6b0e813f510ebd49c9cf4ee9fea66394a3cdd516010000006b4830450221008eddddd407132af0fdebbdd756db68f3440a3d41047bce5fd30a08a6fe5adbb502200825ca373a426ac1471c44eeebd29f10f1459d949a3cea09c7b95d1ff269cf3e012103c70fe3608fd1a6cfb79a66552a2ead99a3d20716ac20b8988ca87636f9c422a8ffffffff02a0860100000000001976a9140172c2761cef7a82f63cd1bd9921306d66fbb93d88ac9312f101000000001976a91424eb20998407878b5d704e54a8c0ace7b1be0eb888ac0000000001000000014fb19d79fb214b86b0fb0a6577c4250b2cba5358a14d0afd7acfdd7b2b055bfa010000006a47304402200692f6d951f2cd66c7a0d9aaa530fd6a07689c65cb5cd5b6d04faaddf75408bb02201e9c0e192ea7d59e1ac9ec2be449f3706fb0f9227c743defed62b3ba5b47f3880121021225b15301c1facaacac0104d6bd05a33046b2ba4731edaa565da41d7b4c2715ffffffff02f0490200000000001976a9142591497f043482f83f30aeeac043291dffebbd0188acfd03ea01000000001976a91457207e70a8aabb9479c5b4716fdbdf0c4238a9b088ac000000000100000001600f3a2aef32b8275f72e356af3cb94ac371c2d40464f899cef86390282f16f1000000006a4730440220521bda4b96e98e37a734ea9ae79c22f2da9b2ba4b1888d1af544b1172ba13b670220609121425bc54c61390bc9a73c92ef4c8e041c5da5d01de72d56d95340845e20012102f543b68df48df748df773d7c6359cf1ff90f81552c513572602733408c3f27eeffffffff0290f60e00000000001976a914b00e35e1b56764175f33e7caa14ccf14f94b5f3088accb85dc01000000001976a91478b58ed969d5df656b5a2bc42c8355656dd354ed88ac000000000100000001287a6ba0a3a61b4132b374c62ebf576790b80c1679accd0b8a655fe2daf9f282010000006a4730440220325c6e862d0c076cefdbe9bc768be8c417a63289aa12c85218e574a979577b3f022042288b09b904764e16019ce51cd3ee9bfbf9e20349f458f27319ae4df67d22b5012103c8fad558718b44e388695b2969d17cf7daaa1fb872ba072d0dd4b97fa1c8b594ffffffff0253c6a501000000001976a914aa2a1b4b7cb551c663c91280e83b11ef25bf488b88ac40420f00000000001976a914fde75662f6e3aaec042bf3670345e070286b6e5b88ac00000000010000000189f749d3a7c6ef70b549a3f7502bdeadc3ab0c98bf80b716d961bf3830150012010000006b483045022100fe8ed68b63c84e3a251f8717caeae551117f52187cf6d591f1d448ce68a57fa202206182a016acaa14438bb25a87345b55340098f4ed6d7833b51f1b2364ae2b328e012103cc3e7ded16d0d2a09b40faf7ba90da7ee77f71ed8086b6bb8d5a97ed287740a9ffffffff026e3b9401000000001976a914a4a2e8d23729124e04dd84b6abfeb53f1a3e22d588ac20a10700000000001976a914b5fdc18f8d82cf96dfea700f7a4dfc434a07fd1788ac00000000010000000129160bfe0aad2936e867fb84f49b484ce6d0c8831cfa88d214641acbbb0ed3a2000000006b483045022100fe49582a0906dc7ae9a167a67249ab22e54b91c4e08335e2924724afafb415df02201f557f540f20ecae35a06f40a1bea9ee7563bfb5f9738fe56bb2673e11690af5012102fab3570778a8b802b52d2fdb583f4d800bc0321b707a3b5b2e78cb4167da4e11ffffffff029df58001000000001976a914cfb467700301f9406e82047b49043907e9b9036b88ac20a10700000000001976a914b5fdc18f8d82cf96dfea700f7a4dfc434a07fd1788ac0000000001000000010fcf7953a6e8f88c430c24b630a61d5a49181afe2e767ce76119ade9fe07c231000000006a47304402201bdc04089297f83336c6e75db11eda95e417d816566f8b89a692f032127d771c02204cfd078b03f01916b5104c44e33067c38338c15e7f243c45e0c8204553f096c10121039b790ac2e936f461b9aa4c93ad40aaf715c800e35c7280f8f71ad222c4aec018ffffffff0253607101000000001976a9145ffd1ab701aaf92210c9125a3e8631505db4ce2088ac20a10700000000001976a914a54a4680732fb4ab0a5893690f8606cbe24fbc5588ac000000000100000001918ca179557f97ca12aadbfb9ba1c18dee32afac64e5ea292790b468c7edabde000000006a47304402206ecdde1cb4c048911c1f271e60edd7d2892181fe262b50b12cf55971e288ee3202205cdf0b06ed964700860c6c266004a9ee5199d80835145c6f153e78056996a1bf012102c28e3e4e6e25d5d7590f4a7ce318c32c0a98c380aab803873a9628c7e0d5c8f4ffffffff025b227000000000001976a9142baef9004079d373df20c22b0dfe40017433db0c88ac154d2800000000001976a914ec0e8c940a0d3c9a786268e2dcae2e3d641b632288ac000000000100000001d9fc92b02970e558021a15e5f6597ed3075a3972705db1990e6eb22d8f21d8fc010000006b483045022100828a4eac23959ec1574f060a7207161e49e4267807bc9744bcc190b5d8caf39a022007c8eb27f14b7f5670f5611a9e6f30a8a206763eccee0b7a5331d0ad552befb001210317f6cc241d8f0a0123378475e52267b6f6870f134b66e9135ecdbde79df4dce5ffffffff0240cc5705000000001976a914b29f68300e3e489fd301a7a8e01d25ea6f1320f588ac10270000000000001976a914f1c5145f86267d64199a22e2c420d022eb56575d88ac000000000100000002d04ddebd5d7076fb60a39b977208d67fefa431a91f47628304f913605c25a68c000000006a473044022050fd6cde2008b312900692a3928d4bcf1b7d150c22fc77598752a75b94d5dbc0022045715e024c59b5060e8246fbd0b9e86ff2408a6cf4b79695a457d131543afa87012103b5ebafa7223a8b4dcebf89d14fba39f5393ecd839e02e09c691180d29974795cffffffffe0f8c952e4dfe597864519f34b292bb4b0094978b8f7bcbf0066d55b5198e934520000006b483045022100a2e0690726c6a8f45a3d4685676c81a43deae953e0a3069e8045cdebafa1fbfa02206327b98b5da80b494830b5654f6844878a7ea06161279fa879cab1d1b337f01d012103f9b986f00ef7410d06f50eaf324deb4513f83079ab7a42acdf470c12bb078adaffffffff02b5a20100000000001976a914665f2d69bd3aeff8581cf66e2764b849a63ab81f88accb770400000000001976a91414da5dde04bc5bf7358984bcb227ed431419ef4d88ac000000000100000001048f282287120e94e0a87bcb4c4c4c07c8c2f8f6e09ced38d861e0331789f14b000000006b48304502202fd11730a933bf595803f10b8c634aea441263bff45200fe29982ee663c89acd022100f51c76447481326553925c1becd5eb86c0fae7ec2fd2ebf7b93ab6ad86a9ce5501210234eece87d535b56c12df83f70e479fc409957df7929b0c4b08eabaacde1b0a82ffffffff0240420f00000000001976a914153a6b7f423b4e51c69039635260eedfe2b584e088ac307eae02000000001976a9145481ed9fdde635476f602b9c9816fe2ce6d5c28588ac000000000100000002e33ed9cab58586d309378728d5644c1913b919c7a1b8675a603f48d2df256631010000006a4730440220015a7513ef719c26f32c97ecde8d570ab3d2196add683430d64a8302dfec8bc002200d9a65d86419813df213a95070731412b6fb2615aab1a495c256046ee40f6a00012102073132dc08c82ec0b01dd90494b27311cc8062cdd543e1ccd25ea9a042e10e6cffffffffe0f8c952e4dfe597864519f34b292bb4b0094978b8f7bcbf0066d55b5198e934100000006a47304402207d850910a0a6766f59338a4d9bf7c735a54c1ab0b6355bac08e668260a3e85f90220586e1043c5a68c7ffe35271cee0aee1b20272e6e722f18f0f5d532b4b027b73f012103f9b986f00ef7410d06f50eaf324deb4513f83079ab7a42acdf470c12bb078adaffffffff023aa00300000000001976a9146ac3dedcb939dd161cf1cbb79d476e54acf811fb88ac7e111400000000001976a914c3f5faffd3dc6f58e0accdc372e14beaa16e3d3088ac00000000010000000241504c537ef2c3e8a8e967d1c560bbadf257c6287fb248c99ea8c87d7d93973a000000006b48304502210094742457c5afa6e809e502e120bfdce94df70a84346916a1d3058c1ed722ca9202201cedf2acc9b309a20c2c4c6f5ebb3fdbae48a81002de7fc4379ef327af53db74012103f0260d1e5394ecaacbeffbd3081d48ad882a83dd1f6e2911a494af3760a879ceffffffffe0f8c952e4dfe597864519f34b292bb4b0094978b8f7bcbf0066d55b5198e934180000006a47304402200cfa32de673d5e505348b0132f09dd3932a0d6950d64a635726808bf27cd13f102200f0985fe3a11f4c0d80bdb8f58e7ed182b154f611162e11cae353778c875b6fa012103f9b986f00ef7410d06f50eaf324deb4513f83079ab7a42acdf470c12bb078adaffffffff02dac40300000000001976a914b18e3c27cda57acac294c7dcd0fa4af5f03a143888ac51401400000000001976a91479450defec6479b2f87fce094c215749528474b688ac00000000010000000272bd1b874963895687dcd5858f9e623c5274e662a95ddb5965cbdeae95028ec1000000006a473044022049f4841b790589647ad484b55e5c8c2c52be4900e492b7e38b1aa2532a76571202200ebaf2ea0a81eca80de1664d9a24c4f38471bebefba0308e380ceb4e872d6a980121022467cc3e4628dbb9ae6fefb534db67c6856adf85bd9843596260b16f1a394fe8ffffffffe90d2e51a4374b3975923f4f1acc37aff14288a40a4593f79742a382cb81465f590000006b483045022100c92e92776ac2884d6543faf2715f8914cc1950afc22e369a752e731fd6ae65ae022078234809f091f7ea344e54c3e77c6397275a1e7d50131991e3b36825648b5235012103f1b4d21e0b344248185408c1af96bdf05f8ee8921dfe400fb1873add6c6e1cadffffffff020dbf0300000000001976a914a642ba657b0dc95190d7067ff2539594f118d01988ac111b1400000000001976a914a2f8422e68f88d6e5fefd3c3c67b6ce8ed4f8e7788ac000000000100000001204a4dc8fed37cfa57e18b042563b311ebe380e6961c65babd7f3c782d0df3fa000000006b483045022100bdb2b7f8c4391a3567d5d5723188d5f3e385aed4c0681e88a0565fa49401ff5f02202153542de0c016fc041cf0078186ce0014997b0134a031d2c4756fb0e1118f4c012103b9d19bda4f288d75fd43add98605285948554aa94c45a3a5e011ad2ffcae07c0ffffffff0240420f00000000001976a91446840e50aaf1b883089b042e4273fbb5ce2b9c4f88acfce4f101000000001976a91454cb919bcc7807e505b1e4ccad4117c4fadc316c88ac000000000100000001e9acf2718a51f0342117707862a54d4e88dc4687602f10c10c7349a7f0776358010000006b483045022100e80e54812e6f2861bfbf1ac81e7bf3ee6dadfc29a66a90ebaf8a5697e030e4be02203be9e88ddf7c60a350468fc45cdd6bd0b282520720f9c4e920e61e7c6d0509ac012102736a6327cc55da03a66dc9191f05f75f79aeb478a45690f5073f3fa6d25f8df2ffffffff029ce2c201000000001976a9146de811dd2dcf0b5bb946a9674a55a65e97fbe36388ac40420f00000000001976a914a27ce59535bf7df916438477091db364acf7497b88ac000000000100000001cdf2b8d3a53caf43e95573519e367727afaa6b3ca56b81f488a672fe3530dfa9000000006b483045022100c17f5d83727c41cc5e1d6f344543d3608af8e0e601d9e58a6662471bf6691b6d02206ab1fc3af73117c68e3a45298f5eca826abdffc3bd2e45051518e35e2800c14e01210206b70a4bc82d2440036bd60dbac15f86d37c7371d59b7b319bd6070808bde174ffffffff010e4223000000000017a91420a28c44599f373d0634cfc252a687aaf173921e87000000000100000001d1ee1f739f2fb1858c4f3718a6d921e907b4f5e297d824f154ee439c4e928f20000000006a473044022067fbda22575e4350242bc38ad56b96c2f9e218110ff43b5f9ed91cd3b9d97ff5022052ff6569053c08c28db9380abe0454e0210c0b97d86ddb8c1fed6543011c5bc3012103bd9ec3c65e09ab45889e362be3272c407c12c643b3eae3b2ac811d7ad30a1025ffffffff0140420f00000000001976a914276c786a1b5b683e67ca92a7d9f80ddf7a65c90c88ac0000000001000000013fd68ae235d1348d4f53445593744a8983dfdda5381ef8f38597097a27a7ade4010000006a47304402200c4160c7a8c145ac41502326071938cc6c5a4b1504f22c6e0687f7ce7686ef3b022014aea6e911fe99eb7c45b8f3408666713c768987e4605e5e0ce14d75b79e5d1c012103addc0d975ec1447c0dd7c0c5eccb3e090b4da22ffea512b1dd1e52ae45491deeffffffff0271991900000000001976a914b9c5b763d69ac9423bde2514c9c84ea206d45a5188ac7ea10200000000001976a9140df5cdbd67f672f755e2610ce35b574f630f0d0188ac0000000001000000014967704cecca8b905658a6049da6e289b6a1ab3b801766d2ec36378257636f3c010000006a473044022010b961d5a7777595b5237eaf85ded87fa59fad12ee150b35143f9edd9b6097de02204af3dd8d2510bfc7e52cca75612054df417e6754f3b16c023551de5680438fc6012103b403c42ab014e8f24bd8f87bdfa685f3a18efb61a9c1a29992feb259d6b22c5bffffffff0230c80700000000001976a914062ba22c85d9460833e8ffb67d4119c95428136688acdc997d05000000001976a91414c402f2c30b8d80c3719d090f7f8a2316f103e688ac000000000100000001deb965b7a5839de16d9c0142838205b623cc3b8bd7e3cb4b1851330bca7150b4010000006a47304402207120969cc910ef2dade86d1a705e1b7bde0de5837879b4805acdf9226e910530022027807755fbecc227f50613559a528addd58f6c9e9c1ea73b6b4e2ebcce0e0a99012102666ffbffcd2c9987e267dc625cb91bdede1636b2bb744dfb0b5e93e11703d77cffffffff0240420f00000000001976a914145ea67c48eb66b0156b13d2305034e27163f53388ac08c43601000000001976a914f3972c052c64a5b3f05b02c4acad74be76c908c588ac000000000100000001294947ed1ef282bb674293138130056dfb4078fa0b82d34ec1e3dabb88fa7430000000006b483045022100957129e2616f81701f469e80bc264076ffcf7ed6ce1f69c736580c1404095b1f0220549d845704eb8eef6f1a0e77b14d34319b930a82aa7c4320ab48a347e2599254012103eb6cbbcf67da9fd27ebe2ef28b94b0ed0e9006f13a3d4b5948ecdc7c2c8d6d60ffffffff026b9e7b01000000001976a914e5ab2575d010b9648f1a54c9cd8f3fb75785728488ac40420f00000000001976a914dd903bb6103c60287e830caaa39295240e90528e88ac000000000100000001a409a263f66a4d28c5be76d8221db433c1de8616555b1847c446eecfcac37ef8010000006b483045022100ba4592ef246a1eccc09a5c7c8a2468e56dea93561661feaa1303fce25c18eb6702206ed78d93cf92fc9315460a0c059ea60f4d3fdf2755773716b80cab5bb44ad170012103f7f2362d11e2b082387b6802a773adfa3c252cb21485c85f737e7cf62e95249affffffff02905f0100000000001976a914a55e832067cdd5c1e1e59288afd7b2b0f59be37a88ac30629500000000001976a914efe4eebd29f5b7a86492584993e05fac65ed6f5688ac000000000100000001e84d537ccdddbe145c8f872abeb9461067426cb6b6eff86a3859b18bb9d05d5f000000006c493046022100810396dbef50bf434b1ab80feb0b2d46f4180da583302f1324de61e5c25a0d9d0221009f84dd37b27f6663937088034a2b726ba6effc107396653270849a91ab44a632012103166654d5cbdc31d65b81e34cf0631a5a0a29019841b20cbf9ea599e049e5f0b2ffffffff02b8a51000000000001976a914630d1618b712c0404d6068985b80f6c1cf86cbd888ac28230000000000001976a91490fb956fb515c4a1695851d083b92142426d13b488ac000000000100000001d7134cb635b71a79f0b9cfdcac9ef9d6832115864c04683b7c577574c168507f010000008c493046022100a63d1a3a217243f50487f1a86c0217676bf846be2fa59bdee6f5f81dd966a143022100a331c9734918d427167514628a84e0d4d9c2899a3e4288ba188ae78abf1530e40141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02204e00000000000017a91422c4270d877177c1dd33037fb5b7bb3fd76cbb8b8761edc8a80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac000000000100000001d0d7fa24b502e8a08472047696daf53d08807494734fd8459b67eeebfe13f63b010000008b483045022100ac7686b9768ef38d86123e7416ec05558795b2aa1603087f364a433bf9515e4002204656b488276b84cd2c05fdc775b3daf890d4d69d5ce62383580e41b78a6d3bcf0141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02204e00000000000017a91422c4270d877177c1dd33037fb5b7bb3fd76cbb8b873178c8a80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac000000000100000001e1798c22f27e5ba948fe9c5e4de74046191b8723309063ef60f8198bdf67930c010000008b483045022022d734a8eeffdaebd54f42586679e75b428c6f4f230d3f587d3f9019ac25f4350221008efe331e7b69696bab645ac85c305b9f9d2b35419e59c2d0dc89ab12f4b49daf0141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a9146f743423659b1a2b5b52bd3ffaa2f6c30c9b6cc288ac81cac6a80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac0000000001000000019347ffb287b7205e817f096b0d4d424dc54bcfd9cf7412b289090cdc16d78eda010000008b483045022100c5537059373bc3cd04bf559970dc25d83bb4338c2e0f2b321b412873ae0b64430220343358577015b688515b4f950f2d5f8ea4053615558e11552929a0552a4bc3210141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a914ce5da921afe91686f53affbea099dfc7626a64e688acd11cc5a80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac000000000100000001d66a7959dbbcdd5a0b2e089008452227074013fa4030ca947ee74d54f06f2490010000008c49304602210087a40aa7da76d295a133c570757b42aa015b212b548556af3e2f3fb196ccc450022100d14bb406b48694d7da93bb8eb551a5ac9dcfe9bf744d1760b0b3b2c482a2c7960141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a91409154d402a0cf4cf0ccb474e806671409604c13388ac216fc3a80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac000000000100000001416c037d85e6f29c3a60509aedc44bffb6ebfa433b6b17629f1f449f6a8a420b010000008b48304502200f5a1836326e868e3489564ff3ec1ceab1f2b1c833a116a5080fb3af4b1e2880022100bfb66b1f5ee9aa74b453fb06d1241653986bc754368fdd125ce1c0867622aefc0141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a914a602986d920c4f2e95d9a0711eed72883181e22888ac71c1c1a80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac00000000010000000109a635ac99aaa207c92dca0903b6db615f1f2e612286f6af75cd7c9558d608b5010000008c493046022100ac53716a177736b1144ca67722e94ca94bdc5645701908eae0d3f142b4530858022100975419f603798b46555ca0d996f4ddbdaabe689d81c7a274af54c823dbbb9b2c0141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a9146ec46e89f8dcce3e4e714b82b64ca8f5fab551af88acc113c0a80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac00000000010000000175e44081f8cf0b6bb3cd1a93946f54484ab1bed18acd94217bd1d94e6408a640010000008c493046022100fdd199b1b921c272db35ec2ca3bf3e555885d0f9917855be169d2520bb9127eb022100fbf87fc8dbb685079a3c7f09c5cfe57e4c4cd9c574f6c6b03080942b3bdd54d60141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a91468e6a1c0f63f1d62c964da9aa16c393f9198bb7288ac1166bea80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac000000000100000001280e2a0c3b17dbac7ded07a5e029cb84c4db6ecaeda742bc241f024b6e757ad8010000008a473044022022cea724cd06f841d78522bd936724b89bf3f3e0340bf4820a619612d45e2f4102201a55dfceeecb157ec1c36565322ce2f7ebb512de7cb9c85d89842a186a55ddc20141040cfa3dfb357bdff37c8748c7771e173453da5d7caa32972ab2f5c888fff5bbaeb5fc812b473bf808206930fade81ef4e373e60039886b51022ce68902d96ef70ffffffff02a0860100000000001976a914afb415d51ee8df29280c362356aacf8198cf1e7488ac61b8bca80a0000001976a91461b469ada61f37c620010912a9d5d56646015f1688ac0000000001000000017a0c07421a1e3cf12aa73cc193154a2095079b82bb3edf80eb4c32aa2ebcb119000000006a47304402206845ebe0b479193a19cc2360845440680e3258933b03c54019589891840761a2022032366f67ba41bdfe00b41fe95ffc371b2d1146f6de6a0cdb011ebb787a09651d0121024f74d640e1f02b40e9bcba20e72fc8c0d7842429d42dfa16fcb52fd15f3284bcffffffff03781e0000000000001976a9143bb7cb7944b25a8a7b394078311fee351efb170188ac781e000000000000475121024f74d640e1f02b40e9bcba20e72fc8c0d7842429d42dfa16fcb52fd15f3284bc211c434e545250525459000000000053d3fedcce940100000000000000050000000052ae805fc901000000001976a914393971070071930ccd8d1248cf8c7de28cbfdea588ac00000000010000000100e2a34591dad16e1de7259cceee8ea6497b1f3fdf26e412fcf15e70dcd03407020000006a473044022058b96022f23049c347d4bc8f371fff98d768dbb1a43d5becf03a85ff16a6675102204113231cc11471246af502c79686b248dbee3eb392654693caac740382d4fe320121024f74d640e1f02b40e9bcba20e72fc8c0d7842429d42dfa16fcb52fd15f3284bcffffffff0290d00300000000001976a9143bb7cb7944b25a8a7b394078311fee351efb170188ace067c501000000001976a914393971070071930ccd8d1248cf8c7de28cbfdea588ac000000000100000001a50c3619d797f67d512435740d826c651d547d76046cd9415b1bd1d5cd326fb4000000006b48304502210098a9cce4ec26f205d9f0251763abd449c302b9eafcd3b4fae414ab8094ae79220220064f7f6739266e8c19746b063a5d8886a84b41ed76a677bcfed389f6e26f9ba8012103f7f2362d11e2b082387b6802a773adfa3c252cb21485c85f737e7cf62e95249affffffff03781e0000000000001976a914a55e832067cdd5c1e1e59288afd7b2b0f59be37a88ac781e00000000000047512103f7f2362d11e2b082387b6802a773adfa3c252cb21485c85f737e7cf62e95249a211c434e5452505254590000000000000000765c056c0000000005f5e1000000000052ae80329800000000001976a914efe4eebd29f5b7a86492584993e05fac65ed6f5688ac0000000001000000012e286507e0ee9e50dbb9994c0b901122e064797f5399204409ae89f5a2e2d797010000006b483045022100b0eae1db5ada154a646e8b651c554978435f74de527cfb11225e11fc5c05d193022037842a670b6a7428f9b876d61341c3fd8a5f9383eba34e2167cca9d9933c34f20121035b7c88183988d374c281c222a6bf0dbcb19dc4dcb946f36fb097efeffd62fc5bffffffff03781e0000000000001976a914b59e93e7dad549bc109245ca27935d06625d703588ac781e000000000000475121035b7c88183988d374c281c222a6bf0dbcb19dc4dcb946f36fb097efeffd62fc5b211c434e5452505254590000000000000000765c056c0000000005f5e1000000000052ae4021a913000000001976a9142bc7076ced236341c9baef7bd618e7bbfa87675f88ac000000000100000001d0e4440e74cd457503e07431bbbc8759cfffd261b610ecc9c9bde6d11dfe121b020000006b48304502207132240141ce3483cd13a8061ee5b9ec3bc722f195f55238e20f22ee83956ebf022100ee7a635ac62a824a95dd6e5b60f2295dbe1217f44a9cf5d25aab1bca13d1d00f0121035b7c88183988d374c281c222a6bf0dbcb19dc4dcb946f36fb097efeffd62fc5bffffffff02905f0100000000001976a914b59e93e7dad549bc109245ca27935d06625d703588aca09aa713000000001976a9142bc7076ced236341c9baef7bd618e7bbfa87675f88ac0000000001000000012e286507e0ee9e50dbb9994c0b901122e064797f5399204409ae89f5a2e2d797000000006c493046022100ec31bde14bae7ccfc6cf01bef40c91914c5d5adbb1b3ea8de7a5dbf1603666fe022100ab36b5fed2db1ec66a1b34fa9b246dfb6322e09245eaebaf2058ff138632d75d0121030787462dda0f7a77337453482ad9789b6cec5993cbb4275255b731f7dfda3281ffffffff03781e0000000000001976a9142bc7076ced236341c9baef7bd618e7bbfa87675f88ac781e000000000000475121030787462dda0f7a77337453482ad9789b6cec5993cbb4275255b731f7dfda3281211c434e5452505254590000000000f0a6c9ae7ec80100000000000000040000000052aea0220100000000001976a914d80cb565a29d5b5c56595b7f1cd332abad7be5e888ac000000000100000001c3e7aafba938dd71b9819421a490e9c12fbe1841297ec92ea24ab94dea929a06010000006c493046022100c1f207f20c2f29175d6cdb5ffb1fa9654cf499cbaa9a316909341e7fa427321c022100f642360759d1e90a5ddf48901de6f9bd7627ebbd7ea9cb422a0944eaf4483a8b012102754dc3568d9ae70e8fcfcff6508b9e70119b1b17ab3090f7335c46d15fb15779ffffffff03781e00000000000047512102754dc3568d9ae70e8fcfcff6508b9e70119b1b17ab3090f7335c46d15fb157792120434e545250525459000000140000001d4c4105ae00005af3107a40000100000052ae781e00000000000047512102754dc3568d9ae70e8fcfcff6508b9e70119b1b17ab3090f7335c46d15fb1577921120000000000000b50726976617465206b2031000000000000000000000000000052aef0822607000000001976a9140d7ec8cf14b0ea73621e9c831338a7921653b6cd88ac000000000100000001b6f0d9b6197830a4c06df6f4467fb99e87f63bfcea55030dc55863d11758276f00000000fd1b0100483045022100e2a0104a7ac38bec2f6a1fd82402d55272e2355d2456dc5a2dd29dbb50dd98ea02205153cf827bdf8a9304cc14ef40cff099b0ebc4d85a118883d9af54ed0ce4fad3014730440220108371557cb344c7725132d04ebaeeb4c6f7e878051068698a92452970d2b44302204a4497706bf6bd791b63753ad3ad5b326781557a96ad7202b91a011265637809014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0110270000000000001976a9141f29cee3509e8268d9500b9b23cc85da1c3b4e5688ac000000000100000002e6c757e91edc7c913416e2306f8cdb3d2e21c49d8f8623e0d92823b9819cbc98000000006a4730440220211e50bb3111449f331f296e2f56558f53a92762ee743d7cbc35b54a5bde2ef1022012783fef6ff4f8586fefe6c4d2bd6f63cdca175332908d494a2db0e10c02f8f60121039c07e5148dbacdf029b3a0fbfc67351b60cc0a347ab4be269a1504318bd26267ffffffff4179331d95be875383f3fcc8d6c280a455064d64328fedf03d1930d4e581e756260000006b48304502210086de5a7d428ba954357f7888c43614533609d5f3a6810ee9395b673f911d88ee022027f6fcd1ffaea6461ef2825c4943f2bc29eada728ddf9751f4dbdd90838e1a6b012103f909a8dc00e2085dabd71213674c090ab0405b903993218eec92bc7c80dfdc54ffffffff02c23b0200000000001976a9147558fc21c84a2aeb097c82489afbc3294608247688ac7fb00600000000001976a914d6f9e26b826174e180fd3f57ce7fecf10a74c7a288ac00000000010000000229e0a2630e8d0070e35f90fc61b77c5d1a67fd3cf7fa870ffeae8e3a4c202f46010000006a473044022031c22aed1b4f58aacfab2a4af552b2d74bae8042d03845e2cf56867748d962a402202cdf57d88dc679461128fec07cd7dc91ca7a87d6e578c65ac817ed30c44841780121030f25bb21ff95d1cf698f0c8b300258d41c64063a2ca81ed68ffdadda803c4bd9ffffffffe90d2e51a4374b3975923f4f1acc37aff14288a40a4593f79742a382cb81465f0a0000006b483045022100901e7427547385db1156b1d823042b88ee8a89e44b92796e9f8587c529cd14c002204786800018ef9c0c39079e08a768fbbe01b02568ea3bbd4c8b670b41b5310c40012103f1b4d21e0b344248185408c1af96bdf05f8ee8921dfe400fb1873add6c6e1cadffffffff027fb00600000000001976a91495267bdeedeb4a5974f46b3dea5f21f81eaa610d88ac51070200000000001976a914311a5aefdb4085af5853d880c8390ea6a1615b4588ac0000000001000000018f631fa01a6797c8fb406b01d2f2dfb9c4c3e2928e77048bce829b0e287c87be00000000fd1c0100483045022100dfd6c4112bbe482a960cffaa6bc534139fc8c035b482610faee2a1ce372728520220257d43ba08c16122601281aea02f2afd501ce67ada619c30583881982483957d01483045022100e0cdfbf616cdffc5a580cd802899daf0cff68a16d7637ae9b80f18b2c46cc8d402203dc2679a41469ef89d037d6bcbc0be5c0fe73de7c3e3c268e2b47aa6ce54ef63014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0110270000000000001976a9146fbccef8c5e7553abc4cffa28baf0a604262248488ac0000000001000000024fb19d79fb214b86b0fb0a6577c4250b2cba5358a14d0afd7acfdd7b2b055bfa000000006a47304402204bfc5e7e31f233a2d2ec9e3a72b40f05788ced58783c8f49ba341be427229aae02204ce55d0cceeee999e788fccff011514ac4dc3b776a68a687b84cfb9c5feda1c0012102b5a5c192d56c23f98a057b8f78caaca88363030e50de36452db77d012cf8f3c0ffffffffba76e2bd51af115649e9ee6dee6e89114ab8526749e0a977214aef78c07b090f000000006a47304402202f41bae81d296b5280a25874e5ef6c8dca05a749ed90082ea77aab824a837a06022055f73d4a2c7aad0b90e27d324d9ca91791a79e76552773cacf882a85d9f31af201210282d40b989ce5de98c89e3b240cee339bbee4a086c8520839a4bf3c11b8a18d23ffffffff0240420f00000000001976a9149b99fea987e53dbaea95816444d90975733b3d6e88ac399f1600000000001976a914b48cb92c7c89edf19643d54989cb54608bfaa4e488ac00000000010000000241d4b068fbc46dab6de7b3c6dc3b5b770b37b981b993d06b4333b8a643f10d7f000000006a473044022100bb259144bf62fa224757ae18877b27865dc27ff61d04b76315040666386dadea021f2d66e54f5a6856a2c91a71f05952650c9d5ae92ad29c5896a8963f629fc32201210321182abbb202e124e62864a66396d34d2492bbd08edf6686382dcc6e04d85b45fffffffffc68edf481ba98601dada97a71d6cf7583a36e1e135f082de6f0f7d0eda70b1b010000006a473044022034ee4482a0ce32c87644081dd423c80840081ebd47a0359e5fa29a717b658da10220018401a23671472033d4b963cfafd2c9c333e319baa676b79ced8bd1e362657d0121025313094076052c8ba1884cf800018d1e9371b6ba6819bfc5f1c66a2566d6c433ffffffff0240420f00000000001976a9144546c0d280d292c8fd2bbee8419ef05fb4e385fa88aca02c1000000000001976a91412eaf230e8991ce934e3050d5c6006c050d7b82a88ac000000000100000002ed9934a2a3b72442fd5e1946ebfc9f230bbc8012722ab828e3f028ed76e8c9d8010000006a47304402200614fe73c43fe79d0bfc793e7887d0a4e5507386199e42182b27fd6cfac49f6f0220759322264b80d45ec676dd7225d0d27ed413e0e049744dbcc76d3fd998f54c7b0121029a6793c92d2859d20204ba1738af4aaaefff1113d95668d0fdf1fc268c17a31effffffffc45fde728eec6c6e103e371d36c91a0d743b44557aeaec1b68d485db2223d0a3010000006a473044022020b63c7729c84a7e800ab94fa1c4a05fd15ec2e93da3089193b09f681d54123f02207192509619af256b9f81fe1205ac57d65c98306cc862eb4bb7e0722f2c0aa4e80121037f6f4e51362069dd7380bb1ac09dd430e85bd796d3e41eb88e4058414e5e94b1ffffffff0250da1100000000001976a9142de3d38ba5d6ef95cd1ec2fd025b4873b779fbb888ac40420f00000000001976a914e4d16ca2b60dc603ae9590672e05cfabed2d7cf588ac0000000001000000025559373139aeb2fa33fcf78ba3e571663b20486cfb7d896528f97091975c5605010000006b483045022100afeae347a631c6cf353f75f4898126845d94c45702ee72ebac3928f1a1403e350220038a6dd69dd4d0ae2438aff188e2b05fd108f79b247e6429f1e5ab6b304d322801210208e3d272bc6b00638268d8b192e20fa56415e4522c567ed84ffca8ad2b004bbbffffffff38161aa5e73aaa5bcaa96dbc120fd8019710542c1015ac7fe5067459492c07da010000006a4730440220381e5b8979b34e0ea5aaf5083b5f84090c7a39786a2a774a38b37bdb7387627d0220622787d68e383296cc4c1953f83670881fd64ce478e8a03b5b27e95fb505aa47012102f6052c249e6de26e1f27d36c795ffb17d47d3210cd4ee103c1586f60b2fcdc61ffffffff0240420f00000000001976a914ceb65b1b5b7d14f8ed093cfd7213a8855c7bf94888ac50bc1600000000001976a914aae22d7d8641a83d5c2420ff7c2082a2908d5fb388ac000000000100000002ba0b4f41996673c775527a6cafe9eab0bd4554e8be55d12048837e53f79e5f6b010000006b4830450221009fe8275ddf2dbbeae2a693b4d4468b166611b5ee94c8fe306cb7a54e527bde9302207278a8b5f74dc7ba662040369e397bc41f6651bf6c9f0a0a8dd2e9b0918f6a5501210332c45c0a00234618027fa964a5be59f690bd860cc23c49fefb75d0fd8a2073a9ffffffffba76e2bd51af115649e9ee6dee6e89114ab8526749e0a977214aef78c07b090f010000006a47304402203eac533197a2658d16313906ff9728753f3fdcb0f5aaa2ea30ce813372ba5571022076bb0965ae283df0de9cc5b025aa0f5429051cfcb4108095b7985f3898766de5012102841ff04be8832522f6cda876a21165c6f751df17d11c604ac8ed4b51292d572effffffff02c0c11600000000001976a914c24947532dc8bcb742419c25dd73d25e429b01ba88ac20a10700000000001976a914a54a4680732fb4ab0a5893690f8606cbe24fbc5588ac00000000010000000213dfa0edbf17bea78fa7c124f6f54fad33fc5274892ba95a653d6fe436861313000000006b483045022100dcfd73f39e2261f22fd1a240f55a52cbfa22a6fbb74bbd49abbeb0421a99fd3d0220557e3890c9db89880c5714c88b470f54d59ad986b4cfb93491ead3322101d7ba0121035dba8a054a8ea2d65977fcff2c0c5b875c32a3efcfc8fe01934e2563e0210fc0ffffffffd1ee1f739f2fb1858c4f3718a6d921e907b4f5e297d824f154ee439c4e928f20010000006a473044022060cabd516735ab67636fa62eb3928f3797ad168f8baa713070242d1b0492036102206047245ce7a60bd0310aefd3f49862baaf1dc59cd71a19e5e9716b8611cddee50121020b3a10541b08f1b637f077ff6f2932b0bfb11829ecc8bcff39728ad47327d9e6ffffffff0250bc1600000000001976a914f01d73bde764f82a6bd101d4f361e4a1e789853f88ac20a10700000000001976a914ceb65b1b5b7d14f8ed093cfd7213a8855c7bf94888ac0000000001000000029b6b975a0b360bdd9b5bd4b9a80f73bc2f11b5a637aa2dd8c1bff635795d3fe5000000006a47304402201be59c88a100439f3546508721f189b8d1b6b7e335bb8accdcd5a66729f1f0fa02201e0793e95f44dc1d90af05ad5ce477aa26cb324f58a0e15f5bbd858ded38d037012102b76651433e6c776213507d5c0c83e6a98a6fa6779ddddf78dfbb152fb510f4c2ffffffff81ea989407217d690564d59d9e6d82303842df3a56d0703fc96d39cc563e4ab8010000006b483045022100ace96baaebee4bb4f2365c73bf87ab66c880a725b842d97d17afbc4d63650a42022069850a754204808e5218d94029a458ba41690cb6a32f189f958bcadf35bd39de012103b9a14855a4c79bcd753274b6d8e00c42a20fd584a6d86c48990e032d7a594eeeffffffff0240420f00000000001976a9143740f53b25dd242cf19eb0bb518e4d84633e2b5488acf0601300000000001976a914ec6f79c75930c650ec0a2b018d8d6535dd5c0b1c88ac000000000100000002f18f2189eb6623167a70bb99325b934d9affafe83b6c9cb4cdc93ad8bb9ec2cf010000006b48304502210086340c01a8dd74b983b54f61edd0d8e0c1631877afb9a17dd60174a3d96b1c4102203b3ca5a9c24c7004c18c0844745e38f92f45211484e7d6a177c7f6a844bebbef01210255d19ddbad95e5c05687c5a6a1e6a63fe9f474877601a2339543d372857ecb22ffffffff5397951f23d44e270d3a40178f0beed922c876bd2007bad9d6620d4a451ac7b4000000006a4730440220017efb6435e7bcde15b846727067675a4c3fa046e0bfea1c9acc543a499e848a02203a7d765e9d8a815f6cb2a15cbe2c6fbd3b65ca35d8f2ffd9a1302dd2081fce46012103c6661178c98e7e9d301a0c6939bdc62da7e0f0dad8afa34f1a1d11fad4b546e8ffffffff0240420f00000000001976a9142709334a6bb7493012424df2712989501b87099688acd0a11000000000001976a914a9d84f0654b8131196be4982d9d6e88d4253872388ac0000000001000000027ecc038b50f20ee0f3032fc7b5caa7740339e7851abcb64b810e3a26cbe676e1010000006a473044022075a9dc1c3d8a5a2a8f1edd1e30088533acad905b83bead4d585ed124fd52f679022074a84fdd5a1e0365d6df9dde0fc18c4a681518bc1aed29a9ce42b155edbbe8870121039e060af0c8c0b3af4a4a980bcc19e4c277565705fbe0dbe648b3235cd0201f5fffffffff25d03e44e8983694a421e551facd631ec6b8f7cfcaccf8eda8fba1762db006d0000000006b483045022100b42c8a06c066a827869343d374c9520b7b7c84e11e75aa68df3d42e5b52865c402203b1aeaf33c7c3b0012fde9910ef811ef243bd5f103a7157519369e160c208b0b012102843a5d13cb9b19441ce8e871d39f821c2dba0599be5066e24ccbb22379676ecaffffffff0250da1100000000001976a91497cc9c5302fbcfd8b8d4cf98539499674fb1bba088ac40420f00000000001976a914f34c5ac23e9f429f127c2c2df80d47df470359dc88ac000000000100000002fe61b8289c169cb90feb37e8b00210618764f090798aa3ff606e21832adbb6b2000000006b483045022100e750d15b7673525643f26ffb6ab014616ffb40eca397c96a4767df625ea1a3a40220141282de969b92e3c06301637b0eb5c7f2088b4c6327c562055230ca355407450121038f88fc8b8b0a05b19aa975e51a4e5744b629dbe789918ef2d7c7b4cbf4e53872ffffffffb6e58f2a4270845a5756bb90e4fae997715217143618f7b8e3f494545e2d0cab010000006a4730440220536361adf93c952b14462f4afdf498ed9cb280c84f6ae329bb7f9bd56155cb7c022015397abeec9088b7f2f68c6822a9ba868016deb47cc13143599af92d23f9399501210307c106b32cb3429706df12b46aab8bbea8299ba86f19c8ac047f729ea0712b8cffffffff0240b31100000000001976a91481d09c73c10beee8414d8e6b2f46d219db9ed9b488ac40420f00000000001976a9146abafcc33f777900180fe642440b781f47bd9be888ac000000000100000002deddeb747d0f9a92dc10c981aa473d6b45dcf65bd6f6ca45971f83a7c1ebedcf000000006b483045022100c8d09b2f037c33ee2c25b4c7623cb354af6c134147fa5b2680792b2728cf7b6302202ccf5c97c0b220ba01519eb307e17d76ac788f199670ce8b155ec2f52325d8f201210345004779de4fcb7677310a210849beb5118a149af6607b65e0e41cff77d5d2c3ffffffffd60177b4e5e63c9c466b628c4e9033590b25f23f0d83a933f4935c30dfa7a533000000006a47304402206ad7dfc4e7eb9c8f988c77162e67f296f9e07e9ffbbcf2bb9cdbf5157210586202202ce81877bdcf6106ceff9e9e02b7ed2936583770a2ea690b075d576ef7b198940121024bba329b6047900251f9eb90f54c1a14960a8efc3cf4fee620c5c6e2b9633e2cffffffff02308c1100000000001976a9140621ba5066df4ef72087082967f8f0488545674588ac006a1800000000001976a914f339a2e7e2adb584f07415b84ab7268226e340f688ac000000000100000002d22091c47e75c4b4c113f3c5e334a19cda256809955bd49f416bc95a0d6b8303000000006b483045022100be8bf43aad3d0011ce275ac230e550466235cad09ef5c741e7bfd46ce43dc2560220011ac7da44c43db4a12e7351d7924ddb3ef1fc70bcf521c19c6c0401fb520824012102dff4ded472831dce0e4870cc6546b726a7659fb8ddd93b3abba82e96bef94d6affffffffd22091c47e75c4b4c113f3c5e334a19cda256809955bd49f416bc95a0d6b8303010000006b483045022100ad5f38fc133c9d7a222ff37c4e244b06d22f923e04daad84de20227759aba27002200193f056a202bd224ebad0683f798c234c4f938cd2e515c95428415762595a16012103d5b11e96151847cbe29062265f92d29efbd62c1ad06a2b3b5e478f7282c42cc7ffffffff0240420f00000000001976a9145af5e14c39eb6f41f873e2f14c44a8cb8f0bfd2f88acd0d61c00000000001976a9147b807912b8099aaa2876c921ee48d57d4184561288ac000000000100000002d8fb1ade0575c53bde1c1caff080ed3af2de1da95ac078dd309e77ccf8e55fdf000000006b483045022100e2eb212aa293d02e8547cb1a763e4f798d667fde3997e5876456debb876ce15e02205db9df52ed1185f0e925a594ef315006fc40317b133348ac6572d71a66fef41b0121030249f823cdfcfc2bdc72ca2f75c04c739af3c5c22cbdc03866739d30b0f968beffffffff5faa04057e21f08df130728030585623b316081908175cbabd9a668bda6bd82a000000006b483045022100f0bf6b0ed5e82a14739a62dbe5c2273ae7e268856f8fe99eec2167032b172e97022046a52017f2cb376fd5dd50301a876876ed2e5123682185e4302740efd126d83c0121024146e08c6d6d6ea2c0270c3277d831259de638d27b5be4e265f3ed6305091d4fffffffff0270281200000000001976a914319d0899408cb8a79e5772d7f113fbe25992dbba88ac40420f00000000001976a914c7290c0a5688926f1e30a23b2cf0ec2b4e456a3188ac00000000010000000266e3d4ba8989e71decb07927e8ef373ee8b6c205496eee0e838a9b6cb1753b83000000006b483045022100f314e2775e6d220b492b6fe35515291b041743b46d0e3b3307cc95167bbb6b010220325ed68888406e1bd7e1e5ccfd592bdee4486307f22c3e382d48d6b831ccbddd012103c7f26643421de501c0a1fa9766a2693e153f29df258cb813ba62864fc956dd99ffffffff20c40362cc8e89914af42a74bdff742686efc0ac3479bf4b431d1e6a587a40b8010000006b483045022100cd934bc91a5c48fb71b8607bd7026f99602041dac596ff9086d3553ce49a88af022050e5b94aa701edaa055da221e64dc09d49b3374c094d1fe0d835d93737d669e60121023ba5487e3278e4abdd44b1ee011124909577480de2eff99c1c889cd84ae8f31effffffff0240061900000000001976a9147ca41603764079bf62c4a4e3f8f66baa669d66fc88ac40420f00000000001976a9149f3f25b06eda2318869d40c6af69eba67137221b88ac00000000010000000250be20e7e9f25515c6af564c41ba49b3ff95fa476768801a943ee0bcc8eed476000000006b483045022100d6b8121fa93efe013daecfa6804603758a35931fbbd6435c9fba43c093f3d16902200744263cbe0975fc0eeb2b7d08363fd3f6e62a072dda7a7e9bab56bd1e620b9f0121028d83f9b1491994790ec76ef598c8ba0436183b466b32bddabb1a462c70e29ea6ffffffff40a16cc443545b1ae809148704511609154d4a9d8dbe31dcd54bdee791eecf7f000000006b48304502205d0911a8ac32ed04d602111ef5e664e2bd146c9d7fad88f6388ff008664f7682022100982367a9b3f72d178ed2e7c2cba3ebb51386d6b2ce8df92b797d3767984ebb7a01210325f1f40c9bd38dcdaabe19034c59caf578a8457ca0d6ab88be63f583d2ff1559ffffffff0200e9a435000000001976a914df073d4a974f8134a21608e19dddbb6cf5bfad2f88acf0b9f505000000001976a9143df52b2dc885ba0bc17ccd77cd2146d7bb52f06c88ac000000000100000001be200e8543914878d90b147f5a43bfc3828af510a043a4e0512293df5ea4ad60000000006a4730440220126b0742ea548b8ae80c708f2978563bf0aad9bd44056b585a4d7dc4e7d05bc902205ad040b48dd756f409b921f6bb0e58ea9913215b26b8e1a90a3fd10026810e840121037dcd7819ce02547f96a93deaf7ea5c6244d79f13c21a855be672eb28af964c16ffffffff02f07be111000000001976a914c0ee975d1a949a6bb1161611dcdba5a13b798f8088ac0046c323000000001976a91467e955c5c4a7489f549bd401f003fdc44d0dd93b88ac000000000100000001387daacc7861110fc52535e8a9733d40fb9c56b281708993e1678c79ed927677010000006b483045022018ee4a970e5410210c715e127d289427dca1ab3fae4d06ecaac1c86887fb0132022100cffa070278a90cb98eed8f0bcc18972153073c9360f6ea1b6e4bc7b65917105d01210387a2e1288a74d1b6824bedf9058a788fc84be8bf549f2f091f4618ed95e23d7dffffffff01f01ec323000000001976a9140744f9fd5a3b73a656694171412182a32f2971b788ac0000000001000000025960889040faa5f580fa8ef80023163878bc3be210f6d0684fcebf5f7885fb62000000006b483045022100c3065feaa69ae01789dc2926205bacabc1687df6c0eda39c13f605ad25970b55022012c5e38ba14efa243ed043d9f984707b301efaf2ef84471059b76a45cc3526a90121035b7c88183988d374c281c222a6bf0dbcb19dc4dcb946f36fb097efeffd62fc5bffffffffe22128623c5c237568cec96afa71054779a91aa5737d1f915e10ddf563c4f662010000006c493046022100e598d9f46a70537e27c04bd6bcf5f69e3a50fc638bbf6de3e7cbe00ad707160a022100b15daa637999657d26bd5fe6ca87cc3fd5de9948f2fb8d3167ac2a377a049c520121035b7c88183988d374c281c222a6bf0dbcb19dc4dcb946f36fb097efeffd62fc5bffffffff0240420f00000000001976a914d43ced8367edd29adc6c364fe31b3651046e287788acc84f9813000000001976a9142bc7076ced236341c9baef7bd618e7bbfa87675f88ac00000000010000000298dd0309ce613a9fcf77ec93e5a00202dc91dc383a2f8676e07188df62c50277000000006b483045022100a6559c0df204031a8d9cb2ba05361b4f370887b2558dff3f01e69511e2f82fe002205961193e15f0b1257686ea5019b706538a6fa54dde545352180102420a4a49fb012103c1c329eea1fb6a6eb10da4394b147b2ddc3c8984dda3006933d17edb214be0eafffffffffa2333d87762d7f47a9cb376c1c6b2eed6441d0cebfb7883b14a1b18b6303d20000000006a47304402206772ff2ad24ae7b5cd9c1c723a141bffc84bfa03fc3ae05c90615b7f7075941402204b0f149a190a450b8c08084169f277a9b11d38b3738413915717778bed3aaf8c0121030ae4453a932caeff36af7a222f5e3a78e06c4a41fbd32872e76afa2f5ddc0b32ffffffff0440420f00000000001976a9149a1349d4d28bd2c7eb295578a8db7e900a88dbef88aca02c1000000000001976a9145ea1c5883f45c0f739052222186de2a97d2b477f88ac40420f00000000001976a914b61ff592088a0848653d10f1ee64934e5048320488ac40420f00000000001976a9142ae828b6dace8aa95f7e427406117f3ad979f31e88ac00000000010000000338161aa5e73aaa5bcaa96dbc120fd8019710542c1015ac7fe5067459492c07da000000006a4730440220488cabf142f1f5ec3ba43423fb527319a4ce24e1151429ecd46d2345cb5382f602203304608e4341d6174f91f72b9936482c442ae8f448e846b41ca7d88b9e1d9e0b012103d733c28935de6c3ffb2bb672642b7ad3e40eefdfc4a9a99bc8fc2c71eca165bcffffffff1279ba15d5879005507f98e4817b559c7197365908a289983702976413748147010000006b483045022100cf35ac9a86679ab434f70e6ae77a01afd7794c180813a25b4d2b3f1b7489a897022004171d5fe92535e16e9b5b584437c00b9c0f6fa61da691186fe5f30d4701ea4901210291b5f1bf2ea4f3606c7ed34d573a015f5720b9286b2f8fb3e1ac6bd08eab2f42ffffffff287a6ba0a3a61b4132b374c62ebf576790b80c1679accd0b8a655fe2daf9f282000000006b483045022100db8692c3731454de56c26068ef24bacb339503229c5f07341e5c984bd66914e402202f12b313e94bd3256b0a00f02ca0667d729deeda53e0f46cad19b6aeb5b9fd76012102ed3c03c968b75d5845cd59fbe31f93d4d73f19f375ff3e4de3ab062755fb42f5ffffffff0280841e00000000001976a914f370186a729515e8621421ee5093730b2535d76988ac103e1100000000001976a914477aa18bae7b229784a7857f27f0c4491337674888ac00000000010000000343a4217ec03a86dbd666e2d50a4f81e6ec78888501d9fe8be407315105e327e4010000006a473044022035ad18774bb1ea6ce5851c3453fa4d1bbb919c152bd70c5846c8dae8fd5768d702201cbf6085713047f0ef706d916ca02b5a64485364a2c15cb22c7b8be5585fafc8012103c8a1ce8275752d7fce768b8e2575f6ed8d770282dca77c0e92edc728e9a52660ffffffff9f3a39e94c21c9badce0da020823e1731ce83b9463f67df74cf60e67b0f1380a000000006b483045022100d2b742a1846f5ef083ad196faad1ee2ba65d1880c09070291a166c7075b5ce5a0220070410a486fef2907ae683d51b16b58367bb2e63ae83da0be06436972a5b8953012103fac77292a178d2a13e9c1cd34b62a3e97c9b67f85dc5ecf2cdc00ea30070ead6ffffffffd342b7c9bc1b211cd022e66d639a4f2529aa29e9cd144c65136cefbdf641a23e000000006b483045022100a961bd3d95a8185d81605b348fd2ec26327cb2bb8a0912cdaebd53d67325d4a902204738f384eb47aa8b30fd3255244ddf12d4e9ceadf781f909414c589f4c033f9901210242b91c415dead69340de6589ffc960181773aa85d79561d1bbe628b320a77913ffffffff0240420f00000000001976a914fe22a31bfb0d128784ec50e9bd23a5ab17ece81988ac006d1000000000001976a9141212aa3479493b3783d632cebb8b1b7f85e0f08e88ac00000000010000000363696517922487df9fafdcd2dfa016271bc74a20ff9981bb07309f74fa2ebf77010000006b483045022100800f701f92e9019ce8799c5e34d34bdff474c95fa1ee208bc42a4db94ce3a2b4022015afdf9c6abf97cf10f71f6938c1e14ec24c0ad48a029262f6f83dd228e7a935012103a6e9d75fed339936435f7b934ab24597ac47979619d6024491bc6b3ce7a18a72ffffffffd4676e4b2debcaeb558c34f9bac6b599085b3e872a18e321d59af6012438d91a010000006a473044022071e14e8ef73cf9e0aab6da408e1a03b0b14e5c58b7f7b2e6a85782ee894cc3f402201921f77148d2f88d9bb2c5fd75eb22e71f17b1b31d502519db78e1791703553801210337122f84beb41ee6b26ad030e1161363b2f6bbd46dd4147960ce7203aa4d2d1fffffffff3fd68ae235d1348d4f53445593744a8983dfdda5381ef8f38597097a27a7ade4000000006b483045022100862a808bac6390a0835d2e1ba9a2686d74d6258456df24c3256db2d75bafe96202207e59df20b49da81977ce7fab71a43ff113c8c7adc47b8e9096a42c1b6e27842601210337122f84beb41ee6b26ad030e1161363b2f6bbd46dd4147960ce7203aa4d2d1fffffffff02f2860f00000000001976a914ba9b1adb0717ed39ba70f6017f7d1ba233dcddb588ac7ea10200000000001976a9140df5cdbd67f672f755e2610ce35b574f630f0d0188ac000000000100000004ba0b4f41996673c775527a6cafe9eab0bd4554e8be55d12048837e53f79e5f6b000000006b483045022100e9f596937f73fbf760b8812d2949239013ccf689d210f344a4799bde555b8b3102205eb9f820510cfdbc1c5d14e069649d4ef107448f7dfc43abe4eb789d3db5efdb0121025efb6cf542a84987701be92bbbcb2b7da729a91e46fc82412de2c3121e29c1afffffffff89f749d3a7c6ef70b549a3f7502bdeadc3ab0c98bf80b716d961bf3830150012000000006a4730440220790dc4db98320dd0a5f5bdce54c24ff1aa22bfceafad0a78b7888c367ab4142d02203f2f55e3a6bca3908da221d23d7f7f103254d9cc6bdde398a7c3de6e4f5824c3012102c55d1894bb30e518dc8f04cbf0a839eea6fdd2f84cb7ee8dfb4df2df543d0081ffffffff0fcf7953a6e8f88c430c24b630a61d5a49181afe2e767ce76119ade9fe07c231010000006b4830450221009e5f130a7a3a1b38e69ee04467aae9974ec16323c6931d1143322ad365de2277022034ae51f6bc8683874fca0cc042ffaf10ec2c0843fca16cb817195c0b2e52678a012102c55d1894bb30e518dc8f04cbf0a839eea6fdd2f84cb7ee8dfb4df2df543d0081ffffffff3373ce2c64e6d6ff443dd48d493401b5ef2c7d1cc6838de0bd157492546f2570010000006b483045022100b94000fc2d47ada82eb93b214a715b0269c1fc1f27ef5de03bdde0bfa867a1f202206994d434eb63e9398da5e42d0ddd1991863416e93d8cf3f56606456fe89e813001210208e3d272bc6b00638268d8b192e20fa56415e4522c567ed84ffca8ad2b004bbbffffffff0260e31600000000001976a9143db4f4e6c67e1540ff43420b226d79dc7d8e168f88ac50bc1600000000001976a914cf3b5cc3a0aa4e24de74d38f7643500a73d6c07f88ac0000000001000000015c9cf5021b59f07ef2ed5970b410bfe6470690d309e03f495b4874a50b372b96010000006b483045022100b633d5fa3838c6753fe9fd5a656719a109ff0579cca9bb3272d5614715ba2202022040089f8af701ce448ce69217f731b013a917d9da6f23d9a408779b7a485b0c6d012103d850746fc0287d8550dfba1ec81c340d3c192d10fa9c918908fc913910667f01ffffffff02a0860100000000001976a91421620cd6d05d98cd15d2c7957d3c07bcf9731f8d88acc89f2e00000000001976a91418751b7839491fb642b370760c5887037d30aefc88ac000000000100000001fa16fe96c11d1541c39de3acee0ddf222a4093b4554ec0b79c3cb230b0105faa010000006b483045022100a19ebbf182c5c26605070915d5c93698fc7145e2f96a7e1981d7eaef99b18c9b02204bd5f9729790f2b7073440c71af9e781b10b1be6a20f5295ca10a9cbc390dc260121038463a2dc022b91a5db8c88b115c2beb647ee226f3876818d81a301cc682b49ceffffffff0200688909000000001976a9141cd4c2807911d65d5ff4c575ddf9141ad022458988ac40047962030000001976a9149dec6baca88fd80aa04d2320fbff60225eb8e9e588ac0000000001000000014e417cfa0ddc6a5627e5a312a7a3300a1e96e9f32489b3faaa35317c907d36a5010000006b483045022100fc52565e014c25cccb61913a08e66106791c3dad63d41e4ea8c20fda5631509e02200e495fd33a06809be1965fb2e9cb757c46b3b0aab6cbe4ce775b9b87123654fb012103d850746fc0287d8550dfba1ec81c340d3c192d10fa9c918908fc913910667f01ffffffff0210270000000000001976a91421620cd6d05d98cd15d2c7957d3c07bcf9731f8d88acb8782e00000000001976a91418751b7839491fb642b370760c5887037d30aefc88ac00000000"
+ }
+ ],
+ "invalid": [
+ {
+ "exception": "Buffer too small \\(< 80 bytes\\)",
+ "hex": "020000003385c4b2a3499669987f5d04fa4127b59dbf2ee625694fa0bf08000000000000cf52f0eb"
+ }
+ ]
+}
From 2214ccfdd80205276c96fd569f98aa37c0d6692d Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 17 Oct 2014 13:07:14 +1100
Subject: [PATCH 178/291] bufferutils: add varIntBuffer
---
src/block.js | 8 +-------
src/bufferutils.js | 9 +++++++++
src/message.js | 3 +--
test/bufferutils.js | 12 +++++++++++-
4 files changed, 22 insertions(+), 10 deletions(-)
diff --git a/src/block.js b/src/block.js
index f25e1c582..8fcce5a3c 100644
--- a/src/block.js
+++ b/src/block.js
@@ -120,13 +120,7 @@ Block.prototype.toBuffer = function(headersOnly) {
if (headersOnly || !this.transactions) return buffer
- function varIntBuffer(i) {
- var ib = new Buffer(bufferutils.varIntSize(i))
- bufferutils.writeVarInt(ib, i, 0)
- return ib
- }
-
- var txLenBuffer = varIntBuffer(this.transactions.length)
+ var txLenBuffer = bufferutils.varIntBuffer(this.transactions.length)
var txBuffers = this.transactions.map(function(tx) {
return tx.toBuffer()
})
diff --git a/src/bufferutils.js b/src/bufferutils.js
index 858a9346c..644db884c 100644
--- a/src/bufferutils.js
+++ b/src/bufferutils.js
@@ -159,6 +159,14 @@ function writeVarInt(buffer, number, offset) {
return size
}
+function varIntBuffer(i) {
+ var size = varIntSize(i)
+ var buffer = new Buffer(size)
+ writeVarInt(buffer, i, 0)
+
+ return buffer
+}
+
function reverse(buffer) {
var buffer2 = new Buffer(buffer)
Array.prototype.reverse.call(buffer2)
@@ -171,6 +179,7 @@ module.exports = {
readUInt64LE: readUInt64LE,
readVarInt: readVarInt,
reverse: reverse,
+ varIntBuffer: varIntBuffer,
varIntSize: varIntSize,
writePushDataInt: writePushDataInt,
writeUInt64LE: writeUInt64LE,
diff --git a/src/message.js b/src/message.js
index 76ba3f0aa..6305a691c 100644
--- a/src/message.js
+++ b/src/message.js
@@ -13,8 +13,7 @@ var ecparams = ecurve.getCurveByName('secp256k1')
function magicHash(message, network) {
var magicPrefix = new Buffer(network.magicPrefix)
var messageBuffer = new Buffer(message)
- var lengthBuffer = new Buffer(bufferutils.varIntSize(messageBuffer.length))
- bufferutils.writeVarInt(lengthBuffer, messageBuffer.length, 0)
+ var lengthBuffer = bufferutils.varIntBuffer(messageBuffer.length)
var buffer = Buffer.concat([magicPrefix, lengthBuffer, messageBuffer])
return crypto.hash256(buffer)
diff --git a/test/bufferutils.js b/test/bufferutils.js
index 447d51606..8fc054cb0 100644
--- a/test/bufferutils.js
+++ b/test/bufferutils.js
@@ -88,6 +88,16 @@ describe('bufferutils', function() {
})
})
+ describe('varIntBuffer', function() {
+ fixtures.valid.forEach(function(f) {
+ it('encodes ' + f.dec + ' correctly', function() {
+ var buffer = bufferutils.varIntBuffer(f.dec)
+
+ assert.equal(buffer.toString('hex'), f.hexVI)
+ })
+ })
+ })
+
describe('varIntSize', function() {
fixtures.valid.forEach(function(f) {
it('determines the varIntSize of ' + f.dec + ' correctly', function() {
@@ -99,7 +109,7 @@ describe('bufferutils', function() {
})
describe('writePushDataInt', function() {
- fixtures.valid.forEach(function(f, i) {
+ fixtures.valid.forEach(function(f) {
if (!f.hexPD) return
it('encodes ' + f.dec + ' correctly', function() {
From 9897fa2876ea0bde66e9994dbb8cca1502d066f7 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 29 Oct 2014 12:12:12 +1100
Subject: [PATCH 179/291] block: adds getUTCDate function
---
src/block.js | 11 +++++++++--
test/block.js | 16 ++++++++++++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/src/block.js b/src/block.js
index 8fcce5a3c..be409c058 100644
--- a/src/block.js
+++ b/src/block.js
@@ -132,12 +132,19 @@ Block.prototype.toHex = function(headersOnly) {
return this.toBuffer(headersOnly).toString('hex')
}
+Block.prototype.getHash = function() {
+ return crypto.hash256(this.toBuffer(true))
+}
+
Block.prototype.getId = function() {
return bufferutils.reverse(this.getHash()).toString('hex')
}
-Block.prototype.getHash = function() {
- return crypto.hash256(this.toBuffer(true))
+Block.prototype.getUTCDate = function() {
+ var date = new Date(0) // epoch
+ date.setUTCSeconds(this.timestamp)
+
+ return date
}
module.exports = Block
diff --git a/test/block.js b/test/block.js
index 4caeb9f48..c5099804a 100644
--- a/test/block.js
+++ b/test/block.js
@@ -69,4 +69,20 @@ describe('Block', function() {
})
})
})
+
+ describe('getUTCDate', function() {
+ fixtures.valid.forEach(function(f) {
+ var block
+
+ beforeEach(function() {
+ block = Block.fromHex(f.hex)
+ })
+
+ it('returns UTC date of ' + f.id, function() {
+ var utcDate = block.getUTCDate().getTime()
+
+ assert.equal(utcDate, f.timestamp * 1e3)
+ })
+ })
+ })
})
From b6b5b568c30db9f40ab38ec55ce184dce06bec6d Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 28 Nov 2014 10:30:07 +1100
Subject: [PATCH 180/291] block: re-order functions to project standard
---
src/block.js | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/src/block.js b/src/block.js
index be409c058..8b786cbcb 100644
--- a/src/block.js
+++ b/src/block.js
@@ -97,6 +97,21 @@ Block.fromHex = function(hex) {
return Block.fromBuffer(new Buffer(hex, 'hex'))
}
+Block.prototype.getHash = function() {
+ return crypto.hash256(this.toBuffer(true))
+}
+
+Block.prototype.getId = function() {
+ return bufferutils.reverse(this.getHash()).toString('hex')
+}
+
+Block.prototype.getUTCDate = function() {
+ var date = new Date(0) // epoch
+ date.setUTCSeconds(this.timestamp)
+
+ return date
+}
+
Block.prototype.toBuffer = function(headersOnly) {
var buffer = new Buffer(80)
@@ -132,19 +147,4 @@ Block.prototype.toHex = function(headersOnly) {
return this.toBuffer(headersOnly).toString('hex')
}
-Block.prototype.getHash = function() {
- return crypto.hash256(this.toBuffer(true))
-}
-
-Block.prototype.getId = function() {
- return bufferutils.reverse(this.getHash()).toString('hex')
-}
-
-Block.prototype.getUTCDate = function() {
- var date = new Date(0) // epoch
- date.setUTCSeconds(this.timestamp)
-
- return date
-}
-
module.exports = Block
From 62e86e0dc116b32482775b2b91f374f31edd96dd Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 28 Nov 2014 12:52:25 +1100
Subject: [PATCH 181/291] scripts: s/dataOutput/nullDataOutput/
---
src/scripts.js | 8 ++++----
test/integration/advanced.js | 2 +-
test/scripts.js | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index d768ae2b0..dfd167d54 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -112,7 +112,7 @@ function isMultisigOutput(script) {
return pubKeys.every(isCanonicalPubKey)
}
-function isNulldataOutput(script) {
+function isNullDataOutput(script) {
return script.chunks[0] === ops.OP_RETURN
}
@@ -127,7 +127,7 @@ function classifyOutput(script) {
return 'multisig'
} else if (isPubKeyOutput(script)) {
return 'pubkey'
- } else if (isNulldataOutput(script)) {
+ } else if (isNullDataOutput(script)) {
return 'nulldata'
}
@@ -241,16 +241,16 @@ function multisigInput(signatures, scriptPubKey) {
return Script.fromChunks([].concat(ops.OP_0, signatures))
}
-function dataOutput(data) {
+function nullDataOutput(data) {
return Script.fromChunks([ops.OP_RETURN, data])
}
module.exports = {
classifyInput: classifyInput,
classifyOutput: classifyOutput,
- dataOutput: dataOutput,
multisigInput: multisigInput,
multisigOutput: multisigOutput,
+ nullDataOutput: nullDataOutput,
pubKeyHashInput: pubKeyHashInput,
pubKeyHashOutput: pubKeyHashOutput,
pubKeyInput: pubKeyInput,
diff --git a/test/integration/advanced.js b/test/integration/advanced.js
index f4479a5e1..be6af1f16 100644
--- a/test/integration/advanced.js
+++ b/test/integration/advanced.js
@@ -78,7 +78,7 @@ describe('bitcoinjs-lib (advanced)', function() {
var tx = new bitcoin.TransactionBuilder()
var data = new Buffer('cafedeadbeef', 'hex')
- var dataScript = bitcoin.scripts.dataOutput(data)
+ var dataScript = bitcoin.scripts.nullDataOutput(data)
tx.addInput(unspent.txHash, unspent.index)
tx.addOutput(dataScript, 1000)
diff --git a/test/scripts.js b/test/scripts.js
index 60b4026ae..6a3c98b5a 100644
--- a/test/scripts.js
+++ b/test/scripts.js
@@ -190,7 +190,7 @@ describe('Scripts', function() {
if (f.type !== 'nulldata') return
var data = new Buffer(f.data, 'hex')
- var scriptPubKey = scripts.dataOutput(data)
+ var scriptPubKey = scripts.nullDataOutput(data)
describe('output script', function() {
it('is generated correctly for ' + f.scriptPubKey, function() {
From e4eb743cf95d23715d3044c229f9e13c16a7968f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 28 Nov 2014 12:50:37 +1100
Subject: [PATCH 182/291] scripts: expose is* classifiers
---
src/scripts.js | 25 +++--
test/fixtures/scripts.json | 87 ++++++++-------
test/scripts.js | 212 ++++++++++++++++++++-----------------
3 files changed, 178 insertions(+), 146 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index dfd167d54..ac6d6e552 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -246,15 +246,26 @@ function nullDataOutput(data) {
}
module.exports = {
- classifyInput: classifyInput,
+ isCanonicalPubKey: isCanonicalPubKey,
+ isCanonicalSignature: isCanonicalSignature,
+ isPubKeyHashInput: isPubKeyHashInput,
+ isPubKeyHashOutput: isPubKeyHashOutput,
+ isPubKeyInput: isPubKeyInput,
+ isPubKeyOutput: isPubKeyOutput,
+ isScriptHashInput: isScriptHashInput,
+ isScriptHashOutput: isScriptHashOutput,
+ isMultisigInput: isMultisigInput,
+ isMultisigOutput: isMultisigOutput,
+ isNullDataOutput: isNullDataOutput,
classifyOutput: classifyOutput,
- multisigInput: multisigInput,
- multisigOutput: multisigOutput,
- nullDataOutput: nullDataOutput,
- pubKeyHashInput: pubKeyHashInput,
+ classifyInput: classifyInput,
+ pubKeyOutput: pubKeyOutput,
pubKeyHashOutput: pubKeyHashOutput,
+ scriptHashOutput: scriptHashOutput,
+ multisigOutput: multisigOutput,
pubKeyInput: pubKeyInput,
- pubKeyOutput: pubKeyOutput,
+ pubKeyHashInput: pubKeyHashInput,
scriptHashInput: scriptHashInput,
- scriptHashOutput: scriptHashOutput
+ multisigInput: multisigInput,
+ nullDataOutput: nullDataOutput
}
diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json
index 86a7390a0..6ae7863cd 100644
--- a/test/fixtures/scripts.json
+++ b/test/fixtures/scripts.json
@@ -56,78 +56,71 @@
}
],
"invalid": {
- "classify": [
+ "isPubKeyHashInput": [
{
- "description": "multisig output : OP_CHECKMULTISIG not found",
+ "description": "pubKeyHash input : extraneous data",
+ "scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 ffffffff"
+ }
+ ],
+ "isScriptHashInput": [
+ {
+ "description": "redeemScript not data",
+ "scriptSig": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 OP_RESERVED"
+ }
+ ],
+ "isPubKeyInput": [
+ {
+ "description": "non-canonical signature",
+ "scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf7593ffffffffffffffff"
+ }
+ ],
+ "isMultisigOutput": [
+ {
+ "description": "OP_CHECKMULTISIG not found",
"scriptPubKey": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_HASH160"
},
{
- "description": "multisig output : less than 4 chunks",
+ "description": "less than 4 chunks",
"scriptPubKey": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_HASH160"
},
{
- "description": "multisig output : m === 0",
+ "description": "m === 0",
"scriptPubKey": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG"
},
{
- "description": "multisig output : m < OP_1",
+ "description": "m < OP_1",
"scriptPubKey": "OP_1NEGATE 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG"
},
{
- "description": "multisig output : m > OP_16",
+ "description": "m > OP_16",
"scriptPubKey": "OP_NOP 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG"
},
{
- "description": "multisig output : n === 0",
+ "description": "n === 0",
"scriptPubKey": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_0 OP_CHECKMULTISIG"
},
{
- "description": "multisig output : n < OP_1",
+ "description": "n < OP_1",
"scriptPubKey": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_1NEGATE OP_CHECKMULTISIG"
},
{
- "description": "multisig output : n > OP_16",
+ "description": "n > OP_16",
"scriptPubKey": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_NOP OP_CHECKMULTISIG"
},
{
- "description": "multisig output : n < m",
+ "description": "n < m",
"scriptPubKey": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_1 OP_CHECKMULTISIG"
},
{
- "description": "multisig output : n < len(pubKeys)",
+ "description": "n < len(pubKeys)",
"scriptPubKey": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_2 OP_CHECKMULTISIG"
},
{
- "description": "multisig output : non-canonical pubKey (bad length)",
+ "description": "non-canonical pubKey (bad length)",
"scriptPubKey": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffff OP_1 OP_CHECKMULTISIG"
- },
- {
- "description": "pubKeyHash input : extraneous data",
- "scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 ffffffff"
- },
- {
- "description": "scriptHash input : redeemScript not data",
- "scriptSig": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 OP_RESERVED"
- },
- {
- "description": "pubKey input : non-canonical signature",
- "scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf7593ffffffffffffffff"
}
],
- "multisig": [
- {
- "exception": "Not enough pubKeys provided",
- "m": 4,
- "pubKeys": [
- "02ea1297665dd733d444f31ec2581020004892cdaaf3dd6c0107c615afb839785f",
- "02fab2dea1458990793f56f42e4a47dbf35a12a351f26fa5d7e0cc7447eaafa21f",
- "036c6802ce7e8113723dd92cdb852e492ebb157a871ca532c3cb9ed08248ff0e19"
- ],
- "signatures": [
- "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801"
- ],
- "scriptPubKey": true
- },
+ "multisigInput": [
{
"exception": "Not enough signatures provided",
"pubKeys": [
@@ -136,8 +129,7 @@
],
"signatures": [
"304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801"
- ],
- "scriptPubKey": false
+ ]
},
{
"exception": "Too many signatures provided",
@@ -149,8 +141,21 @@
"304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
"3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
"3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
+ ]
+ }
+ ],
+ "multisigOutput": [
+ {
+ "exception": "Not enough pubKeys provided",
+ "m": 4,
+ "pubKeys": [
+ "02ea1297665dd733d444f31ec2581020004892cdaaf3dd6c0107c615afb839785f",
+ "02fab2dea1458990793f56f42e4a47dbf35a12a351f26fa5d7e0cc7447eaafa21f",
+ "036c6802ce7e8113723dd92cdb852e492ebb157a871ca532c3cb9ed08248ff0e19"
],
- "scriptPubKey": false
+ "signatures": [
+ "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801"
+ ]
}
]
}
diff --git a/test/scripts.js b/test/scripts.js
index 6a3c98b5a..41c3b3099 100644
--- a/test/scripts.js
+++ b/test/scripts.js
@@ -1,7 +1,6 @@
var assert = require('assert')
var scripts = require('../src/scripts')
-var Address = require('../src/address')
var ECPubKey = require('../src/ecpubkey')
var Script = require('../src/script')
@@ -19,17 +18,6 @@ describe('Scripts', function() {
assert.equal(type, f.type)
})
})
-
- fixtures.invalid.classify.forEach(function(f) {
- if (!f.scriptSig) return
-
- it('returns nonstandard for ' + f.description, function() {
- var script = Script.fromASM(f.scriptSig)
- var type = scripts.classifyInput(script)
-
- assert.equal(type, 'nonstandard')
- })
- })
})
describe('classifyOutput', function() {
@@ -43,159 +31,187 @@ describe('Scripts', function() {
assert.equal(type, f.type)
})
})
+ })
- fixtures.invalid.classify.forEach(function(f) {
- if (!f.scriptPubKey) return
+ ;['PubKey', 'PubKeyHash', 'ScriptHash', 'Multisig', 'NullData'].forEach(function(type) {
+ var inputFn = scripts['is' + type + 'Input']
+ var outputFn= scripts['is' + type + 'Output']
- it('returns nonstandard for ' + f.description, function() {
- var script = Script.fromASM(f.scriptPubKey)
- var type = scripts.classifyOutput(script)
+ describe('is' + type + 'Input', function() {
+ fixtures.valid.forEach(function(f) {
+ var expected = type.toLowerCase() === f.type
+
+ if (inputFn && f.scriptSig) {
+ it('returns ' + expected + ' for ' + f.scriptSig, function() {
+ var script = Script.fromASM(f.scriptSig)
+
+ assert.equal(inputFn(script), expected)
+ })
+ }
+ })
+ })
+
+ describe('is' + type + 'Output', function() {
+ fixtures.valid.forEach(function(f) {
+ var expected = type.toLowerCase() === f.type
- assert.equal(type, 'nonstandard')
+ if (outputFn && f.scriptPubKey) {
+ it('returns ' + expected + ' for ' + f.scriptPubKey, function() {
+ var script = Script.fromASM(f.scriptPubKey)
+
+ assert.equal(outputFn(script), expected)
+ })
+ }
})
})
})
- describe('pubKey', function() {
+ describe('pubKeyInput', function() {
fixtures.valid.forEach(function(f) {
if (f.type !== 'pubkey') return
- describe('input script', function() {
- it('is generated correctly for ' + f.pubKey, function() {
- var signature = new Buffer(f.signature, 'hex')
+ it('returns ' + f.scriptSig, function() {
+ var signature = new Buffer(f.signature, 'hex')
- var scriptSig = scripts.pubKeyInput(signature)
- assert.equal(scriptSig.toASM(), f.scriptSig)
- })
+ var scriptSig = scripts.pubKeyInput(signature)
+ assert.equal(scriptSig.toASM(), f.scriptSig)
})
+ })
+ })
- describe('output script', function() {
- it('is generated correctly for ' + f.pubKey, function() {
- var pubKey = ECPubKey.fromHex(f.pubKey)
+ describe('pubKeyOutput', function() {
+ fixtures.valid.forEach(function(f) {
+ if (f.type !== 'pubkey') return
- var scriptPubKey = scripts.pubKeyOutput(pubKey)
- assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
- })
+ it('returns ' + f.scriptPubKey, function() {
+ var pubKey = ECPubKey.fromHex(f.pubKey)
+
+ var scriptPubKey = scripts.pubKeyOutput(pubKey)
+ assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
})
})
})
- describe('pubKeyHash', function() {
+ describe('pubKeyHashInput', function() {
fixtures.valid.forEach(function(f) {
if (f.type !== 'pubkeyhash') return
var pubKey = ECPubKey.fromHex(f.pubKey)
- var address = pubKey.getAddress()
- describe('input script', function() {
- it('is generated correctly for ' + address, function() {
- var signature = new Buffer(f.signature, 'hex')
+ it('returns ' + f.scriptSig, function() {
+ var signature = new Buffer(f.signature, 'hex')
- var scriptSig = scripts.pubKeyHashInput(signature, pubKey)
- assert.equal(scriptSig.toASM(), f.scriptSig)
- })
+ var scriptSig = scripts.pubKeyHashInput(signature, pubKey)
+ assert.equal(scriptSig.toASM(), f.scriptSig)
})
+ })
+ })
- describe('output script', function() {
- it('is generated correctly for ' + address, function() {
- var scriptPubKey = scripts.pubKeyHashOutput(address.hash)
- assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
- })
+ describe('pubKeyHashOutput', function() {
+ fixtures.valid.forEach(function(f) {
+ if (f.type !== 'pubkeyhash') return
+
+ var pubKey = ECPubKey.fromHex(f.pubKey)
+ var address = pubKey.getAddress()
+
+ it('returns ' + f.scriptPubKey, function() {
+ var scriptPubKey = scripts.pubKeyHashOutput(address.hash)
+ assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
})
})
})
- describe('multisig', function() {
+ describe('multisigInput', function() {
fixtures.valid.forEach(function(f) {
if (f.type !== 'multisig') return
+ it('returns ' + f.scriptSig, function() {
+ var signatures = f.signatures.map(function(signature) {
+ return new Buffer(signature, 'hex')
+ })
+
+ var scriptSig = scripts.multisigInput(signatures)
+ assert.equal(scriptSig.toASM(), f.scriptSig)
+ })
+ })
+
+ fixtures.invalid.multisigInput.forEach(function(f) {
var pubKeys = f.pubKeys.map(ECPubKey.fromHex)
var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys)
- describe('input script', function() {
- it('is generated correctly for ' + f.scriptPubKey, function() {
- var signatures = f.signatures.map(function(signature) {
- return new Buffer(signature, 'hex')
- })
-
- var scriptSig = scripts.multisigInput(signatures)
- assert.equal(scriptSig.toASM(), f.scriptSig)
+ it('throws on ' + f.exception, function() {
+ var signatures = f.signatures.map(function(signature) {
+ return new Buffer(signature, 'hex')
})
- })
- describe('output script', function() {
- it('is generated correctly for ' + f.scriptPubKey, function() {
- assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
- })
+ assert.throws(function() {
+ scripts.multisigInput(signatures, scriptPubKey)
+ }, new RegExp(f.exception))
})
})
+ })
+
+ describe('multisigOutput', function() {
+ fixtures.valid.forEach(function(f) {
+ if (f.type !== 'multisig') return
- fixtures.invalid.multisig.forEach(function(f) {
var pubKeys = f.pubKeys.map(ECPubKey.fromHex)
var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys)
- if (f.scriptPubKey) {
- describe('output script', function() {
- it('throws on ' + f.exception, function() {
- assert.throws(function() {
- scripts.multisigOutput(f.m, pubKeys)
- }, new RegExp(f.exception))
- })
- })
- } else {
- describe('input script', function() {
- it('throws on ' + f.exception, function() {
- var signatures = f.signatures.map(function(signature) {
- return new Buffer(signature, 'hex')
- })
-
- assert.throws(function() {
- scripts.multisigInput(signatures, scriptPubKey)
- }, new RegExp(f.exception))
- })
- })
- }
+ it('returns ' + f.scriptPubKey, function() {
+ assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
+ })
+ })
+
+ fixtures.invalid.multisigOutput.forEach(function(f) {
+ var pubKeys = f.pubKeys.map(function(p) { return new Buffer(p, 'hex') })
+
+ it('throws on ' + f.exception, function() {
+ assert.throws(function() {
+ scripts.multisigOutput(f.m, pubKeys)
+ }, new RegExp(f.exception))
+ })
})
})
- describe('scripthash', function() {
+ describe('scriptHashInput', function() {
fixtures.valid.forEach(function(f) {
if (f.type !== 'scripthash') return
var redeemScript = Script.fromASM(f.redeemScript)
var redeemScriptSig = Script.fromASM(f.redeemScriptSig)
- var address = Address.fromOutputScript(Script.fromASM(f.scriptPubKey))
-
- describe('input script', function() {
- it('is generated correctly for ' + address, function() {
- var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
+ it('returns ' + f.scriptSig, function() {
+ var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
- assert.equal(scriptSig.toASM(), f.scriptSig)
- })
+ assert.equal(scriptSig.toASM(), f.scriptSig)
})
+ })
+ })
- describe('output script', function() {
- it('is generated correctly for ' + address, function() {
- var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash())
+ describe('scriptHashOutput', function() {
+ fixtures.valid.forEach(function(f) {
+ if (f.type !== 'scripthash') return
- assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
- })
+ var redeemScript = Script.fromASM(f.redeemScript)
+
+ it('returns ' + f.scriptPubKey, function() {
+ var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash())
+
+ assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
})
})
})
- describe('data', function() {
+ describe('nullDataOutput', function() {
fixtures.valid.forEach(function(f) {
if (f.type !== 'nulldata') return
var data = new Buffer(f.data, 'hex')
var scriptPubKey = scripts.nullDataOutput(data)
- describe('output script', function() {
- it('is generated correctly for ' + f.scriptPubKey, function() {
- assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
- })
+ it('returns ' + f.scriptPubKey, function() {
+ assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
})
})
})
From f8f459dda8f254f15e0d11a524f13546fd0720a1 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 28 Nov 2014 13:47:05 +1100
Subject: [PATCH 183/291] scripts: add dataOutput deprecation
---
src/scripts.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/scripts.js b/src/scripts.js
index ac6d6e552..0ffb1e049 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -267,5 +267,9 @@ module.exports = {
pubKeyHashInput: pubKeyHashInput,
scriptHashInput: scriptHashInput,
multisigInput: multisigInput,
+ dataOutput: function(data) {
+ console.warn('dataOutput is deprecated, use nullDataOutput by 2.0.0')
+ return nullDataOutput(data)
+ },
nullDataOutput: nullDataOutput
}
From 254974d999b0d5cdca5b8332bdd35c6f98ff1956 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 28 Nov 2014 13:49:43 +1100
Subject: [PATCH 184/291] scripts: add TODO for tests for isCanonical*
functions
---
test/scripts.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/scripts.js b/test/scripts.js
index 41c3b3099..8405cd572 100644
--- a/test/scripts.js
+++ b/test/scripts.js
@@ -7,6 +7,10 @@ var Script = require('../src/script')
var fixtures = require('./fixtures/scripts.json')
describe('Scripts', function() {
+ // TODO
+ describe.skip('isCanonicalPubKey', function() {})
+ describe.skip('isCanonicalSignature', function() {})
+
describe('classifyInput', function() {
fixtures.valid.forEach(function(f) {
if (!f.scriptSig) return
From 4fe0b34f27f5cc4f52d71ce76bdb182999092a59 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 28 Nov 2014 13:53:43 +1100
Subject: [PATCH 185/291] Address: no need to check other script types
---
src/address.js | 8 +++-----
test/fixtures/address.json | 6 +++---
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/src/address.js b/src/address.js
index 124c0ef7b..cc6264fe4 100644
--- a/src/address.js
+++ b/src/address.js
@@ -35,12 +35,10 @@ Address.fromBase58Check = function(string) {
Address.fromOutputScript = function(script, network) {
network = network || networks.bitcoin
- var type = scripts.classifyOutput(script)
+ if (scripts.isPubKeyHashOutput(script)) return new Address(script.chunks[2], network.pubKeyHash)
+ if (scripts.isScriptHashOutput(script)) return new Address(script.chunks[1], network.scriptHash)
- if (type === 'pubkeyhash') return new Address(script.chunks[2], network.pubKeyHash)
- if (type === 'scripthash') return new Address(script.chunks[1], network.scriptHash)
-
- assert(false, type + ' has no matching Address')
+ assert(false, script.toASM() + ' has no matching Address')
}
// Export functions
diff --git a/test/fixtures/address.json b/test/fixtures/address.json
index cedd17d1f..28602bcaa 100644
--- a/test/fixtures/address.json
+++ b/test/fixtures/address.json
@@ -48,15 +48,15 @@
],
"fromOutputScript": [
{
- "description": "pubkey has no matching Address",
+ "description": "has no matching Address",
"hex": "21031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95ac"
},
{
- "description": "multisig has no matching Address",
+ "description": "has no matching Address",
"hex": "5121032487c2a32f7c8d57d2a93906a6457afd00697925b0e6e145d89af6d3bca330162102308673d16987eaa010e540901cc6fe3695e758c19f46ce604e174dac315e685a52ae"
},
{
- "description": "nulldata has no matching Address",
+ "description": "has no matching Address",
"hex": "6a2606deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474"
}
],
From 7fbc397141881f043fef17471a5eefdd6c1693a3 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 28 Nov 2014 14:02:19 +1100
Subject: [PATCH 186/291] Address: use script ASM over hex
---
test/address.js | 24 ++++++++++++------------
test/fixtures/address.json | 28 ++++++++++++----------------
2 files changed, 24 insertions(+), 28 deletions(-)
diff --git a/test/address.js b/test/address.js
index 50ff895af..0e29f0d93 100644
--- a/test/address.js
+++ b/test/address.js
@@ -10,22 +10,22 @@ describe('Address', function() {
describe('Constructor', function() {
it('does not mutate the input', function() {
fixtures.valid.forEach(function(f) {
- var hash = new Buffer(f.hex, 'hex')
+ var hash = new Buffer(f.hash, 'hex')
var addr = new Address(hash, f.version)
assert.equal(addr.version, f.version)
- assert.equal(addr.hash.toString('hex'), f.hex)
+ assert.equal(addr.hash.toString('hex'), f.hash)
})
})
})
describe('fromBase58Check', function() {
fixtures.valid.forEach(function(f) {
- it('imports ' + f.description + '(' + f.network + ') correctly', function() {
+ it('imports ' + f.script + ' (' + f.network + ') correctly', function() {
var addr = Address.fromBase58Check(f.base58check)
assert.equal(addr.version, f.version)
- assert.equal(addr.hash.toString('hex'), f.hex)
+ assert.equal(addr.hash.toString('hex'), f.hash)
})
})
@@ -40,18 +40,18 @@ describe('Address', function() {
describe('fromOutputScript', function() {
fixtures.valid.forEach(function(f) {
- it('imports ' + f.description + '(' + f.network + ') correctly', function() {
- var script = Script.fromHex(f.script)
+ it('imports ' + f.script + ' (' + f.network + ') correctly', function() {
+ var script = Script.fromASM(f.script)
var addr = Address.fromOutputScript(script, networks[f.network])
assert.equal(addr.version, f.version)
- assert.equal(addr.hash.toString('hex'), f.hex)
+ assert.equal(addr.hash.toString('hex'), f.hash)
})
})
fixtures.invalid.fromOutputScript.forEach(function(f) {
it('throws when ' + f.description, function() {
- var script = Script.fromHex(f.hex)
+ var script = Script.fromASM(f.script)
assert.throws(function() {
Address.fromOutputScript(script)
@@ -62,7 +62,7 @@ describe('Address', function() {
describe('toBase58Check', function() {
fixtures.valid.forEach(function(f) {
- it('exports ' + f.description + '(' + f.network + ') correctly', function() {
+ it('exports ' + f.script + ' (' + f.network + ') correctly', function() {
var addr = Address.fromBase58Check(f.base58check)
var result = addr.toBase58Check()
@@ -73,17 +73,17 @@ describe('Address', function() {
describe('toOutputScript', function() {
fixtures.valid.forEach(function(f) {
- it('imports ' + f.description + '(' + f.network + ') correctly', function() {
+ it('imports ' + f.script + ' (' + f.network + ') correctly', function() {
var addr = Address.fromBase58Check(f.base58check)
var script = addr.toOutputScript()
- assert.equal(script.toHex(), f.script)
+ assert.equal(script.toASM(), f.script)
})
})
fixtures.invalid.toOutputScript.forEach(function(f) {
it('throws when ' + f.description, function() {
- var addr = new Address(new Buffer(f.hex, 'hex'), f.version)
+ var addr = new Address(new Buffer(f.hash, 'hex'), f.version)
assert.throws(function() {
addr.toOutputScript()
diff --git a/test/fixtures/address.json b/test/fixtures/address.json
index 28602bcaa..fff8d9a59 100644
--- a/test/fixtures/address.json
+++ b/test/fixtures/address.json
@@ -1,36 +1,32 @@
{
"valid": [
{
- "description": "pubKeyHash",
"network": "bitcoin",
"version": 0,
- "hex": "751e76e8199196d454941c45d1b3a323f1433bd6",
+ "hash": "751e76e8199196d454941c45d1b3a323f1433bd6",
"base58check": "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH",
- "script": "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac"
+ "script": "OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG"
},
{
- "description": "scriptHash",
"network": "bitcoin",
"version": 5,
- "hex": "cd7b44d0b03f2d026d1e586d7ae18903b0d385f6",
+ "hash": "cd7b44d0b03f2d026d1e586d7ae18903b0d385f6",
"base58check": "3LRW7jeCvQCRdPF8S3yUCfRAx4eqXFmdcr",
- "script": "a914cd7b44d0b03f2d026d1e586d7ae18903b0d385f687"
+ "script": "OP_HASH160 cd7b44d0b03f2d026d1e586d7ae18903b0d385f6 OP_EQUAL"
},
{
- "description": "pubKeyHash",
"network": "testnet",
"version": 111,
- "hex": "751e76e8199196d454941c45d1b3a323f1433bd6",
+ "hash": "751e76e8199196d454941c45d1b3a323f1433bd6",
"base58check": "mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r",
- "script": "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac"
+ "script": "OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG"
},
{
- "description": "scriptHash",
"network": "testnet",
"version": 196,
- "hex": "cd7b44d0b03f2d026d1e586d7ae18903b0d385f6",
+ "hash": "cd7b44d0b03f2d026d1e586d7ae18903b0d385f6",
"base58check": "2NByiBUaEXrhmqAsg7BbLpcQSAQs1EDwt5w",
- "script": "a914cd7b44d0b03f2d026d1e586d7ae18903b0d385f687"
+ "script": "OP_HASH160 cd7b44d0b03f2d026d1e586d7ae18903b0d385f6 OP_EQUAL"
}
],
"invalid": {
@@ -49,21 +45,21 @@
"fromOutputScript": [
{
"description": "has no matching Address",
- "hex": "21031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95ac"
+ "script": "031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95 OP_CHECKSIG"
},
{
"description": "has no matching Address",
- "hex": "5121032487c2a32f7c8d57d2a93906a6457afd00697925b0e6e145d89af6d3bca330162102308673d16987eaa010e540901cc6fe3695e758c19f46ce604e174dac315e685a52ae"
+ "script": "OP_TRUE 032487c2a32f7c8d57d2a93906a6457afd00697925b0e6e145d89af6d3bca33016 02308673d16987eaa010e540901cc6fe3695e758c19f46ce604e174dac315e685a OP_2 OP_CHECKMULTISIG"
},
{
"description": "has no matching Address",
- "hex": "6a2606deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474"
+ "script": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474"
}
],
"toOutputScript": [
{
"description": "24kPZCmVgzfkpGdXExy56234MRHrsqQxNWE has no matching Script",
- "hex": "751e76e8199196d454941c45d1b3a323f1433bd6",
+ "hash": "751e76e8199196d454941c45d1b3a323f1433bd6",
"version": 153
}
]
From a8459818e324d34cfc8ce410a369725a0f644358 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 29 Nov 2014 11:28:37 +1100
Subject: [PATCH 187/291] HDNode: avoid walking bip32 object
---
src/hdnode.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/hdnode.js b/src/hdnode.js
index 9f0828e2c..837cf8a14 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -15,11 +15,11 @@ function findBIP32ParamsByVersion(version) {
for (var name in networks) {
var network = networks[name]
- for (var type in network.bip32) {
- if (version != network.bip32[type]) continue
+ if (version === network.bip32.private ||
+ version === network.bip32.public) {
return {
- isPrivate: (type === 'private'),
+ isPrivate: (version === network.bip32.private),
network: network
}
}
From 10f3d7c46b04f2630b2fc71039bcd17526e87f13 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 29 Nov 2014 12:39:12 +1100
Subject: [PATCH 188/291] package: remove testling
---
package.json | 45 ++++++++++++++++-----------------------------
1 file changed, 16 insertions(+), 29 deletions(-)
diff --git a/package.json b/package.json
index a548d06a4..a5d9a1c1c 100644
--- a/package.json
+++ b/package.json
@@ -31,35 +31,6 @@
"url": "http://www.justmoon.net"
}
],
- "repository": {
- "type": "git",
- "url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
- },
- "devDependencies": {
- "browserify": "^5.12.0",
- "bs58": "^2.0.0",
- "coveralls": "^2.11.2",
- "helloblock-js": "^0.2.5",
- "istanbul": "^0.3.2",
- "jshint": "^2.5.6",
- "mocha": "^1.21.4",
- "mocha-lcov-reporter": "0.0.1",
- "sinon": "^1.10.3",
- "uglify-js": "^2.4.15"
- },
- "testling": {
- "browsers": [
- "android-browser/4.2..latest",
- "chrome/20..latest",
- "firefox/21..latest",
- "ipad/6..latest",
- "iphone/6..latest",
- "opera/15..latest",
- "safari/latest"
- ],
- "harness": "mocha-bdd",
- "files": "test/*.js"
- },
"scripts": {
"compile": "browserify ./src/index.js -s bitcoin | uglifyjs > bitcoinjs-min.js",
"coverage": "istanbul cover _mocha -- test/*.js",
@@ -69,6 +40,10 @@
"test": "npm run-script unit",
"unit": "istanbul test mocha -- --reporter list test/*.js"
},
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
+ },
"browser": {
"crypto": "crypto-browserify"
},
@@ -77,5 +52,17 @@
"bs58check": "1.0.3",
"crypto-browserify": "^3.2.6",
"ecurve": "1.0.0"
+ },
+ "devDependencies": {
+ "browserify": "^5.12.0",
+ "bs58": "^2.0.0",
+ "coveralls": "^2.11.2",
+ "helloblock-js": "^0.2.5",
+ "istanbul": "^0.3.2",
+ "jshint": "^2.5.6",
+ "mocha": "^1.21.4",
+ "mocha-lcov-reporter": "0.0.1",
+ "sinon": "^1.10.3",
+ "uglify-js": "^2.4.15"
}
}
From 86df6fc8c0ff6dfe4de70fc8be63c721153de329 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 29 Nov 2014 12:48:27 +1100
Subject: [PATCH 189/291] README: better wording
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e64353e1e..0b5d648fb 100644
--- a/README.md
+++ b/README.md
@@ -67,7 +67,7 @@ After loading this file in your browser, you will be able to use the global `bit
## Examples
-The below examples are implemented as integration tests, but should be very easy to follow. Pull requests welcome.
+The below examples are implemented as integration tests, they should be very easy to understand. Otherwise, pull requests are appreciated.
- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L8)
- [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L20)
From 25038bdb9f8c9d01cc428c4fb96f00c430dc8e8a Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 29 Nov 2014 14:16:20 +1100
Subject: [PATCH 190/291] README: remove testling badge
---
README.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/README.md b/README.md
index e64353e1e..39863eb09 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,6 @@
[](https://nodei.co/npm/bitcoinjs-lib/)
-[](https://ci.testling.com/bitcoinjs/bitcoinjs-lib)
-
The pure JavaScript Bitcoin library for node.js and browsers.
A continued implementation of the original `0.1.3` version used by over a million wallet users; the backbone for almost all Bitcoin web wallets in production today.
From 4fca3ac1965153f7b11e1a0a5757ff31261d1a04 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 27 Nov 2014 17:10:26 +1100
Subject: [PATCH 191/291] network: add failing tests for gamerscoin, viacoin
and zetacoin
---
test/fixtures/network.json | 223 ++++++++++++++++++++++++-------------
test/network.js | 36 ++++--
2 files changed, 172 insertions(+), 87 deletions(-)
diff --git a/test/fixtures/network.json b/test/fixtures/network.json
index e2ed7674c..b638221c9 100644
--- a/test/fixtures/network.json
+++ b/test/fixtures/network.json
@@ -1,84 +1,151 @@
{
- "valid": [
- {
- "description": "when txSize < 1kb",
- "network": "bitcoin",
- "txSize": 1,
- "fee": 10000
- },
- {
- "description": "when txSize >= 1kb",
- "network": "bitcoin",
- "txSize": 1000,
- "fee": 10000
- },
- {
- "description": "rounding",
- "network": "bitcoin",
- "txSize": 2800,
- "fee": 30000
- },
- {
- "description": "when outputs.value > DUST_SOFT_LIMIT, feePerKb is used",
- "network": "dogecoin",
- "txSize": 1000,
- "outputs": [
- {
- "value": 100000000
+ "valid": {
+ "constants": [
+ {
+ "network": "bitcoin",
+ "bip32": {
+ "private": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
+ "public": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
}
- ],
- "fee": 100000000
- },
- {
- "description": "when not every outputs.value > DUST_SOFT_LIMIT",
- "network": "dogecoin",
- "txSize": 1000,
- "outputs": [
- {
- "value": 99999999
- },
- {
- "value": 99999999
+ },
+ {
+ "network": "testnet",
+ "bip32": {
+ "private": "tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m",
+ "public": "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp"
}
- ],
- "fee": 300000000
- },
- {
- "description": "rounding",
- "network": "dogecoin",
- "txSize": 2800,
- "fee": 300000000
- },
- {
- "description": "when outputs.value > DUST_SOFT_LIMIT, feePerKb is used",
- "network": "litecoin",
- "txSize": 1000,
- "outputs": [
- {
- "value": 100000
+ },
+ {
+ "network": "litecoin",
+ "bip32": {
+ "private": "Ltpv71G8qDifUiNetP6nmxPA5STrUVmv2J9YSmXajv8VsYBUyuPhvN9xCaQrfX2wo5xxJNtEazYCFRUu5FmokYMM79pcqz8pcdo4rNXAFPgyB4k",
+ "public": "Ltub2SSUS19CirucWFod2ZsYA2J4v4U76YiCXHdcQttnoiy5aGanFHCPDBX7utfG6f95u1cUbZJNafmvzNCzZZJTw1EmyFoL8u1gJbGM8ipu491"
}
- ],
- "fee": 100000
- },
- {
- "description": "when not every outputs.value > DUST_SOFT_LIMIT",
- "network": "litecoin",
- "txSize": 1000,
- "outputs": [
- {
- "value": 99999
- },
- {
- "value": 99999
+ },
+ {
+ "network": "dogecoin",
+ "bip32": {
+ "private": "dgpv51eADS3spNJh9Gjth94XcPwAczvQaDJs9rqx11kvxKs6r3Ek8AgERHhjLs6mzXQFHRzQqGwqdeoDkZmr8jQMBfi43b7sT3sx3cCSk5fGeUR",
+ "public": "dgub8kXBZ7ymNWy2S8Q3jNgVjFUm5ZJ3QLLaSTdAA89ukSv7Q6MSXwE14b7Nv6eDpE9JJXinTKc8LeLVu19uDPrm5uJuhpKNzV2kAgncwo6bNpP"
}
- ],
- "fee": 300000
- },
- {
- "description": "rounding",
- "network": "litecoin",
- "txSize": 2800,
- "fee": 300000
- }
- ]
+ },
+ {
+ "network": "viacoin",
+ "bip32": {
+ "private": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
+ "public": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
+ }
+ },
+ {
+ "network": "viacointestnet",
+ "bip32": {
+ "private": "tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m",
+ "public": "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp"
+ }
+ },
+ {
+ "network": "gamerscoin",
+ "bip32": {
+ "private": "Ltpv71G8qDifUiNetP6nmxPA5STrUVmv2J9YSmXajv8VsYBUyuPhvN9xCaQrfX2wo5xxJNtEazYCFRUu5FmokYMM79pcqz8pcdo4rNXAFPgyB4k",
+ "public": "Ltub2SSUS19CirucWFod2ZsYA2J4v4U76YiCXHdcQttnoiy5aGanFHCPDBX7utfG6f95u1cUbZJNafmvzNCzZZJTw1EmyFoL8u1gJbGM8ipu491"
+ }
+ },
+ {
+ "network": "jumbucks",
+ "bip32": {
+ "private": "jprv5eCacBgN4Bz4zYxgVQ7RDt1a3eREhEaj8KjAcJ7YwogxGo2rmBF5kvAQS53JwZpo5wnUmJ9Q7kB6b2gQ1MzC6yaTc188hr6hXZ5t8Ruria1",
+ "public": "jpub1sBw1hDFtZYND339bReRb1xJbgFj6hJaVYemQgXAW9Dw9bN1JiZLJiUtHLgcTTEs1UgRGFAYm3XQPYsYJbpqj1aYPhrMsNcJHfgdAhvFZBB"
+ }
+ },
+ {
+ "network": "zetacoin",
+ "bip32": {
+ "private": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
+ "public": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
+ }
+ }
+ ],
+ "estimateFee": [
+ {
+ "description": "when txSize < 1kb",
+ "network": "bitcoin",
+ "txSize": 1,
+ "fee": 10000
+ },
+ {
+ "description": "when txSize >= 1kb",
+ "network": "bitcoin",
+ "txSize": 1000,
+ "fee": 10000
+ },
+ {
+ "description": "rounding",
+ "network": "bitcoin",
+ "txSize": 2800,
+ "fee": 30000
+ },
+ {
+ "description": "when outputs.value > DUST_SOFT_LIMIT, feePerKb is used",
+ "network": "dogecoin",
+ "txSize": 1000,
+ "outputs": [
+ {
+ "value": 100000000
+ }
+ ],
+ "fee": 100000000
+ },
+ {
+ "description": "when not every outputs.value > DUST_SOFT_LIMIT",
+ "network": "dogecoin",
+ "txSize": 1000,
+ "outputs": [
+ {
+ "value": 99999999
+ },
+ {
+ "value": 99999999
+ }
+ ],
+ "fee": 300000000
+ },
+ {
+ "description": "rounding",
+ "network": "dogecoin",
+ "txSize": 2800,
+ "fee": 300000000
+ },
+ {
+ "description": "when outputs.value > DUST_SOFT_LIMIT, feePerKb is used",
+ "network": "litecoin",
+ "txSize": 1000,
+ "outputs": [
+ {
+ "value": 100000
+ }
+ ],
+ "fee": 100000
+ },
+ {
+ "description": "when not every outputs.value > DUST_SOFT_LIMIT",
+ "network": "litecoin",
+ "txSize": 1000,
+ "outputs": [
+ {
+ "value": 99999
+ },
+ {
+ "value": 99999
+ }
+ ],
+ "fee": 300000
+ },
+ {
+ "description": "rounding",
+ "network": "litecoin",
+ "txSize": 2800,
+ "fee": 300000
+ }
+ ]
+ }
}
diff --git a/test/network.js b/test/network.js
index ad674b635..51611f42a 100644
--- a/test/network.js
+++ b/test/network.js
@@ -1,6 +1,8 @@
var assert = require('assert')
var networks = require('../src/networks')
var sinon = require('sinon')
+
+var HDNode = require('../src/hdnode')
var Transaction = require('../src/transaction')
var fixtures = require('./fixtures/network')
@@ -15,19 +17,35 @@ describe('networks', function() {
Transaction.prototype.toBuffer.restore()
})
- fixtures.valid.forEach(function(f) {
- describe(f.network + ' estimateFee', function() {
+ describe('constants', function() {
+ fixtures.valid.constants.forEach(function(f) {
var network = networks[f.network]
- it('calculates the fee correctly for ' + f.description, function() {
- var buffer = new Buffer(f.txSize)
- txToBuffer.returns(buffer)
+ Object.keys(f.bip32).forEach(function(name) {
+ var extb58 = f.bip32[name]
+
+ it('resolves ' + extb58 + ' to ' + f.network, function() {
+ assert.equal(HDNode.fromBase58(extb58).network, network)
+ })
+ })
+ })
+ })
+
+ describe('estimateFee', function() {
+ fixtures.valid.estimateFee.forEach(function(f) {
+ describe('(' + f.network + ')', function() {
+ var network = networks[f.network]
+
+ it('calculates the fee correctly for ' + f.description, function() {
+ var buffer = new Buffer(f.txSize)
+ txToBuffer.returns(buffer)
- var estimateFee = network.estimateFee
- var tx = new Transaction()
- tx.outs = f.outputs || []
+ var estimateFee = network.estimateFee
+ var tx = new Transaction()
+ tx.outs = f.outputs || []
- assert.equal(estimateFee(tx), f.fee)
+ assert.equal(estimateFee(tx), f.fee)
+ })
})
})
})
From 311df7e4067814930f75bcf52d66961da0b69ae3 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 29 Nov 2014 12:04:02 +1100
Subject: [PATCH 192/291] HDNode: add optional network flag to import functions
---
src/hdnode.js | 30 +++++++++++++++++++---------
test/fixtures/hdnode.json | 35 ++++++++++++++++++++++++++++++--
test/hdnode.js | 42 +++++++++++++++++++--------------------
test/network.js | 2 +-
4 files changed, 75 insertions(+), 34 deletions(-)
diff --git a/src/hdnode.js b/src/hdnode.js
index 837cf8a14..9e41d1b3a 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -74,12 +74,12 @@ HDNode.fromSeedHex = function(hex, network) {
return HDNode.fromSeedBuffer(new Buffer(hex, 'hex'), network)
}
-HDNode.fromBase58 = function(string) {
- return HDNode.fromBuffer(base58check.decode(string), true)
+HDNode.fromBase58 = function(string, network) {
+ return HDNode.fromBuffer(base58check.decode(string), network, true)
}
// FIXME: remove in 2.x.y
-HDNode.fromBuffer = function(buffer, __ignoreDeprecation) {
+HDNode.fromBuffer = function(buffer, network, __ignoreDeprecation) {
if (!__ignoreDeprecation) {
console.warn('HDNode.fromBuffer() is deprecated for removal in 2.x.y, use fromBase58 instead')
}
@@ -88,7 +88,19 @@ HDNode.fromBuffer = function(buffer, __ignoreDeprecation) {
// 4 byte: version bytes
var version = buffer.readUInt32BE(0)
- var params = findBIP32ParamsByVersion(version)
+ var isPrivate
+
+ if (network) {
+ assert(version === network.bip32.private || version === network.bip32.public, 'Network doesn\'t match')
+ isPrivate = (version === network.bip32.private)
+
+ // auto-detection
+ } else {
+ var params = findBIP32ParamsByVersion(version)
+
+ isPrivate = params.isPrivate
+ network = params.network
+ }
// 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ...
var depth = buffer.readUInt8(4)
@@ -109,11 +121,11 @@ HDNode.fromBuffer = function(buffer, __ignoreDeprecation) {
var data, hd
// 33 bytes: private key data (0x00 + k)
- if (params.isPrivate) {
+ if (isPrivate) {
assert.strictEqual(buffer.readUInt8(45), 0x00, 'Invalid private key')
data = buffer.slice(46, 78)
var d = BigInteger.fromBuffer(data)
- hd = new HDNode(d, chainCode, params.network)
+ hd = new HDNode(d, chainCode, network)
// 33 bytes: public key data (0x02 + X or 0x03 + X)
} else {
@@ -125,7 +137,7 @@ HDNode.fromBuffer = function(buffer, __ignoreDeprecation) {
// If not, the extended public key is invalid.
curve.validate(Q)
- hd = new HDNode(Q, chainCode, params.network)
+ hd = new HDNode(Q, chainCode, network)
}
hd.depth = depth
@@ -136,8 +148,8 @@ HDNode.fromBuffer = function(buffer, __ignoreDeprecation) {
}
// FIXME: remove in 2.x.y
-HDNode.fromHex = function(hex) {
- return HDNode.fromBuffer(new Buffer(hex, 'hex'))
+HDNode.fromHex = function(hex, network) {
+ return HDNode.fromBuffer(new Buffer(hex, 'hex'), network)
}
HDNode.prototype.getIdentifier = function() {
diff --git a/test/fixtures/hdnode.json b/test/fixtures/hdnode.json
index 0f25c3f2a..8ab9265bf 100644
--- a/test/fixtures/hdnode.json
+++ b/test/fixtures/hdnode.json
@@ -1,6 +1,7 @@
{
"valid": [
{
+ "network": "bitcoin",
"master": {
"seed": "000102030405060708090a0b0c0d0e0f",
"wif": "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW",
@@ -8,7 +9,6 @@
"chainCode": "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508",
"hex": "0488b21e000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d5080339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
"hexPriv": "0488ade4000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d50800e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35",
- "network": "bitcoin",
"base58": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
"base58Priv": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
"identifier": "3442193e1bb70916e914552172cd4e2dbc9df811",
@@ -96,12 +96,12 @@
]
},
{
+ "network": "bitcoin",
"master": {
"seed": "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542",
"wif": "KyjXhyHF9wTphBkfpxjL8hkDXDUSbE3tKANT94kXSyh6vn6nKaoy",
"pubKey": "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7",
"chainCode": "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689",
- "network": "bitcoin",
"base58": "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
"base58Priv": "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
"hex": "0488b21e00000000000000000060499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd968903cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7",
@@ -189,6 +189,37 @@
"address": "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt"
}
]
+ },
+ {
+ "network": "litecoin",
+ "master": {
+ "seed": "000102030405060708090a0b0c0d0e0f",
+ "wif": "TAroS5Knm8GZcnpPycBgzjwwDLWMyQjDrcuGPPoArgrbW7Ln22qp",
+ "pubKey": "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
+ "chainCode": "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508",
+ "hex": "0488b21e000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d5080339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
+ "hexPriv": "019d9cfe000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d50800e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35",
+ "base58": "Ltub2SSUS19CirucWFod2ZsYA2J4v4U76YiCXHdcQttnoiy5aGanFHCPDBX7utfG6f95u1cUbZJNafmvzNCzZZJTw1EmyFoL8u1gJbGM8ipu491",
+ "base58Priv": "Ltpv71G8qDifUiNetP6nmxPA5STrUVmv2J9YSmXajv8VsYBUyuPhvN9xCaQrfX2wo5xxJNtEazYCFRUu5FmokYMM79pcqz8pcdo4rNXAFPgyB4k",
+ "identifier": "3442193e1bb70916e914552172cd4e2dbc9df811",
+ "fingerprint": "3442193e",
+ "address": "LPzGaoLUtXFkmNo3u1chDxGxDnSaBQTTxm"
+ },
+ "children": [
+ {
+ "description": "m/0'",
+ "m": 0,
+ "hardened": true,
+ "wif": "TB22qU2V9EJCVKJ8cdYaTfvDhnYcCzthcWgFm1k6hbvbKM1NLxoL",
+ "pubKey": "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56",
+ "chainCode": "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141",
+ "base58": "Ltub2UhtRiSfp82berwLEKkB34QBEt2TUdCDCu4WNzGumvAMwYsxfWjULKsXhADxqy3cuDu3TnqoKJr1xmB8Wb2qzthWAtbb4CutpXPuSU1YMgG",
+ "base58Priv": "Ltpv73XYpw28ZyVe2zEVyiFnxUZxoKLGQNdZ8NxUi1WcqjNmMBgtLbh3KimGSnPHCoLv1RmvxHs4dnKmo1oXQ8dXuDu8uroxrbVxZPA1gXboYvx",
+ "identifier": "5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7",
+ "fingerprint": "5c1bd648",
+ "address": "LTcyn1jun6g9hvxtsT7cqMRSyix7AULC76"
+ }
+ ]
}
],
"invalid": {
diff --git a/test/hdnode.js b/test/hdnode.js
index 617261d6b..7a75e4751 100644
--- a/test/hdnode.js
+++ b/test/hdnode.js
@@ -65,9 +65,10 @@ describe('HDNode', function() {
describe('fromSeed*', function() {
fixtures.valid.forEach(function(f) {
it('calculates privKey and chainCode for ' + f.master.fingerprint, function() {
- var hd = HDNode.fromSeedHex(f.master.seed)
+ var network = networks[f.network]
+ var hd = HDNode.fromSeedHex(f.master.seed, network)
- assert.equal(hd.privKey.toWIF(), f.master.wif)
+ assert.equal(hd.privKey.toWIF(network), f.master.wif)
assert.equal(hd.chainCode.toString('hex'), f.master.chainCode)
})
})
@@ -88,7 +89,8 @@ describe('HDNode', function() {
describe('toBase58', function() {
fixtures.valid.forEach(function(f) {
it('exports ' + f.master.base58 + ' (public) correctly', function() {
- var hd = HDNode.fromSeedHex(f.master.seed).neutered()
+ var network = networks[f.network]
+ var hd = HDNode.fromSeedHex(f.master.seed, network).neutered()
assert.equal(hd.toBase58(), f.master.base58)
})
@@ -96,7 +98,8 @@ describe('HDNode', function() {
fixtures.valid.forEach(function(f) {
it('exports ' + f.master.base58Priv + ' (private) correctly', function() {
- var hd = HDNode.fromSeedHex(f.master.seed)
+ var network = networks[f.network]
+ var hd = HDNode.fromSeedHex(f.master.seed, network)
assert.equal(hd.toBase58(), f.master.base58Priv)
})
@@ -175,7 +178,8 @@ describe('HDNode', function() {
fixtures.valid.forEach(function(f) {
it('exports ' + f.master.hexPriv + ' (private) correctly', function() {
- var hd = HDNode.fromSeedHex(f.master.seed)
+ var network = networks[f.network]
+ var hd = HDNode.fromSeedHex(f.master.seed, network)
assert.equal(hd.toHex(), f.master.hexPriv)
})
@@ -212,19 +216,12 @@ describe('HDNode', function() {
})
describe('getAddress', function() {
- var f = fixtures.valid[0]
-
- it('returns the Address (pubHash) for ' + f.master.fingerprint, function() {
- var hd = HDNode.fromBase58(f.master.base58)
-
- assert.equal(hd.getAddress().toString(), f.master.address)
- })
-
- it('supports alternative networks', function() {
- var hd = HDNode.fromBase58(f.master.base58)
- hd.network = networks.testnet
+ fixtures.valid.forEach(function(f) {
+ it('returns ' + f.master.address + ' for ' + f.master.fingerprint, function() {
+ var hd = HDNode.fromBase58(f.master.base58)
- assert.equal(hd.getAddress().version, networks.testnet.pubKeyHash)
+ assert.equal(hd.getAddress().toString(), f.master.address)
+ })
})
})
@@ -244,8 +241,8 @@ describe('HDNode', function() {
})
describe('derive', function() {
- function verifyVector(hd, v, depth) {
- assert.equal(hd.privKey.toWIF(), v.wif)
+ function verifyVector(hd, network, v, depth) {
+ assert.equal(hd.privKey.toWIF(network), v.wif)
assert.equal(hd.pubKey.toHex(), v.pubKey)
assert.equal(hd.chainCode.toString('hex'), v.chainCode)
assert.equal(hd.depth, depth || 0)
@@ -257,8 +254,9 @@ describe('HDNode', function() {
}
}
- fixtures.valid.forEach(function(f, j) {
- var hd = HDNode.fromSeedHex(f.master.seed)
+ fixtures.valid.forEach(function(f) {
+ var network = networks[f.network]
+ var hd = HDNode.fromSeedHex(f.master.seed, network)
// FIXME: test data is only testing Private -> private for now
f.children.forEach(function(c, i) {
@@ -270,7 +268,7 @@ describe('HDNode', function() {
hd = hd.derive(c.m)
}
- verifyVector(hd, c, i + 1)
+ verifyVector(hd, network, c, i + 1)
})
})
})
diff --git a/test/network.js b/test/network.js
index 51611f42a..b4cd89f77 100644
--- a/test/network.js
+++ b/test/network.js
@@ -25,7 +25,7 @@ describe('networks', function() {
var extb58 = f.bip32[name]
it('resolves ' + extb58 + ' to ' + f.network, function() {
- assert.equal(HDNode.fromBase58(extb58).network, network)
+ assert.equal(HDNode.fromBase58(extb58, network).network, network)
})
})
})
From 8bdfa881c9c18e905766179d4f847fcf13b0733d Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 29 Nov 2014 12:04:09 +1100
Subject: [PATCH 193/291] tests: remove unused testing data
---
test/fixtures/hdnode.json | 30 ------------------------------
1 file changed, 30 deletions(-)
diff --git a/test/fixtures/hdnode.json b/test/fixtures/hdnode.json
index 8ab9265bf..d87e1bf0b 100644
--- a/test/fixtures/hdnode.json
+++ b/test/fixtures/hdnode.json
@@ -23,9 +23,6 @@
"wif": "L5BmPijJjrKbiUfG4zbiFKNqkvuJ8usooJmzuD7Z8dkRoTThYnAT",
"pubKey": "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56",
"chainCode": "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141",
- "hex": "0488b21e013442193e8000000047fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56",
- "hexPriv": "0488ade4013442193e8000000047fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae623614100edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea",
- "network": "bitcoin",
"base58": "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw",
"base58Priv": "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
"identifier": "5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7",
@@ -38,9 +35,6 @@
"wif": "KyFAjQ5rgrKvhXvNMtFB5PCSKUYD1yyPEe3xr3T34TZSUHycXtMM",
"pubKey": "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c",
"chainCode": "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19",
- "hex": "0488b21e025c1bd648000000012a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c1903501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c",
- "hexPriv": "0488ade4025c1bd648000000012a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19003c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368",
- "network": "bitcoin",
"base58": "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ",
"base58Priv": "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
"identifier": "bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe",
@@ -54,9 +48,6 @@
"wif": "L43t3od1Gh7Lj55Bzjj1xDAgJDcL7YFo2nEcNaMGiyRZS1CidBVU",
"pubKey": "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2",
"chainCode": "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f",
- "hex": "0488b21e03bef5a2f98000000204466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2",
- "hexPriv": "0488ade403bef5a2f98000000204466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f00cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca",
- "network": "bitcoin",
"base58": "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
"base58Priv": "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
"identifier": "ee7ab90cde56a8c0e2bb086ac49748b8db9dce72",
@@ -69,9 +60,6 @@
"wif": "KwjQsVuMjbCP2Zmr3VaFaStav7NvevwjvvkqrWd5Qmh1XVnCteBR",
"pubKey": "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29",
"chainCode": "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd",
- "hex": "0488b21e04ee7ab90c00000002cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29",
- "hexPriv": "0488ade404ee7ab90c00000002cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd000f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4",
- "network": "bitcoin",
"base58": "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV",
"base58Priv": "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
"identifier": "d880d7d893848509a62d8fb74e32148dac68412f",
@@ -84,9 +72,6 @@
"wif": "Kybw8izYevo5xMh1TK7aUr7jHFCxXS1zv8p3oqFz3o2zFbhRXHYs",
"pubKey": "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011",
"chainCode": "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e",
- "hex": "0488b21e05d880d7d83b9aca00c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011",
- "hexPriv": "0488ade405d880d7d83b9aca00c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e00471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8",
- "network": "bitcoin",
"base58": "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy",
"base58Priv": "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
"identifier": "d69aa102255fed74378278c7812701ea641fdf32",
@@ -117,9 +102,6 @@
"wif": "L2ysLrR6KMSAtx7uPqmYpoTeiRzydXBattRXjXz5GDFPrdfPzKbj",
"pubKey": "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea",
"chainCode": "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c",
- "hex": "0488b21e01bd16bee500000000f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea",
- "hexPriv": "0488ade401bd16bee500000000f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c00abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e",
- "network": "bitcoin",
"base58": "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH",
"base58Priv": "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
"identifier": "5a61ff8eb7aaca3010db97ebda76121610b78096",
@@ -133,9 +115,6 @@
"wif": "L1m5VpbXmMp57P3knskwhoMTLdhAAaXiHvnGLMribbfwzVRpz2Sr",
"pubKey": "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b",
"chainCode": "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9",
- "hex": "0488b21e025a61ff8effffffffbe17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d903c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b",
- "hexPriv": "0488ade4025a61ff8effffffffbe17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d900877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93",
- "network": "bitcoin",
"base58": "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a",
"base58Priv": "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
"identifier": "d8ab493736da02f11ed682f88339e720fb0379d1",
@@ -148,9 +127,6 @@
"wif": "KzyzXnznxSv249b4KuNkBwowaN3akiNeEHy5FWoPCJpStZbEKXN2",
"pubKey": "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9",
"chainCode": "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb",
- "hex": "0488b21e03d8ab493700000001f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9",
- "hexPriv": "0488ade403d8ab493700000001f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb00704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7",
- "network": "bitcoin",
"base58": "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon",
"base58Priv": "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
"identifier": "78412e3a2296a40de124307b6485bd19833e2e34",
@@ -164,9 +140,6 @@
"wif": "L5KhaMvPYRW1ZoFmRjUtxxPypQ94m6BcDrPhqArhggdaTbbAFJEF",
"pubKey": "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0",
"chainCode": "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29",
- "hex": "0488b21e0478412e3afffffffe637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e2902d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0",
- "hexPriv": "0488ade40478412e3afffffffe637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e2900f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d",
- "network": "bitcoin",
"base58": "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",
"base58Priv": "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
"identifier": "31a507b815593dfc51ffc7245ae7e5aee304246e",
@@ -179,9 +152,6 @@
"wif": "L3WAYNAZPxx1fr7KCz7GN9nD5qMBnNiqEJNJMU1z9MMaannAt4aK",
"pubKey": "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c",
"chainCode": "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271",
- "hex": "0488b21e0531a507b8000000029452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c",
- "hexPriv": "0488ade40531a507b8000000029452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed27100bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23",
- "network": "bitcoin",
"base58": "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt",
"base58Priv": "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
"identifier": "26132fdbe7bf89cbc64cf8dafa3f9f88b8666220",
From 1ac79b8327f7c809a904e921c6ffdaf0d5ed9f5d Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 29 Nov 2014 12:12:24 +1100
Subject: [PATCH 194/291] tests: add test for non-matching network
---
test/fixtures/hdnode.json | 5 +++++
test/hdnode.js | 4 +++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/test/fixtures/hdnode.json b/test/fixtures/hdnode.json
index d87e1bf0b..77342d0a9 100644
--- a/test/fixtures/hdnode.json
+++ b/test/fixtures/hdnode.json
@@ -201,6 +201,11 @@
{
"exception": "Could not find version 0",
"string": "1111111111111adADjFaSNPxwXqLjHLj4mBfYxuewDPbw9hEj1uaXCzMxRPXDFF3cUoezTFYom4sEmEVSQmENPPR315cFk9YUFVek73wE9"
+ },
+ {
+ "exception": "Network doesn\\'t match",
+ "string": "Ltpv73XYpw28ZyVe2zEVyiFnxUZxoKLGQNdZ8NxUi1WcqjNmMBgtLbh3KimGSnPHCoLv1RmvxHs4dnKmo1oXQ8dXuDu8uroxrbVxZPA1gXboYvx",
+ "network": "bitcoin"
}
],
"fromBuffer": [
diff --git a/test/hdnode.js b/test/hdnode.js
index 7a75e4751..a1cb97a14 100644
--- a/test/hdnode.js
+++ b/test/hdnode.js
@@ -135,7 +135,9 @@ describe('HDNode', function() {
fixtures.invalid.fromBase58.forEach(function(f) {
it('throws on ' + f.string, function() {
assert.throws(function() {
- HDNode.fromBase58(f.string)
+ var network = networks[f.network]
+
+ HDNode.fromBase58(f.string, network)
}, new RegExp(f.exception))
})
})
From b6017b0faee731c59909968093b7d58ddbff5cf4 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 1 Dec 2014 10:43:52 +1100
Subject: [PATCH 195/291] HDNode: move isPrivate logic
---
src/hdnode.js | 20 ++++++--------------
test/fixtures/hdnode.json | 4 ++--
2 files changed, 8 insertions(+), 16 deletions(-)
diff --git a/src/hdnode.js b/src/hdnode.js
index 9e41d1b3a..8979a9ef6 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -11,21 +11,18 @@ var ECPubKey = require('./ecpubkey')
var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')
-function findBIP32ParamsByVersion(version) {
+function findBIP32NetworkByVersion(version) {
for (var name in networks) {
var network = networks[name]
if (version === network.bip32.private ||
version === network.bip32.public) {
- return {
- isPrivate: (version === network.bip32.private),
- network: network
- }
+ return network
}
}
- assert(false, 'Could not find version ' + version.toString(16))
+ assert(false, 'Could not find network for ' + version.toString(16))
}
function HDNode(K, chainCode, network) {
@@ -88,18 +85,13 @@ HDNode.fromBuffer = function(buffer, network, __ignoreDeprecation) {
// 4 byte: version bytes
var version = buffer.readUInt32BE(0)
- var isPrivate
if (network) {
assert(version === network.bip32.private || version === network.bip32.public, 'Network doesn\'t match')
- isPrivate = (version === network.bip32.private)
- // auto-detection
+ // auto-detect
} else {
- var params = findBIP32ParamsByVersion(version)
-
- isPrivate = params.isPrivate
- network = params.network
+ network = findBIP32NetworkByVersion(version)
}
// 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ...
@@ -121,7 +113,7 @@ HDNode.fromBuffer = function(buffer, network, __ignoreDeprecation) {
var data, hd
// 33 bytes: private key data (0x00 + k)
- if (isPrivate) {
+ if (version === network.bip32.private) {
assert.strictEqual(buffer.readUInt8(45), 0x00, 'Invalid private key')
data = buffer.slice(46, 78)
var d = BigInteger.fromBuffer(data)
diff --git a/test/fixtures/hdnode.json b/test/fixtures/hdnode.json
index 77342d0a9..797f940bd 100644
--- a/test/fixtures/hdnode.json
+++ b/test/fixtures/hdnode.json
@@ -199,7 +199,7 @@
"string": "xprvQQQQQQQQQQQQQQQQCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"
},
{
- "exception": "Could not find version 0",
+ "exception": "Could not find network for 0",
"string": "1111111111111adADjFaSNPxwXqLjHLj4mBfYxuewDPbw9hEj1uaXCzMxRPXDFF3cUoezTFYom4sEmEVSQmENPPR315cFk9YUFVek73wE9"
},
{
@@ -226,7 +226,7 @@
"hex": "0488b21e0000000000ffffffff7ffc03d4a1f2fb41ef93374c69e4d19e42e27c9a87ec8b799a205eecd3b43b5f02948d03e260a571e21bcf5bfd8e3b6602800df154906e06b2bc88eee410aee355"
},
{
- "exception": "Could not find version 22222222",
+ "exception": "Could not find network for 22222222",
"hex": "222222220000000000000000007ffc03d4a1f2fb41ef93374c69e4d19e42e27c9a87ec8b799a205eecd3b43b5f02948d03e260a571e21bcf5bfd8e3b6602800df154906e06b2bc88eee410aee355"
},
{
From 6ed8e15b63e39dd1e7097440a7babd1c812c0df4 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 2 Dec 2014 14:20:04 +1100
Subject: [PATCH 196/291] transaction/builder: s/txin/txIn/g
---
src/transaction.js | 44 +++++++++++++++++++-------------------
src/transaction_builder.js | 16 +++++++-------
2 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index bc94d4e80..8a407095f 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -83,7 +83,7 @@ Transaction.fromHex = function(hex) {
}
/**
- * Create a new txin.
+ * Create a new txIn.
*
* Can be called with any of:
*
@@ -122,7 +122,7 @@ Transaction.prototype.addInput = function(hash, index, sequence, script) {
}
/**
- * Create a new txout.
+ * Create a new txOut.
*
* Can be called with:
*
@@ -156,19 +156,19 @@ Transaction.prototype.clone = function () {
newTx.version = this.version
newTx.locktime = this.locktime
- newTx.ins = this.ins.map(function(txin) {
+ newTx.ins = this.ins.map(function(txIn) {
return {
- hash: txin.hash,
- index: txin.index,
- script: txin.script,
- sequence: txin.sequence
+ hash: txIn.hash,
+ index: txIn.index,
+ script: txIn.script,
+ sequence: txIn.sequence
}
})
- newTx.outs = this.outs.map(function(txout) {
+ newTx.outs = this.outs.map(function(txOut) {
return {
- script: txout.script,
- value: txout.value
+ script: txOut.script,
+ value: txOut.value
}
})
@@ -205,8 +205,8 @@ Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashTy
var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR)
// Blank out other inputs' signatures
- txTmp.ins.forEach(function(txin) {
- txin.script = Script.EMPTY
+ txTmp.ins.forEach(function(txIn) {
+ txIn.script = Script.EMPTY
})
txTmp.ins[inIndex].script = hashScript
@@ -280,19 +280,19 @@ Transaction.prototype.toBuffer = function () {
writeUInt32(this.version)
writeVarInt(this.ins.length)
- this.ins.forEach(function(txin) {
- writeSlice(txin.hash)
- writeUInt32(txin.index)
- writeVarInt(txin.script.buffer.length)
- writeSlice(txin.script.buffer)
- writeUInt32(txin.sequence)
+ this.ins.forEach(function(txIn) {
+ writeSlice(txIn.hash)
+ writeUInt32(txIn.index)
+ writeVarInt(txIn.script.buffer.length)
+ writeSlice(txIn.script.buffer)
+ writeUInt32(txIn.sequence)
})
writeVarInt(this.outs.length)
- this.outs.forEach(function(txout) {
- writeUInt64(txout.value)
- writeVarInt(txout.script.buffer.length)
- writeSlice(txout.script.buffer)
+ this.outs.forEach(function(txOut) {
+ writeUInt64(txOut.value)
+ writeVarInt(txOut.script.buffer.length)
+ writeSlice(txOut.script.buffer)
})
writeUInt32(this.locktime)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index c0acb099c..5e0a35f83 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -20,26 +20,26 @@ TransactionBuilder.fromTransaction = function(transaction) {
var txb = new TransactionBuilder()
// Extract/add inputs
- transaction.ins.forEach(function(txin) {
- txb.addInput(txin.hash, txin.index, txin.sequence)
+ transaction.ins.forEach(function(txIn) {
+ txb.addInput(txIn.hash, txIn.index, txIn.sequence)
})
// Extract/add outputs
- transaction.outs.forEach(function(txout) {
- txb.addOutput(txout.script, txout.value)
+ transaction.outs.forEach(function(txOut) {
+ txb.addOutput(txOut.script, txOut.value)
})
// Extract/add signatures
- transaction.ins.forEach(function(txin, i) {
+ transaction.ins.forEach(function(txIn, i) {
// Ignore empty scripts
- if (txin.script.buffer.length === 0) return
+ if (txIn.script.buffer.length === 0) return
- assert(!Array.prototype.every.call(txin.hash, function(x) {
+ assert(!Array.prototype.every.call(txIn.hash, function(x) {
return x === 0
}), 'coinbase inputs not supported')
var redeemScript
- var scriptSig = txin.script
+ var scriptSig = txIn.script
var scriptType = scripts.classifyInput(scriptSig)
// Re-classify if P2SH
From 68e4ba6c936d46c089eb87456a7ea7eaa63f358a Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 2 Dec 2014 15:13:02 +1100
Subject: [PATCH 197/291] 1.4.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index a5d9a1c1c..a96e90508 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.3.1",
+ "version": "1.4.0",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 083e8fa6306f28d53d6bc32aa893a56db7632c9c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 2 Dec 2014 15:15:58 +1100
Subject: [PATCH 198/291] index: expose Block
---
src/index.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/index.js b/src/index.js
index 3761d2773..5dc683f48 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,7 @@
module.exports = {
Address: require('./address'),
base58check: require('./base58check'),
+ Block: require('./block'),
bufferutils: require('./bufferutils'),
crypto: require('./crypto'),
ecdsa: require('./ecdsa'),
From 5bfc89b43d4bd9037d53503e373011dd9cdaf2a6 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 2 Dec 2014 15:16:50 +1100
Subject: [PATCH 199/291] 1.4.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index a96e90508..b2cfc59ec 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.4.0",
+ "version": "1.4.1",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From f3ddc508f1c10a2c0a2601d60ef5a177a314a6ee Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 8 Dec 2014 11:13:42 +1100
Subject: [PATCH 200/291] crypto: add deprecation warnings
---
src/crypto.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/crypto.js b/src/crypto.js
index 890bf0a6b..e62e14b87 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -22,10 +22,12 @@ function sha256(buffer) {
// FIXME: Name not consistent with others
function HmacSHA256(buffer, secret) {
+ console.warn('Hmac* functions are deprecated for removal in 2.0.0, use node crypto instead')
return crypto.createHmac('sha256', secret).update(buffer).digest()
}
function HmacSHA512(buffer, secret) {
+ console.warn('Hmac* functions are deprecated for removal in 2.0.0, use node crypto instead')
return crypto.createHmac('sha512', secret).update(buffer).digest()
}
From 7ef134436ea9af45f4585481f443c24bce6b1fbf Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 8 Dec 2014 11:24:16 +1100
Subject: [PATCH 201/291] ecdsa/HDNode: use node crypto for Hmacs
---
src/ecdsa.js | 33 +++++++++++++++++++++++++--------
src/hdnode.js | 9 +++++----
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/src/ecdsa.js b/src/ecdsa.js
index 75450dcfd..e3343fa1d 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -1,10 +1,13 @@
var assert = require('assert')
-var crypto = require('./crypto')
+var crypto = require('crypto')
var enforceType = require('./types')
var BigInteger = require('bigi')
var ECSignature = require('./ecsignature')
+var ZERO = new Buffer([0])
+var ONE = new Buffer([1])
+
// https://tools.ietf.org/html/rfc6979#section-3.2
function deterministicGenerateK(curve, hash, d) {
enforceType('Buffer', hash)
@@ -24,27 +27,41 @@ function deterministicGenerateK(curve, hash, d) {
k.fill(0)
// Step D
- k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([0]), x, hash]), k)
+ k = crypto.createHmac('sha256', k)
+ .update(v)
+ .update(ZERO)
+ .update(x)
+ .update(hash)
+ .digest()
// Step E
- v = crypto.HmacSHA256(v, k)
+ v = crypto.createHmac('sha256', k).update(v).digest()
// Step F
- k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([1]), x, hash]), k)
+ k = crypto.createHmac('sha256', k)
+ .update(v)
+ .update(ONE)
+ .update(x)
+ .update(hash)
+ .digest()
// Step G
- v = crypto.HmacSHA256(v, k)
+ v = crypto.createHmac('sha256', k).update(v).digest()
// Step H1/H2a, ignored as tlen === qlen (256 bit)
// Step H2b
- v = crypto.HmacSHA256(v, k)
+ v = crypto.createHmac('sha256', k).update(v).digest()
var T = BigInteger.fromBuffer(v)
// Step H3, repeat until T is within the interval [1, n - 1]
while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0)) {
- k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([0])]), k)
- v = crypto.HmacSHA256(v, k)
+ k = crypto.createHmac('sha256', k)
+ .update(v)
+ .update(ZERO)
+ .digest()
+
+ v = crypto.createHmac('sha256', k).update(v).digest()
T = BigInteger.fromBuffer(v)
}
diff --git a/src/hdnode.js b/src/hdnode.js
index 8979a9ef6..a3c9f4b28 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -1,6 +1,7 @@
var assert = require('assert')
var base58check = require('bs58check')
-var crypto = require('./crypto')
+var bcrypto = require('./crypto')
+var crypto = require('crypto')
var enforceType = require('./types')
var networks = require('./networks')
@@ -56,7 +57,7 @@ HDNode.fromSeedBuffer = function(seed, network) {
assert(seed.length >= 16, 'Seed should be at least 128 bits')
assert(seed.length <= 64, 'Seed should be at most 512 bits')
- var I = crypto.HmacSHA512(seed, HDNode.MASTER_SECRET)
+ var I = crypto.createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest()
var IL = I.slice(0, 32)
var IR = I.slice(32)
@@ -145,7 +146,7 @@ HDNode.fromHex = function(hex, network) {
}
HDNode.prototype.getIdentifier = function() {
- return crypto.hash160(this.pubKey.toBuffer())
+ return bcrypto.hash160(this.pubKey.toBuffer())
}
HDNode.prototype.getFingerprint = function() {
@@ -255,7 +256,7 @@ HDNode.prototype.derive = function(index) {
])
}
- var I = crypto.HmacSHA512(data, this.chainCode)
+ var I = crypto.createHmac('sha512', this.chainCode).update(data).digest()
var IL = I.slice(0, 32)
var IR = I.slice(32)
From dd2a264241f72866abc26a289c9a5ca47d33a598 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 8 Dec 2014 11:47:27 +1100
Subject: [PATCH 202/291] 1.4.2
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index b2cfc59ec..6b11f97ee 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.4.1",
+ "version": "1.4.2",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From a66773b5f58d80917ef10e4675df4b471b4b9d5f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 5 Dec 2014 15:07:30 +1100
Subject: [PATCH 203/291] tests/integration: add HDNode private key recovery
example
---
src/hdnode.js | 4 +--
test/integration/crypto.js | 52 ++++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 2 deletions(-)
create mode 100644 test/integration/crypto.js
diff --git a/src/hdnode.js b/src/hdnode.js
index a3c9f4b28..03e5bb126 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -37,6 +37,7 @@ function HDNode(K, chainCode, network) {
this.chainCode = chainCode
this.depth = 0
this.index = 0
+ this.parentFingerprint = 0x00000000
this.network = network
if (K instanceof BigInteger) {
@@ -196,8 +197,7 @@ HDNode.prototype.toBuffer = function(isPrivate, __ignoreDeprecation) {
buffer.writeUInt8(this.depth, 4)
// 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
- var fingerprint = (this.depth === 0) ? 0x00000000 : this.parentFingerprint
- buffer.writeUInt32BE(fingerprint, 5)
+ buffer.writeUInt32BE(this.parentFingerprint, 5)
// 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
// This is encoded in Big endian. (0x00000000 if master key)
diff --git a/test/integration/crypto.js b/test/integration/crypto.js
new file mode 100644
index 000000000..38389b7b8
--- /dev/null
+++ b/test/integration/crypto.js
@@ -0,0 +1,52 @@
+var assert = require('assert')
+var bigi = require('bigi')
+var bitcoin = require('../../')
+var crypto = require('crypto')
+
+describe('bitcoinjs-lib (crypto)', function() {
+ it('can recover a parent private key from the parent\'s public key and a derived non-hardened child private key', function() {
+ function recoverParent(master, child) {
+ assert(!master.privKey, 'You already have the parent private key')
+ assert(child.privKey, 'Missing child private key')
+
+ var curve = bitcoin.ECKey.curve
+ var QP = master.pubKey.toBuffer()
+ var QP64 = QP.toString('base64')
+ var d1 = child.privKey.d
+ var d2
+ var indexBuffer = new Buffer(4)
+
+ // search index space until we find it
+ for (var i = 0; i < bitcoin.HDNode.HIGHEST_BIT; ++i) {
+ indexBuffer.writeUInt32BE(i, 0)
+
+ // calculate I
+ var data = Buffer.concat([QP, indexBuffer])
+ var I = crypto.createHmac('sha512', master.chainCode).update(data).digest()
+ var IL = I.slice(0, 32)
+ var pIL = bigi.fromBuffer(IL)
+
+ // See hdnode.js:273 to understand
+ d2 = d1.subtract(pIL).mod(curve.n)
+
+ var Qp = new bitcoin.ECKey(d2, true).pub.toBuffer()
+ if (Qp.toString('base64') === QP64) break
+ }
+
+ var node = new bitcoin.HDNode(d2, master.chainCode, master.network)
+ node.depth = master.depth
+ node.index = master.index
+ node.masterFingerprint = master.masterFingerprint
+ return node
+ }
+
+ var seed = crypto.randomBytes(32)
+ var master = bitcoin.HDNode.fromSeedBuffer(seed)
+ var child = master.derive(6) // m/6
+
+ // now for the recovery
+ var neuteredMaster = master.neutered()
+ var recovered = recoverParent(neuteredMaster, child)
+ assert.equal(recovered.toBase58(), master.toBase58())
+ })
+})
From de914ff8faeee2ac1ba0e8d46492a86bc47e3805 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 5 Dec 2014 15:09:24 +1100
Subject: [PATCH 204/291] tests/integration: move crypto-like tests to
test/integration/crypto.js
---
test/integration/advanced.js | 36 ------------------------------------
test/integration/crypto.js | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 35 insertions(+), 36 deletions(-)
diff --git a/test/integration/advanced.js b/test/integration/advanced.js
index be6af1f16..a6479f31e 100644
--- a/test/integration/advanced.js
+++ b/test/integration/advanced.js
@@ -1,5 +1,4 @@
var assert = require('assert')
-var bigi = require('bigi')
var bitcoin = require('../../')
var helloblock = require('helloblock-js')({
network: 'testnet'
@@ -22,41 +21,6 @@ describe('bitcoinjs-lib (advanced)', function() {
assert(bitcoin.Message.verify(address, signature, message))
})
- it('can generate a single-key stealth address', function() {
- var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
-
- // XXX: ephemeral, must be random (and secret to sender) to preserve privacy
- var sender = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
-
- var G = bitcoin.ECKey.curve.G
- var d = receiver.d // secret (receiver only)
- var Q = receiver.pub.Q // shared
-
- var e = sender.d // secret (sender only)
- var P = sender.pub.Q // shared
-
- // derived shared secret
- var eQ = Q.multiply(e) // sender
- var dP = P.multiply(d) // receiver
- assert.deepEqual(eQ.getEncoded(), dP.getEncoded())
-
- var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
- var cG = G.multiply(c)
-
- // derived public key
- var QprimeS = Q.add(cG)
- var QprimeR = G.multiply(d.add(c))
- assert.deepEqual(QprimeR.getEncoded(), QprimeS.getEncoded())
-
- // derived shared-secret address
- var address = new bitcoin.ECPubKey(QprimeS).getAddress().toString()
-
- assert.equal(address, '1EwCNJNZM5q58YPPTnjR1H5BvYRNeyZi47')
- })
-
- // TODO
- it.skip('can generate a dual-key stealth address', function() {})
-
it('can create an OP_RETURN transaction', function(done) {
this.timeout(20000)
diff --git a/test/integration/crypto.js b/test/integration/crypto.js
index 38389b7b8..7d5360292 100644
--- a/test/integration/crypto.js
+++ b/test/integration/crypto.js
@@ -4,6 +4,41 @@ var bitcoin = require('../../')
var crypto = require('crypto')
describe('bitcoinjs-lib (crypto)', function() {
+ it('can generate a single-key stealth address', function() {
+ var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
+
+ // XXX: ephemeral, must be random (and secret to sender) to preserve privacy
+ var sender = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
+
+ var G = bitcoin.ECKey.curve.G
+ var d = receiver.d // secret (receiver only)
+ var Q = receiver.pub.Q // shared
+
+ var e = sender.d // secret (sender only)
+ var P = sender.pub.Q // shared
+
+ // derived shared secret
+ var eQ = Q.multiply(e) // sender
+ var dP = P.multiply(d) // receiver
+ assert.deepEqual(eQ.getEncoded(), dP.getEncoded())
+
+ var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
+ var cG = G.multiply(c)
+
+ // derived public key
+ var QprimeS = Q.add(cG)
+ var QprimeR = G.multiply(d.add(c))
+ assert.deepEqual(QprimeR.getEncoded(), QprimeS.getEncoded())
+
+ // derived shared-secret address
+ var address = new bitcoin.ECPubKey(QprimeS).getAddress().toString()
+
+ assert.equal(address, '1EwCNJNZM5q58YPPTnjR1H5BvYRNeyZi47')
+ })
+
+ // TODO
+ it.skip('can generate a dual-key stealth address', function() {})
+
it('can recover a parent private key from the parent\'s public key and a derived non-hardened child private key', function() {
function recoverParent(master, child) {
assert(!master.privKey, 'You already have the parent private key')
From e6b7f51055e35ff93c4616dd4811709a3ed2b424 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 8 Dec 2014 11:58:46 +1100
Subject: [PATCH 205/291] README: update README links
---
README.md | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index cf67965f2..329e7c700 100644
--- a/README.md
+++ b/README.md
@@ -73,11 +73,12 @@ The below examples are implemented as integration tests, they should be very eas
- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L36)
- [Sign a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L9)
- [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L17)
-- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L25)
-- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L58)
-- [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L60)
+- [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L24)
- [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L8)
- [Spend from a 2-of-2 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L22)
+- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L7)
+- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L40)
+- [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L42)
## Projects utilizing BitcoinJS
From 837e0a3564716b0147e00e93a2128d4b353fbe49 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 9 Dec 2014 11:54:36 +1100
Subject: [PATCH 206/291] package: use cb-helloblock for integration tests
---
package.json | 3 ++-
test/integration/advanced.js | 19 ++++++++-----------
test/integration/multisig.js | 16 +++++++---------
3 files changed, 17 insertions(+), 21 deletions(-)
diff --git a/package.json b/package.json
index 6b11f97ee..98801165e 100644
--- a/package.json
+++ b/package.json
@@ -54,10 +54,11 @@
"ecurve": "1.0.0"
},
"devDependencies": {
+ "async": "^0.9.0",
"browserify": "^5.12.0",
"bs58": "^2.0.0",
+ "cb-helloblock": "^0.4.7",
"coveralls": "^2.11.2",
- "helloblock-js": "^0.2.5",
"istanbul": "^0.3.2",
"jshint": "^2.5.6",
"mocha": "^1.21.4",
diff --git a/test/integration/advanced.js b/test/integration/advanced.js
index a6479f31e..b4effbb32 100644
--- a/test/integration/advanced.js
+++ b/test/integration/advanced.js
@@ -1,8 +1,6 @@
var assert = require('assert')
var bitcoin = require('../../')
-var helloblock = require('helloblock-js')({
- network: 'testnet'
-})
+var blockchain = new (require('cb-helloblock'))('testnet')
describe('bitcoinjs-lib (advanced)', function() {
it('can sign a Bitcoin message', function() {
@@ -27,10 +25,10 @@ describe('bitcoinjs-lib (advanced)', function() {
var key = bitcoin.ECKey.fromWIF("L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy")
var address = key.pub.getAddress(bitcoin.networks.testnet).toString()
- helloblock.faucet.withdraw(address, 2e4, function(err) {
+ blockchain.addresses.__faucetWithdraw(address, 2e4, function(err) {
if (err) return done(err)
- helloblock.addresses.getUnspents(address, function(err, _, unspents) {
+ blockchain.addresses.unspents(address, function(err, unspents) {
if (err) return done(err)
// filter small unspents
@@ -44,20 +42,19 @@ describe('bitcoinjs-lib (advanced)', function() {
var data = new Buffer('cafedeadbeef', 'hex')
var dataScript = bitcoin.scripts.nullDataOutput(data)
- tx.addInput(unspent.txHash, unspent.index)
+ tx.addInput(unspent.txId, unspent.vout)
tx.addOutput(dataScript, 1000)
tx.sign(0, key)
- helloblock.transactions.propagate(tx.build().toHex(), function(err) {
+ blockchain.transactions.propagate(tx.build().toHex(), function(err) {
if (err) return done(err)
// check that the message was propagated
- helloblock.addresses.getTransactions(address, function(err, res, transactions) {
+ blockchain.addresses.transactions(address, function(err, transactions) {
if (err) return done(err)
- var transaction = transactions[0]
- var output = transaction.outputs[0]
- var dataScript2 = bitcoin.Script.fromHex(output.scriptPubKey)
+ var transaction = bitcoin.Transaction.fromHex(transactions[0].txHex)
+ var dataScript2 = transaction.outs[0].script
var data2 = dataScript2.chunks[1]
assert.deepEqual(dataScript, dataScript2)
diff --git a/test/integration/multisig.js b/test/integration/multisig.js
index 60f46c9ad..911affddb 100644
--- a/test/integration/multisig.js
+++ b/test/integration/multisig.js
@@ -1,8 +1,6 @@
var assert = require('assert')
var bitcoin = require('../../')
-var helloblock = require('helloblock-js')({
- network: 'testnet'
-})
+var blockchain = new (require('cb-helloblock'))('testnet')
describe('bitcoinjs-lib (multisig)', function() {
it('can create a 2-of-3 multisig P2SH address', function() {
@@ -33,11 +31,11 @@ describe('bitcoinjs-lib (multisig)', function() {
var address = bitcoin.Address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet).toString()
// Attempt to send funds to the source address
- helloblock.faucet.withdraw(address, 2e4, function(err) {
+ blockchain.addresses.__faucetWithdraw(address, 2e4, function(err) {
if (err) return done(err)
// get latest unspents from the address
- helloblock.addresses.getUnspents(address, function(err, _, unspents) {
+ blockchain.addresses.unspents(address, function(err, unspents) {
if (err) return done(err)
// filter small unspents
@@ -50,7 +48,7 @@ describe('bitcoinjs-lib (multisig)', function() {
var targetAddress = bitcoin.ECKey.makeRandom().pub.getAddress(bitcoin.networks.testnet).toString()
var txb = new bitcoin.TransactionBuilder()
- txb.addInput(unspent.txHash, unspent.index)
+ txb.addInput(unspent.txId, unspent.vout)
txb.addOutput(targetAddress, 1e4)
// sign w/ each private key
@@ -59,14 +57,14 @@ describe('bitcoinjs-lib (multisig)', function() {
})
// broadcast our transaction
- helloblock.transactions.propagate(txb.build().toHex(), function(err) {
+ blockchain.transactions.propagate(txb.build().toHex(), function(err) {
if (err) return done(err)
// check that the funds (1e4 Satoshis) indeed arrived at the intended address
- helloblock.addresses.get(targetAddress, function(err, res, addrInfo) {
+ blockchain.addresses.summary(targetAddress, function(err, result) {
if (err) return done(err)
- assert.equal(addrInfo.balance, 1e4)
+ assert.equal(result.balance, 1e4)
done()
})
})
From 3710105eefee476a0a904967995cb0a92bde5530 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 9 Dec 2014 11:52:01 +1100
Subject: [PATCH 207/291] tests/integration: add k-value derivation and private
key recovery example
---
README.md | 1 +
test/integration/crypto.js | 96 ++++++++++++++++++++++++++++++++++++++
2 files changed, 97 insertions(+)
diff --git a/README.md b/README.md
index 329e7c700..e941e4f87 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,7 @@ The below examples are implemented as integration tests, they should be very eas
- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L7)
- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L40)
- [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L42)
+- [Recover a Private key from duplicate R values in a signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L90)
## Projects utilizing BitcoinJS
diff --git a/test/integration/crypto.js b/test/integration/crypto.js
index 7d5360292..06e3cf18a 100644
--- a/test/integration/crypto.js
+++ b/test/integration/crypto.js
@@ -1,6 +1,8 @@
var assert = require('assert')
+var async = require('async')
var bigi = require('bigi')
var bitcoin = require('../../')
+var blockchain = new (require('cb-helloblock'))('bitcoin')
var crypto = require('crypto')
describe('bitcoinjs-lib (crypto)', function() {
@@ -84,4 +86,98 @@ describe('bitcoinjs-lib (crypto)', function() {
var recovered = recoverParent(neuteredMaster, child)
assert.equal(recovered.toBase58(), master.toBase58())
})
+
+ it('can recover a private key from duplicate R values', function() {
+ var inputs = [
+ {
+ txId: "f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50",
+ vout: 0
+ },
+ {
+ txId: "f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50",
+ vout: 1
+ }
+ ]
+
+ var txIds = inputs.map(function(x) { return x.txId })
+
+ // first retrieve the relevant transactions
+ blockchain.transactions.get(txIds, function(err, results) {
+ assert.ifError(err)
+
+ var transactions = {}
+ results.forEach(function(tx) {
+ transactions[tx.txId] = bitcoin.Transaction.fromHex(tx.txHex)
+ })
+
+ var tasks = []
+
+ // now we need to collect/transform a bit of data from the selected inputs
+ inputs.forEach(function(input) {
+ var transaction = transactions[input.txId]
+ var script = transaction.ins[input.vout].script
+ assert(bitcoin.scripts.isPubKeyHashInput(script), 'Expected pubKeyHash script')
+
+ var prevOutTxId = bitcoin.bufferutils.reverse(transaction.ins[input.vout].hash).toString('hex')
+ var prevVout = transaction.ins[input.vout].index
+
+ tasks.push(function(callback) {
+ blockchain.transactions.get(prevOutTxId, function(err, result) {
+ if (err) return callback(err)
+
+ var prevOut = bitcoin.Transaction.fromHex(result.txHex)
+ var prevOutScript = prevOut.outs[prevVout].script
+
+ var scriptSignature = bitcoin.ECSignature.parseScriptSignature(script.chunks[0])
+ var publicKey = bitcoin.ECPubKey.fromBuffer(script.chunks[1])
+
+ var m = transaction.hashForSignature(input.vout, prevOutScript, scriptSignature.hashType)
+ assert(publicKey.verify(m, scriptSignature.signature), 'Invalid m')
+
+ // store the required information
+ input.signature = scriptSignature.signature
+ input.z = bigi.fromBuffer(m)
+
+ return callback()
+ })
+ })
+ })
+
+ // finally, run the tasks, then on to the math
+ async.parallel(tasks, function(err) {
+ if (err) throw err
+ var n = bitcoin.ECKey.curve.n
+
+ for (var i = 0; i < inputs.length; ++i) {
+ for (var j = i + 1; j < inputs.length; ++j) {
+ var inputA = inputs[i]
+ var inputB = inputs[j]
+
+ // enforce matching r values
+ assert.equal(inputA.signature.r.toString(), inputB.signature.r.toString())
+ var r = inputA.signature.r
+ var rInv = r.modInverse(n)
+
+ var s1 = inputA.signature.s
+ var s2 = inputB.signature.s
+ var z1 = inputA.z
+ var z2 = inputB.z
+
+ var zz = z1.subtract(z2).mod(n)
+ var ss = s1.subtract(s2).mod(n)
+
+ // k = (z1 - z2) / (s1 - s2)
+ // d1 = (s1 * k - z1) / r
+ // d2 = (s2 * k - z2) / r
+ var k = zz.multiply(ss.modInverse(n)).mod(n)
+ var d1 = (( s1.multiply(k).mod(n) ).subtract(z1).mod(n) ).multiply(rInv).mod(n)
+ var d2 = (( s2.multiply(k).mod(n) ).subtract(z2).mod(n) ).multiply(rInv).mod(n)
+
+ // enforce matching private keys
+ assert.equal(d1.toString(), d2.toString())
+ }
+ }
+ })
+ })
+ })
})
From 50a32328bab08491219285d7c0c44fa93f372b06 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 12 Dec 2014 16:31:47 +1100
Subject: [PATCH 208/291] tests: remove unused variables
---
test/transaction_builder.js | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 0bc10323d..bdfe48e16 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -1,8 +1,6 @@
var assert = require('assert')
-var ecdsa = require('../src/ecdsa')
var scripts = require('../src/scripts')
-var Address = require('../src/address')
var BigInteger = require('bigi')
var ECKey = require('../src/eckey')
var Script = require('../src/script')
@@ -24,12 +22,10 @@ describe('TransactionBuilder', function() {
prevTx.addOutput('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH', 0)
prevTx.addOutput('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP', 1)
prevTxHash = prevTx.getHash()
- prevTxId = prevTx.getId()
privKey = new ECKey(BigInteger.ONE, false)
privAddress = privKey.pub.getAddress()
privScript = privAddress.toOutputScript()
- value = 10000
})
describe('addInput', function() {
@@ -90,7 +86,7 @@ describe('TransactionBuilder', function() {
describe('addOutput', function() {
it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function() {
txb.addInput(prevTxHash, 0)
- txb.addOutput(privScript, value)
+ txb.addOutput(privScript, 2000)
txb.sign(0, privKey)
assert.throws(function() {
@@ -256,7 +252,7 @@ describe('TransactionBuilder', function() {
})
})
- fixtures.invalid.fromTransaction.forEach(function(f,i) {
+ fixtures.invalid.fromTransaction.forEach(function(f) {
it('throws on ' + f.exception, function() {
var tx = Transaction.fromHex(f.hex)
From 3a17e232ad34418b3db87464ca7baea02bcdcb1d Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 12 Dec 2014 16:38:33 +1100
Subject: [PATCH 209/291] tests: remove unused variable
---
test/message.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/test/message.js b/test/message.js
index 0161e1bcb..37ed1d872 100644
--- a/test/message.js
+++ b/test/message.js
@@ -33,7 +33,6 @@ describe('Message', function() {
it('verifies a valid signature for \"' + f.message + '\" (' + f.network + ')', function() {
var network = networks[f.network]
- var signature = f.signature
assert(Message.verify(f.address, f.signature, f.message, network))
if (f.compressed) {
From fc7c7ce2a8c67b31133bbd7a7097046981fc5936 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 12 Dec 2014 16:41:36 +1100
Subject: [PATCH 210/291] tests: remove extraneous anonymous function
---
test/transaction_builder.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index bdfe48e16..63ad8beee 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -266,7 +266,7 @@ describe('TransactionBuilder', function() {
var privKeys = [
"91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
- ].map(function(wif) { return ECKey.fromWIF(wif) })
+ ].map(ECKey.fromWIF)
var redeemScript = Script.fromASM("OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG")
txb.addInput("4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", 0)
From ca4e64d07110655999204cfb6c4dfd232e7ae414 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 13 Dec 2014 09:20:19 +1100
Subject: [PATCH 211/291] tests: use ASM for fixtures, avoid JSON comparison
---
test/fixtures/transaction.json | 67 +++++++++++++---------------------
test/transaction.js | 59 +++++++++++++++++-------------
2 files changed, 59 insertions(+), 67 deletions(-)
diff --git a/test/fixtures/transaction.json b/test/fixtures/transaction.json
index c47332330..36cf356ed 100644
--- a/test/fixtures/transaction.json
+++ b/test/fixtures/transaction.json
@@ -10,13 +10,12 @@
{
"hash": "f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe",
"index": 0,
- "script": "4830450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
- "sequence": 4294967295
+ "script": "30450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
}
],
"outs": [
{
- "script": "76a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac",
+ "script": "OP_DUP OP_HASH160 c42e7ef92fdb603af844d064faad95db9bcdfd3d OP_EQUALVERIFY OP_CHECKSIG",
"value": 100000
}
],
@@ -26,37 +25,37 @@
},
{
"description": "Standard transaction (2:2)",
- "txid": "eb1c3a8b1bd7d38a6bd8f3c48e8fc950cf3ddf9b34e91594d8c1b31e0bcf8240",
- "hash": "4082cf0b1eb3c1d89415e9349bdf3dcf50c98f8ec4f3d86b8ad3d71b8b3a1ceb",
+ "txid": "fcdd6d89c43e76dcff94285d9b6e31d5c60cb5e397a76ebc4920befad30907bc",
+ "hash": "bc0709d3fabe2049bc6ea797e3b50cc6d5316e9b5d2894ffdc763ec4896dddfc",
"raw": {
"version": 1,
"ins": [
{
"hash": "f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe",
"index": 0,
- "script": "483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ "script": "3045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"sequence": 4294967295
},
{
"hash": "f2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe",
"index": 1,
- "script": "483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687",
- "sequence": 4294967295
+ "script": "3045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c7801 02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5 a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687",
+ "sequence": 2147483648
}
],
"outs": [
{
- "script": "76a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac",
+ "script": "OP_DUP OP_HASH160 c42e7ef92fdb603af844d064faad95db9bcdfd3d OP_EQUALVERIFY OP_CHECKSIG",
"value": 50000
},
{
- "script": "a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687",
+ "script": "OP_HASH160 7ccb85f0ab2d599bc17246c98babd5a20b1cdc76 OP_EQUAL",
"value": 150000
}
],
"locktime": 0
},
- "hex": "0100000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687ffffffff0250c30000000000001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88acf04902000000000017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000"
+ "hex": "0100000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687000000800250c30000000000001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88acf04902000000000017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000"
},
{
"description": "Standard transaction (14:2)",
@@ -69,96 +68,82 @@
{
"hash": "e7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0",
"index": 0,
- "script": "493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c01 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea",
"index": 1,
- "script": "483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b01 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3",
"index": 1,
- "script": "473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa401 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "e6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b",
"index": 0,
- "script": "483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba2673801 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "e6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b",
"index": 1,
- "script": "4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "30440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe04118101 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "d3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d",
"index": 1,
- "script": "483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d48901 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31",
"index": 1,
- "script": "483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a016801 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084",
"index": 1,
- "script": "47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c801 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "ecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663",
"index": 1,
- "script": "473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a8017351401 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "a1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e",
"index": 1,
- "script": "48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a01 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "b89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8",
"index": 0,
- "script": "4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "30450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd401 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0",
"index": 1,
- "script": "483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced801 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170",
"index": 1,
- "script": "493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c01 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
},
{
"hash": "a4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959",
"index": 1,
- "script": "483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
- "sequence": 4294967295
+ "script": "3045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa37219501 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
}
],
"outs": [
{
"value": 52680000,
- "script": "76a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac"
+ "script": "OP_DUP OP_HASH160 167c3e1f10cc3b691c73afbdb211e156e3e3f25c OP_EQUALVERIFY OP_CHECKSIG"
},
{
"value": 3032597,
- "script": "76a914290f7d617b75993e770e5606335fa0999a28d71388ac"
+ "script": "OP_DUP OP_HASH160 290f7d617b75993e770e5606335fa0999a28d713 OP_EQUALVERIFY OP_CHECKSIG"
}
]
},
diff --git a/test/transaction.js b/test/transaction.js
index d07061adb..454bbbf94 100644
--- a/test/transaction.js
+++ b/test/transaction.js
@@ -8,27 +8,32 @@ var Script = require('../src/script')
var fixtures = require('./fixtures/transaction')
-// FIXME: what is a better way to do this, seems a bit odd
-fixtures.valid.forEach(function(f) {
- var Script = require('../src/script')
+describe('Transaction', function() {
+ function fromRaw(raw) {
+ var tx = new Transaction()
+ tx.version = raw.version
+ tx.locktime = raw.locktime
- f.raw.ins.forEach(function(fin) {
- fin.hash = new Buffer(fin.hash, 'hex')
- fin.script = Script.fromHex(fin.script)
- })
+ raw.ins.forEach(function(txIn) {
+ var txHash = new Buffer(txIn.hash, 'hex')
+ var script = txIn.script ? Script.fromASM(txIn.script) : undefined
- f.raw.outs.forEach(function(fout) {
- fout.script = Script.fromHex(fout.script)
- })
-})
+ tx.addInput(txHash, txIn.index, txIn.sequence, script)
+ })
+
+ raw.outs.forEach(function(txOut) {
+ tx.addOutput(Script.fromASM(txOut.script), txOut.value)
+ })
+
+ return tx
+ }
-describe('Transaction', function() {
describe('fromBuffer/fromHex', function() {
fixtures.valid.forEach(function(f) {
it('imports ' + f.txid + ' correctly', function() {
var actual = Transaction.fromHex(f.hex)
- assert.deepEqual(actual, f.raw)
+ assert.deepEqual(actual.toHex(), f.hex)
})
})
@@ -44,9 +49,9 @@ describe('Transaction', function() {
describe('toBuffer/toHex', function() {
fixtures.valid.forEach(function(f) {
it('exports ' + f.txid + ' correctly', function() {
- var actual = Transaction.prototype.toBuffer.call(f.raw)
+ var actual = fromRaw(f.raw)
- assert.equal(actual.toString('hex'), f.hex)
+ assert.deepEqual(actual.toHex(), f.hex)
})
})
})
@@ -108,18 +113,19 @@ describe('Transaction', function() {
var tx = new Transaction()
f.raw.ins.forEach(function(txIn, i) {
- var script = txIn.script ? Script.fromHex(txIn.script) : undefined
- var j = tx.addInput(txIn.hash, txIn.index, txIn.sequence, script)
+ var txHash = new Buffer(txIn.hash, 'hex')
+ var script = txIn.script ? Script.fromASM(txIn.script) : undefined
+ var j = tx.addInput(txHash, txIn.index, txIn.sequence, script)
+ var sequence = txIn.sequence
+ if (sequence === undefined) {
+ sequence = Transaction.DEFAULT_SEQUENCE
+ }
assert.equal(i, j)
- assert.deepEqual(tx.ins[i].hash, txIn.hash)
+ assert.equal(tx.ins[i].hash.toString('hex'), txIn.hash)
assert.equal(tx.ins[i].index, txIn.index)
-
- var sequence = txIn.sequence
- if (sequence === undefined) sequence = Transaction.DEFAULT_SEQUENCE
-
assert.equal(tx.ins[i].sequence, sequence)
- assert.equal(tx.ins[i].script, script || Script.EMPTY)
+ assert.deepEqual(tx.ins[i].script, script || Script.EMPTY)
})
})
})
@@ -181,12 +187,13 @@ describe('Transaction', function() {
var tx = new Transaction()
f.raw.outs.forEach(function(txOut, i) {
- var j = tx.addOutput(txOut.script, txOut.value)
+ var scriptPubKey = Script.fromASM(txOut.script)
+ var j = tx.addOutput(scriptPubKey, txOut.value)
assert.equal(i, j)
+ assert.equal(tx.outs[i].script, scriptPubKey)
+ assert.equal(tx.outs[i].value, txOut.value)
})
-
- assert.deepEqual(tx.outs, f.raw.outs)
})
})
})
From fc690d418b50d88e1a4b8e2ef4a4f005350e5653 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sat, 13 Dec 2014 09:48:31 +1100
Subject: [PATCH 212/291] tests: rename txid to id in Transaction context
---
test/fixtures/transaction.json | 6 +++---
test/transaction.js | 14 +++++++-------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/test/fixtures/transaction.json b/test/fixtures/transaction.json
index 36cf356ed..9ddbfb0d3 100644
--- a/test/fixtures/transaction.json
+++ b/test/fixtures/transaction.json
@@ -2,7 +2,7 @@
"valid": [
{
"description": "Standard transaction (1:1)",
- "txid": "a0ff943d3f644d8832b1fa74be4d0ad2577615dc28a7ef74ff8c271b603a082a",
+ "id": "a0ff943d3f644d8832b1fa74be4d0ad2577615dc28a7ef74ff8c271b603a082a",
"hash": "2a083a601b278cff74efa728dc157657d20a4dbe74fab132884d643f3d94ffa0",
"raw": {
"version": 1,
@@ -25,7 +25,7 @@
},
{
"description": "Standard transaction (2:2)",
- "txid": "fcdd6d89c43e76dcff94285d9b6e31d5c60cb5e397a76ebc4920befad30907bc",
+ "id": "fcdd6d89c43e76dcff94285d9b6e31d5c60cb5e397a76ebc4920befad30907bc",
"hash": "bc0709d3fabe2049bc6ea797e3b50cc6d5316e9b5d2894ffdc763ec4896dddfc",
"raw": {
"version": 1,
@@ -59,7 +59,7 @@
},
{
"description": "Standard transaction (14:2)",
- "txid": "39d57bc27f72e904d81f6b5ef7b4e6e17fa33a06b11e5114a43435830d7b5563",
+ "id": "39d57bc27f72e904d81f6b5ef7b4e6e17fa33a06b11e5114a43435830d7b5563",
"hash": "63557b0d833534a414511eb1063aa37fe1e6b4f75e6b1fd804e9727fc27bd539",
"raw": {
"version": 1,
diff --git a/test/transaction.js b/test/transaction.js
index 454bbbf94..41f94f6b0 100644
--- a/test/transaction.js
+++ b/test/transaction.js
@@ -30,7 +30,7 @@ describe('Transaction', function() {
describe('fromBuffer/fromHex', function() {
fixtures.valid.forEach(function(f) {
- it('imports ' + f.txid + ' correctly', function() {
+ it('imports ' + f.id + ' correctly', function() {
var actual = Transaction.fromHex(f.hex)
assert.deepEqual(actual.toHex(), f.hex)
@@ -48,7 +48,7 @@ describe('Transaction', function() {
describe('toBuffer/toHex', function() {
fixtures.valid.forEach(function(f) {
- it('exports ' + f.txid + ' correctly', function() {
+ it('exports ' + f.id + ' correctly', function() {
var actual = fromRaw(f.raw)
assert.deepEqual(actual.toHex(), f.hex)
@@ -109,7 +109,7 @@ describe('Transaction', function() {
})
fixtures.valid.forEach(function(f) {
- it('should add the inputs for ' + f.txid + ' correctly', function() {
+ it('should add the inputs for ' + f.id + ' correctly', function() {
var tx = new Transaction()
f.raw.ins.forEach(function(txIn, i) {
@@ -183,7 +183,7 @@ describe('Transaction', function() {
})
fixtures.valid.forEach(function(f) {
- it('should add the outputs for ' + f.txid + ' correctly', function() {
+ it('should add the outputs for ' + f.id + ' correctly', function() {
var tx = new Transaction()
f.raw.outs.forEach(function(txOut, i) {
@@ -215,18 +215,18 @@ describe('Transaction', function() {
describe('getId', function() {
fixtures.valid.forEach(function(f) {
- it('should return the txid for ' + f.txid, function() {
+ it('should return the id for ' + f.id, function() {
var tx = Transaction.fromHex(f.hex)
var actual = tx.getId()
- assert.equal(actual, f.txid)
+ assert.equal(actual, f.id)
})
})
})
describe('getHash', function() {
fixtures.valid.forEach(function(f) {
- it('should return the hash for ' + f.txid, function() {
+ it('should return the hash for ' + f.id, function() {
var tx = Transaction.fromHex(f.hex)
var actual = tx.getHash().toString('hex')
From 044c53bcad2e28f90d406f7a1ccfb1aca23073e7 Mon Sep 17 00:00:00 2001
From: Bez Reyhan
Date: Fri, 12 Dec 2014 12:28:26 -0800
Subject: [PATCH 213/291] transaction.addInput checks if sequence is NULL
---
src/transaction.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/transaction.js b/src/transaction.js
index 8a407095f..167126c64 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -93,7 +93,10 @@ Transaction.fromHex = function(hex) {
* Note that this method does not sign the created input.
*/
Transaction.prototype.addInput = function(hash, index, sequence, script) {
- if (sequence === undefined) sequence = Transaction.DEFAULT_SEQUENCE
+ if (sequence === undefined || sequence === null) {
+ sequence = Transaction.DEFAULT_SEQUENCE
+ }
+
script = script || Script.EMPTY
if (typeof hash === 'string') {
From 1c6d5a28a968a63f87f3631a1f6ea0e3b040c8af Mon Sep 17 00:00:00 2001
From: Bez Reyhan
Date: Mon, 15 Dec 2014 19:21:34 -0800
Subject: [PATCH 214/291] update fixtures and tests for merge
---
test/fixtures/transaction.json | 5 +++++
test/transaction.js | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/test/fixtures/transaction.json b/test/fixtures/transaction.json
index 9ddbfb0d3..32dad1db0 100644
--- a/test/fixtures/transaction.json
+++ b/test/fixtures/transaction.json
@@ -65,6 +65,11 @@
"version": 1,
"locktime": 0,
"ins": [
+ {
+ "hash": "2afdde042a49d7cf5c34c9ec2331049bb8cbc5841d7324748eab52bf10dfb954",
+ "index": 1,
+ "script": null
+ },
{
"hash": "e7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0",
"index": 0,
diff --git a/test/transaction.js b/test/transaction.js
index 41f94f6b0..b54185ed9 100644
--- a/test/transaction.js
+++ b/test/transaction.js
@@ -117,7 +117,7 @@ describe('Transaction', function() {
var script = txIn.script ? Script.fromASM(txIn.script) : undefined
var j = tx.addInput(txHash, txIn.index, txIn.sequence, script)
var sequence = txIn.sequence
- if (sequence === undefined) {
+ if (sequence === undefined || sequence === null ) {
sequence = Transaction.DEFAULT_SEQUENCE
}
From 85979a062e551a4032123cbfa23348ff4062db98 Mon Sep 17 00:00:00 2001
From: Bez Reyhan
Date: Mon, 15 Dec 2014 20:10:32 -0800
Subject: [PATCH 215/291] remove fixture
---
test/fixtures/transaction.json | 5 -----
1 file changed, 5 deletions(-)
diff --git a/test/fixtures/transaction.json b/test/fixtures/transaction.json
index 32dad1db0..9ddbfb0d3 100644
--- a/test/fixtures/transaction.json
+++ b/test/fixtures/transaction.json
@@ -65,11 +65,6 @@
"version": 1,
"locktime": 0,
"ins": [
- {
- "hash": "2afdde042a49d7cf5c34c9ec2331049bb8cbc5841d7324748eab52bf10dfb954",
- "index": 1,
- "script": null
- },
{
"hash": "e7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0",
"index": 0,
From c716367f77327c79329a8633250368b9ce54e252 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 16 Dec 2014 15:15:39 +1100
Subject: [PATCH 216/291] tests: add test for null sequence number
---
test/fixtures/transaction.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/fixtures/transaction.json b/test/fixtures/transaction.json
index 9ddbfb0d3..cb6559713 100644
--- a/test/fixtures/transaction.json
+++ b/test/fixtures/transaction.json
@@ -68,7 +68,8 @@
{
"hash": "e7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0",
"index": 0,
- "script": "3046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c01 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f"
+ "script": "3046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c01 04aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19f",
+ "sequence": null
},
{
"hash": "7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea",
From e42c497a3c9afe67c86ba0a602b5a0e9bd66e604 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 23 Dec 2014 15:08:20 +1100
Subject: [PATCH 217/291] package: use typeforce
---
package.json | 3 ++-
src/address.js | 4 ++--
src/ecdsa.js | 6 +++---
src/eckey.js | 4 ++--
src/ecpubkey.js | 6 +++---
src/ecsignature.js | 6 +++---
src/hdnode.js | 6 +++---
src/script.js | 8 ++++----
src/scripts.js | 16 ++++++++--------
src/transaction.js | 22 +++++++++++-----------
src/types.js | 40 ----------------------------------------
src/wallet.js | 10 +++++-----
test/types.js | 28 ----------------------------
13 files changed, 46 insertions(+), 113 deletions(-)
delete mode 100644 src/types.js
delete mode 100644 test/types.js
diff --git a/package.json b/package.json
index 98801165e..1ee96bd61 100644
--- a/package.json
+++ b/package.json
@@ -51,7 +51,8 @@
"bigi": "^1.1.0",
"bs58check": "1.0.3",
"crypto-browserify": "^3.2.6",
- "ecurve": "1.0.0"
+ "ecurve": "1.0.0",
+ "typeforce": "0.0.2"
},
"devDependencies": {
"async": "^0.9.0",
diff --git a/src/address.js b/src/address.js
index cc6264fe4..be2b239c9 100644
--- a/src/address.js
+++ b/src/address.js
@@ -1,6 +1,6 @@
var assert = require('assert')
var base58check = require('bs58check')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var networks = require('./networks')
var scripts = require('./scripts')
@@ -14,7 +14,7 @@ function findScriptTypeByVersion(version) {
}
function Address(hash, version) {
- enforceType('Buffer', hash)
+ typeForce('Buffer', hash)
assert.strictEqual(hash.length, 20, 'Invalid hash length')
assert.strictEqual(version & 0xff, version, 'Invalid version byte')
diff --git a/src/ecdsa.js b/src/ecdsa.js
index e3343fa1d..28ba1b4ab 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -1,6 +1,6 @@
var assert = require('assert')
var crypto = require('crypto')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var BigInteger = require('bigi')
var ECSignature = require('./ecsignature')
@@ -10,8 +10,8 @@ var ONE = new Buffer([1])
// https://tools.ietf.org/html/rfc6979#section-3.2
function deterministicGenerateK(curve, hash, d) {
- enforceType('Buffer', hash)
- enforceType(BigInteger, d)
+ typeForce('Buffer', hash)
+ typeForce('BigInteger', d)
// sanity check
assert.equal(hash.length, 32, 'Hash must be 256 bit')
diff --git a/src/eckey.js b/src/eckey.js
index 501384dcd..74ba93c76 100644
--- a/src/eckey.js
+++ b/src/eckey.js
@@ -2,7 +2,7 @@ var assert = require('assert')
var base58check = require('bs58check')
var crypto = require('crypto')
var ecdsa = require('./ecdsa')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var networks = require('./networks')
var BigInteger = require('bigi')
@@ -50,7 +50,7 @@ ECKey.makeRandom = function(compressed, rng) {
rng = rng || crypto.randomBytes
var buffer = rng(32)
- enforceType('Buffer', buffer)
+ typeForce('Buffer', buffer)
assert.equal(buffer.length, 32, 'Expected 256-bit Buffer from RNG')
var d = BigInteger.fromBuffer(buffer)
diff --git a/src/ecpubkey.js b/src/ecpubkey.js
index e2b25bc03..860e415a6 100644
--- a/src/ecpubkey.js
+++ b/src/ecpubkey.js
@@ -1,6 +1,6 @@
var crypto = require('./crypto')
var ecdsa = require('./ecdsa')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var networks = require('./networks')
var Address = require('./address')
@@ -11,8 +11,8 @@ var secp256k1 = ecurve.getCurveByName('secp256k1')
function ECPubKey(Q, compressed) {
if (compressed === undefined) compressed = true
- enforceType(ecurve.Point, Q)
- enforceType('Boolean', compressed)
+ typeForce('Point', Q)
+ typeForce('Boolean', compressed)
this.compressed = compressed
this.Q = Q
diff --git a/src/ecsignature.js b/src/ecsignature.js
index 7b71c6183..073d7f125 100644
--- a/src/ecsignature.js
+++ b/src/ecsignature.js
@@ -1,11 +1,11 @@
var assert = require('assert')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var BigInteger = require('bigi')
function ECSignature(r, s) {
- enforceType(BigInteger, r)
- enforceType(BigInteger, s)
+ typeForce('BigInteger', r)
+ typeForce('BigInteger', s)
this.r = r
this.s = s
diff --git a/src/hdnode.js b/src/hdnode.js
index 03e5bb126..e81dc4ecb 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -2,7 +2,7 @@ var assert = require('assert')
var base58check = require('bs58check')
var bcrypto = require('./crypto')
var crypto = require('crypto')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var networks = require('./networks')
var BigInteger = require('bigi')
@@ -29,7 +29,7 @@ function findBIP32NetworkByVersion(version) {
function HDNode(K, chainCode, network) {
network = network || networks.bitcoin
- enforceType('Buffer', chainCode)
+ typeForce('Buffer', chainCode)
assert.equal(chainCode.length, 32, 'Expected chainCode length of 32, got ' + chainCode.length)
assert(network.bip32, 'Unknown BIP32 constants for network')
@@ -53,7 +53,7 @@ HDNode.HIGHEST_BIT = 0x80000000
HDNode.LENGTH = 78
HDNode.fromSeedBuffer = function(seed, network) {
- enforceType('Buffer', seed)
+ typeForce('Buffer', seed)
assert(seed.length >= 16, 'Seed should be at least 128 bits')
assert(seed.length <= 64, 'Seed should be at most 512 bits')
diff --git a/src/script.js b/src/script.js
index d3afc7061..2283495c9 100644
--- a/src/script.js
+++ b/src/script.js
@@ -1,12 +1,12 @@
var assert = require('assert')
var bufferutils = require('./bufferutils')
var crypto = require('./crypto')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var opcodes = require('./opcodes')
function Script(buffer, chunks) {
- enforceType('Buffer', buffer)
- enforceType('Array', chunks)
+ typeForce('Buffer', buffer)
+ typeForce('Array', chunks)
this.buffer = buffer
this.chunks = chunks
@@ -56,7 +56,7 @@ Script.fromBuffer = function(buffer) {
}
Script.fromChunks = function(chunks) {
- enforceType('Array', chunks)
+ typeForce('Array', chunks)
var bufferSize = chunks.reduce(function(accum, chunk) {
if (Buffer.isBuffer(chunk)) {
diff --git a/src/scripts.js b/src/scripts.js
index 0ffb1e049..33f51ca94 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -1,5 +1,5 @@
var assert = require('assert')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var ops = require('./opcodes')
var ecurve = require('ecurve')
@@ -117,7 +117,7 @@ function isNullDataOutput(script) {
}
function classifyOutput(script) {
- enforceType(Script, script)
+ typeForce('Script', script)
if (isPubKeyHashOutput(script)) {
return 'pubkeyhash'
@@ -135,7 +135,7 @@ function classifyOutput(script) {
}
function classifyInput(script) {
- enforceType(Script, script)
+ typeForce('Script', script)
if (isPubKeyHashInput(script)) {
return 'pubkeyhash'
@@ -161,7 +161,7 @@ function pubKeyOutput(pubKey) {
// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput(hash) {
- enforceType('Buffer', hash)
+ typeForce('Buffer', hash)
return Script.fromChunks([
ops.OP_DUP,
@@ -174,7 +174,7 @@ function pubKeyHashOutput(hash) {
// OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput(hash) {
- enforceType('Buffer', hash)
+ typeForce('Buffer', hash)
return Script.fromChunks([
ops.OP_HASH160,
@@ -185,7 +185,7 @@ function scriptHashOutput(hash) {
// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput(m, pubKeys) {
- enforceType('Array', pubKeys)
+ typeForce('Array', pubKeys)
assert(pubKeys.length >= m, 'Not enough pubKeys provided')
@@ -204,14 +204,14 @@ function multisigOutput(m, pubKeys) {
// {signature}
function pubKeyInput(signature) {
- enforceType('Buffer', signature)
+ typeForce('Buffer', signature)
return Script.fromChunks([signature])
}
// {signature} {pubKey}
function pubKeyHashInput(signature, pubKey) {
- enforceType('Buffer', signature)
+ typeForce('Buffer', signature)
return Script.fromChunks([signature, pubKey.toBuffer()])
}
diff --git a/src/transaction.js b/src/transaction.js
index 167126c64..a952dbb6a 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -1,7 +1,7 @@
var assert = require('assert')
var bufferutils = require('./bufferutils')
var crypto = require('./crypto')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var opcodes = require('./opcodes')
var scripts = require('./scripts')
@@ -96,7 +96,7 @@ Transaction.prototype.addInput = function(hash, index, sequence, script) {
if (sequence === undefined || sequence === null) {
sequence = Transaction.DEFAULT_SEQUENCE
}
-
+
script = script || Script.EMPTY
if (typeof hash === 'string') {
@@ -108,10 +108,10 @@ Transaction.prototype.addInput = function(hash, index, sequence, script) {
}
- enforceType('Buffer', hash)
- enforceType('Number', index)
- enforceType('Number', sequence)
- enforceType(Script, script)
+ typeForce('Buffer', hash)
+ typeForce('Number', index)
+ typeForce('Number', sequence)
+ typeForce('Script', script)
assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
@@ -144,8 +144,8 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) {
scriptPubKey = scriptPubKey.toOutputScript()
}
- enforceType(Script, scriptPubKey)
- enforceType('Number', value)
+ typeForce('Script', scriptPubKey)
+ typeForce('Number', value)
// Add the output and return the output's index
return (this.outs.push({
@@ -197,9 +197,9 @@ Transaction.prototype.hashForSignature = function(inIndex, prevOutScript, hashTy
prevOutScript = tmp
}
- enforceType('Number', inIndex)
- enforceType(Script, prevOutScript)
- enforceType('Number', hashType)
+ typeForce('Number', inIndex)
+ typeForce('Script', prevOutScript)
+ typeForce('Number', hashType)
assert(inIndex >= 0, 'Invalid vin index')
assert(inIndex < this.ins.length, 'Invalid vin index')
diff --git a/src/types.js b/src/types.js
deleted file mode 100644
index 5f885d0c5..000000000
--- a/src/types.js
+++ /dev/null
@@ -1,40 +0,0 @@
-module.exports = function enforce(type, value) {
- switch (type) {
- case 'Array': {
- if (Array.isArray(value)) return
- break
- }
-
- case 'Boolean': {
- if (typeof value === 'boolean') return
- break
- }
-
- case 'Buffer': {
- if (Buffer.isBuffer(value)) return
- break
- }
-
- case 'Number': {
- if (typeof value === 'number') return
- break
- }
-
- case 'String': {
- if (typeof value === 'string') return
- break
- }
-
- default: {
- if (getName(value.constructor) === getName(type)) return
- }
- }
-
- throw new TypeError('Expected ' + (getName(type) || type) + ', got ' + value)
-}
-
-function getName(fn) {
- // Why not fn.name: https://kangax.github.io/compat-table/es6/#function_name_property
- var match = fn.toString().match(/function (.*?)\(/)
- return match ? match[1] : null
-}
diff --git a/src/wallet.js b/src/wallet.js
index f7068ff29..3e3ab7799 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -1,7 +1,7 @@
var assert = require('assert')
var bufferutils = require('./bufferutils')
var crypto = require('crypto')
-var enforceType = require('./types')
+var typeForce = require('typeforce')
var networks = require('./networks')
var Address = require('./address')
@@ -303,9 +303,9 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
index = unspent.outputIndex
}
- enforceType('String', txId)
- enforceType('Number', index)
- enforceType('Number', unspent.value)
+ typeForce('String', txId)
+ typeForce('Number', index)
+ typeForce('Number', unspent.value)
assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId)
assert.doesNotThrow(function() { Address.fromBase58Check(unspent.address) }, 'Expected Base58 Address, got ' + unspent.address)
@@ -313,7 +313,7 @@ Wallet.prototype.setUnspentOutputs = function(unspents) {
// FIXME: remove branch in 2.0.0
if (unspent.confirmations !== undefined) {
- enforceType('Number', unspent.confirmations)
+ typeForce('Number', unspent.confirmations)
}
var txHash = bufferutils.reverse(new Buffer(txId, 'hex'))
diff --git a/test/types.js b/test/types.js
deleted file mode 100644
index fe1d149c7..000000000
--- a/test/types.js
+++ /dev/null
@@ -1,28 +0,0 @@
-var assert = require('assert')
-var enforceType = require('../src/types')
-
-function CustomType() { return "ensure non-greedy match".toUpperCase() }
-
-var types = ['Array', 'Boolean', 'Buffer', 'Number', 'String', CustomType]
-var values = [[], true, new Buffer(1), 1234, 'foobar', new CustomType()]
-
-describe('enforceType', function() {
- types.forEach(function(type, i) {
- describe(type, function() {
- values.forEach(function(value, j) {
- if (j === i) {
- it('passes for ' + types[j], function() {
- enforceType(type, value)
- })
-
- } else {
- it('fails for ' + types[j], function() {
- assert.throws(function() {
- enforceType(type, value)
- }, new RegExp('Expected ' + (type.name || type) + ', got '))
- })
- }
- })
- })
- })
-})
From 0524ced98464c4643366f77042da1e8fe2a86af1 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 23 Dec 2014 15:30:14 +1100
Subject: [PATCH 218/291] scripts: enforce pubKeys as type ECPubKey
---
src/scripts.js | 2 +-
test/scripts.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index 33f51ca94..606e14b7e 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -185,7 +185,7 @@ function scriptHashOutput(hash) {
// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput(m, pubKeys) {
- typeForce('Array', pubKeys)
+ typeForce(['ECPubKey'], pubKeys)
assert(pubKeys.length >= m, 'Not enough pubKeys provided')
diff --git a/test/scripts.js b/test/scripts.js
index 8405cd572..ac35a65bb 100644
--- a/test/scripts.js
+++ b/test/scripts.js
@@ -168,7 +168,7 @@ describe('Scripts', function() {
})
fixtures.invalid.multisigOutput.forEach(function(f) {
- var pubKeys = f.pubKeys.map(function(p) { return new Buffer(p, 'hex') })
+ var pubKeys = f.pubKeys.map(ECPubKey.fromHex)
it('throws on ' + f.exception, function() {
assert.throws(function() {
From c41bc33c5c9e1275cb5552ad2a0c9c8543d1d10c Mon Sep 17 00:00:00 2001
From: Ben Holden-Crowther
Date: Thu, 1 Jan 2015 11:41:21 +0000
Subject: [PATCH 219/291] Updated license date
Updated license date to 2015 for new year.
---
LICENSE | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/LICENSE b/LICENSE
index 2b07c4258..7f5a4ce67 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2011-2014 Bitcoinjs-lib contributors
+Copyright (c) 2011-2015 Bitcoinjs-lib contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
From 4c61380fa571c1474fdfd75692721d575e1be71c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 4 Jan 2015 12:29:01 +1100
Subject: [PATCH 220/291] ecdsa: add comment for Step A
---
src/ecdsa.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/ecdsa.js b/src/ecdsa.js
index 28ba1b4ab..2765fb940 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -20,6 +20,7 @@ function deterministicGenerateK(curve, hash, d) {
var k = new Buffer(32)
var v = new Buffer(32)
+ // Step A, ignored as hash already provided
// Step B
v.fill(1)
From e9778ae358b5d6da69e5ceade8e8227dddf6d8be Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 4 Jan 2015 12:46:37 +1100
Subject: [PATCH 221/291] ecdsa: fixes edge case presented in #336
---
package.json | 2 +-
src/ecdsa.js | 34 ++++++++++++++++++++++++----------
test/ecdsa.js | 6 ++++--
3 files changed, 29 insertions(+), 13 deletions(-)
diff --git a/package.json b/package.json
index 1ee96bd61..d91156442 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,7 @@
"bs58check": "1.0.3",
"crypto-browserify": "^3.2.6",
"ecurve": "1.0.0",
- "typeforce": "0.0.2"
+ "typeforce": "0.1.0"
},
"devDependencies": {
"async": "^0.9.0",
diff --git a/src/ecdsa.js b/src/ecdsa.js
index 2765fb940..d330add33 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -9,9 +9,10 @@ var ZERO = new Buffer([0])
var ONE = new Buffer([1])
// https://tools.ietf.org/html/rfc6979#section-3.2
-function deterministicGenerateK(curve, hash, d) {
+function deterministicGenerateK(curve, hash, d, checkSig) {
typeForce('Buffer', hash)
typeForce('BigInteger', d)
+ typeForce('Function', checkSig)
// sanity check
assert.equal(hash.length, 32, 'Hash must be 256 bit')
@@ -55,8 +56,8 @@ function deterministicGenerateK(curve, hash, d) {
var T = BigInteger.fromBuffer(v)
- // Step H3, repeat until T is within the interval [1, n - 1]
- while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0)) {
+ // Step H3, repeat until T is within the interval [1, n - 1] and is suitable for ECDSA
+ while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0) || !checkSig(T)) {
k = crypto.createHmac('sha256', k)
.update(v)
.update(ZERO)
@@ -64,6 +65,9 @@ function deterministicGenerateK(curve, hash, d) {
v = crypto.createHmac('sha256', k).update(v).digest()
+ // Step H1/H2a, again, ignored as tlen === qlen (256 bit)
+ // Step H2b again
+ v = crypto.createHmac('sha256', k).update(v).digest()
T = BigInteger.fromBuffer(v)
}
@@ -71,18 +75,28 @@ function deterministicGenerateK(curve, hash, d) {
}
function sign(curve, hash, d) {
- var k = deterministicGenerateK(curve, hash, d)
+ var r, s
+ var e = BigInteger.fromBuffer(hash)
var n = curve.n
var G = curve.G
- var Q = G.multiply(k)
- var e = BigInteger.fromBuffer(hash)
- var r = Q.affineX.mod(n)
- assert.notEqual(r.signum(), 0, 'Invalid R value')
+ deterministicGenerateK(curve, hash, d, function(k) {
+ var Q = G.multiply(k)
+
+ if (curve.isInfinity(Q))
+ return false
+
+ r = Q.affineX.mod(n)
+ if (r.signum() === 0)
+ return false
+
+ s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
+ if (s.signum() === 0)
+ return false
- var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
- assert.notEqual(s.signum(), 0, 'Invalid S value')
+ return true
+ })
var N_OVER_TWO = n.shiftRight(1)
diff --git a/test/ecdsa.js b/test/ecdsa.js
index 58a00762b..20c6aa1df 100644
--- a/test/ecdsa.js
+++ b/test/ecdsa.js
@@ -15,12 +15,14 @@ var fixtures = require('./fixtures/ecdsa.json')
describe('ecdsa', function() {
describe('deterministicGenerateK', function() {
+ function checkSig() { return true }
+
fixtures.valid.forEach(function(f) {
it('for \"' + f.message + '\"', function() {
var d = BigInteger.fromHex(f.d)
var h1 = crypto.sha256(f.message)
- var k = ecdsa.deterministicGenerateK(curve, h1, d)
+ var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig)
assert.equal(k.toHex(), f.k)
})
})
@@ -35,7 +37,7 @@ describe('ecdsa', function() {
var d = new BigInteger('1')
var h1 = new Buffer(32)
- var k = ecdsa.deterministicGenerateK(curve, h1, d)
+ var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig)
assert.equal(k.toString(), '42')
}))
From 1e7f537f38efe8b430bff562184b5de94c68693c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 5 Jan 2015 11:15:07 +1100
Subject: [PATCH 222/291] tests: adds ecdsa test enforcing valid signature
callback
---
test/ecdsa.js | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/test/ecdsa.js b/test/ecdsa.js
index 20c6aa1df..c9378ac38 100644
--- a/test/ecdsa.js
+++ b/test/ecdsa.js
@@ -30,17 +30,36 @@ describe('ecdsa', function() {
it('loops until an appropriate k value is found', sinon.test(function() {
this.mock(BigInteger).expects('fromBuffer')
.exactly(3)
- .onCall(0).returns(new BigInteger('0'))
- .onCall(1).returns(curve.n)
- .onCall(2).returns(new BigInteger('42'))
+ .onCall(0).returns(new BigInteger('0')) // < 1
+ .onCall(1).returns(curve.n) // > n-1
+ .onCall(2).returns(new BigInteger('42')) // valid
var d = new BigInteger('1')
var h1 = new Buffer(32)
-
var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig)
assert.equal(k.toString(), '42')
}))
+
+ it('loops until a suitable signature is found', sinon.test(function() {
+ this.mock(BigInteger).expects('fromBuffer')
+ .exactly(4)
+ .onCall(0).returns(new BigInteger('0')) // < 1
+ .onCall(1).returns(curve.n) // > n-1
+ .onCall(2).returns(new BigInteger('42')) // valid, but 'bad' signature
+ .onCall(3).returns(new BigInteger('53')) // valid, good signature
+
+ var checkSig = this.mock()
+ checkSig.exactly(2)
+ checkSig.onCall(0).returns(false) // bad signature
+ checkSig.onCall(1).returns(true) // good signature
+
+ var d = new BigInteger('1')
+ var h1 = new Buffer(32)
+ var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig)
+
+ assert.equal(k.toString(), '53')
+ }))
})
describe('recoverPubKey', function() {
From 0e5c7b2a5a179d1a8fab092f6a401f108f374d23 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 5 Jan 2015 12:31:28 +1100
Subject: [PATCH 223/291] tests: add bip32JPs RFC6979 test vectors and tests
---
test/ecdsa.js | 27 ++++-
test/fixtures/ecdsa.json | 216 ++++++++++++++++++++++++++-------------
2 files changed, 168 insertions(+), 75 deletions(-)
diff --git a/test/ecdsa.js b/test/ecdsa.js
index c9378ac38..60ac6df3d 100644
--- a/test/ecdsa.js
+++ b/test/ecdsa.js
@@ -17,7 +17,7 @@ describe('ecdsa', function() {
describe('deterministicGenerateK', function() {
function checkSig() { return true }
- fixtures.valid.forEach(function(f) {
+ fixtures.valid.ecdsa.forEach(function(f) {
it('for \"' + f.message + '\"', function() {
var d = BigInteger.fromHex(f.d)
var h1 = crypto.sha256(f.message)
@@ -60,10 +60,29 @@ describe('ecdsa', function() {
assert.equal(k.toString(), '53')
}))
+
+ // TODO: this could be done better?
+ fixtures.valid.rfc6979.forEach(function(f) {
+ it('produces the expected k values for ' + f.message + ' if k wasn\'t suitable', sinon.test(function() {
+ var d = BigInteger.fromHex(f.d)
+ var h1 = crypto.sha256(f.message)
+
+ var i = 0
+ ecdsa.deterministicGenerateK(curve, h1, d, function(k) {
+ var expected = f['k' + i]
+
+ if (expected !== undefined) {
+ assert.equal(k.toHex(), expected)
+ }
+
+ return ++i > 15
+ })
+ }))
+ })
})
describe('recoverPubKey', function() {
- fixtures.valid.forEach(function(f) {
+ fixtures.valid.ecdsa.forEach(function(f) {
it('recovers the pubKey for ' + f.d, function() {
var d = BigInteger.fromHex(f.d)
var Q = curve.G.multiply(d)
@@ -115,7 +134,7 @@ describe('ecdsa', function() {
})
describe('sign', function() {
- fixtures.valid.forEach(function(f) {
+ fixtures.valid.ecdsa.forEach(function(f) {
it('produces a deterministic signature for \"' + f.message + '\"', function() {
var d = BigInteger.fromHex(f.d)
var hash = crypto.sha256(f.message)
@@ -137,7 +156,7 @@ describe('ecdsa', function() {
})
describe('verify/verifyRaw', function() {
- fixtures.valid.forEach(function(f) {
+ fixtures.valid.ecdsa.forEach(function(f) {
it('verifies a valid signature for \"' + f.message + '\"', function() {
var d = BigInteger.fromHex(f.d)
var H = crypto.sha256(f.message)
diff --git a/test/fixtures/ecdsa.json b/test/fixtures/ecdsa.json
index faad86415..57814c280 100644
--- a/test/fixtures/ecdsa.json
+++ b/test/fixtures/ecdsa.json
@@ -1,76 +1,150 @@
{
- "valid": [
- {
- "d": "01",
- "k": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5",
- "message": "Everything should be made as simple as possible, but not simpler.",
- "i": 0,
- "signature": {
- "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
- "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
- }
- },
- {
- "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
- "k": "9dc74cbfd383980fb4ae5d2680acddac9dac956dca65a28c80ac9c847c2374e4",
- "message": "Equations are more important to me, because politics is for the present, but an equation is something for eternity.",
- "i": 0,
- "signature": {
- "r": "38341707918488238920692284707283974715538935465589664377561695343399725051885",
- "s": "3180566392414476763164587487324397066658063772201694230600609996154610926757"
- }
- },
- {
- "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
- "k": "fd27071f01648ebbdd3e1cfbae48facc9fa97edc43bbbc9a7fdc28eae13296f5",
- "message": "Not only is the Universe stranger than we think, it is stranger than we can think.",
- "i": 0,
- "signature": {
- "r": "115464191557905790016094131873849783294273568009648050793030031933291767741904",
- "s": "50562520307781850052192542766631199590053690478900449960232079510155113443971"
- }
- },
- {
- "d": "0000000000000000000000000000000000000000000000000000000000000001",
- "k": "f0cd2ba5fc7c183de589f6416220a36775a146740798756d8d949f7166dcc87f",
- "message": "How wonderful that we have met with a paradox. Now we have some hope of making progress.",
- "i": 1,
- "signature": {
- "r": "87230998027579607140680851455601772643840468630989315269459846730712163783123",
- "s": "53231320085894623106179381504478252331065330583563809963303318469380290929875"
- }
- },
- {
- "d": "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64",
- "k": "6bb4a594ad57c1aa22dbe991a9d8501daf4688bf50a4892ef21bd7c711afda97",
- "message": "Computer science is no more about computers than astronomy is about telescopes.",
- "i": 0,
- "signature": {
- "r": "51348483531757779992459563033975330355971795607481991320287437101831125115997",
- "s": "6277080015686056199074771961940657638578000617958603212944619747099038735862"
- }
- },
- {
- "d": "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637",
- "k": "097b5c8ee22c3ea78a4d3635e0ff6fe85a1eb92ce317ded90b9e71aab2b861cb",
- "message": "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough",
- "i": 1,
- "signature": {
- "r": "113979859486826658566290715281614250298918272782414232881639314569529560769671",
- "s": "6517071009538626957379450615706485096874328019806177698938278220732027419959"
+ "valid": {
+ "ecdsa": [
+ {
+ "d": "01",
+ "k": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5",
+ "message": "Everything should be made as simple as possible, but not simpler.",
+ "i": 0,
+ "signature": {
+ "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
+ "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
+ }
+ },
+ {
+ "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "k": "9dc74cbfd383980fb4ae5d2680acddac9dac956dca65a28c80ac9c847c2374e4",
+ "message": "Equations are more important to me, because politics is for the present, but an equation is something for eternity.",
+ "i": 0,
+ "signature": {
+ "r": "38341707918488238920692284707283974715538935465589664377561695343399725051885",
+ "s": "3180566392414476763164587487324397066658063772201694230600609996154610926757"
+ }
+ },
+ {
+ "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "k": "fd27071f01648ebbdd3e1cfbae48facc9fa97edc43bbbc9a7fdc28eae13296f5",
+ "message": "Not only is the Universe stranger than we think, it is stranger than we can think.",
+ "i": 0,
+ "signature": {
+ "r": "115464191557905790016094131873849783294273568009648050793030031933291767741904",
+ "s": "50562520307781850052192542766631199590053690478900449960232079510155113443971"
+ }
+ },
+ {
+ "d": "0000000000000000000000000000000000000000000000000000000000000001",
+ "k": "f0cd2ba5fc7c183de589f6416220a36775a146740798756d8d949f7166dcc87f",
+ "message": "How wonderful that we have met with a paradox. Now we have some hope of making progress.",
+ "i": 1,
+ "signature": {
+ "r": "87230998027579607140680851455601772643840468630989315269459846730712163783123",
+ "s": "53231320085894623106179381504478252331065330583563809963303318469380290929875"
+ }
+ },
+ {
+ "d": "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64",
+ "k": "6bb4a594ad57c1aa22dbe991a9d8501daf4688bf50a4892ef21bd7c711afda97",
+ "message": "Computer science is no more about computers than astronomy is about telescopes.",
+ "i": 0,
+ "signature": {
+ "r": "51348483531757779992459563033975330355971795607481991320287437101831125115997",
+ "s": "6277080015686056199074771961940657638578000617958603212944619747099038735862"
+ }
+ },
+ {
+ "d": "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637",
+ "k": "097b5c8ee22c3ea78a4d3635e0ff6fe85a1eb92ce317ded90b9e71aab2b861cb",
+ "message": "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough",
+ "i": 1,
+ "signature": {
+ "r": "113979859486826658566290715281614250298918272782414232881639314569529560769671",
+ "s": "6517071009538626957379450615706485096874328019806177698938278220732027419959"
+ }
+ },
+ {
+ "d": "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3",
+ "k": "19355c36c8cbcdfb2382e23b194b79f8c97bf650040fc7728dfbf6b39a97c25b",
+ "message": "The question of whether computers can think is like the question of whether submarines can swim.",
+ "i": 1,
+ "signature": {
+ "r": "93122007060065279508564838030979550535085999589142852106617159184757394422777",
+ "s": "3078539468410661027472930027406594684630312677495124015420811882501887769839"
+ }
}
- },
- {
- "d": "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3",
- "k": "19355c36c8cbcdfb2382e23b194b79f8c97bf650040fc7728dfbf6b39a97c25b",
- "message": "The question of whether computers can think is like the question of whether submarines can swim.",
- "i": 1,
- "signature": {
- "r": "93122007060065279508564838030979550535085999589142852106617159184757394422777",
- "s": "3078539468410661027472930027406594684630312677495124015420811882501887769839"
+ ],
+ "rfc6979": [
+ {
+ "message": "test data",
+ "d": "fee0a1f7afebf9d2a5a80c0c98a31c709681cce195cbcd06342b517970c0be1e",
+ "k0": "fcce1de7a9bcd6b2d3defade6afa1913fb9229e3b7ddf4749b55c4848b2a196e",
+ "k1": "727fbcb59eb48b1d7d46f95a04991fc512eb9dbf9105628e3aec87428df28fd8",
+ "k15": "398f0e2c9f79728f7b3d84d447ac3a86d8b2083c8f234a0ffa9c4043d68bd258"
+ },
+ {
+ "message": "Everything should be made as simple as possible, but not simpler.",
+ "d": "0000000000000000000000000000000000000000000000000000000000000001",
+ "k0": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5",
+ "k1": "df55b6d1b5c48184622b0ead41a0e02bfa5ac3ebdb4c34701454e80aabf36f56",
+ "k15": "def007a9a3c2f7c769c75da9d47f2af84075af95cadd1407393dc1e26086ef87"
+ },
+ {
+ "message": "Satoshi Nakamoto",
+ "d": "0000000000000000000000000000000000000000000000000000000000000002",
+ "k0": "d3edc1b8224e953f6ee05c8bbf7ae228f461030e47caf97cde91430b4607405e",
+ "k1": "f86d8e43c09a6a83953f0ab6d0af59fb7446b4660119902e9967067596b58374",
+ "k15": "241d1f57d6cfd2f73b1ada7907b199951f95ef5ad362b13aed84009656e0254a"
+ },
+ {
+ "message": "Diffie Hellman",
+ "d": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
+ "k0": "c378a41cb17dce12340788dd3503635f54f894c306d52f6e9bc4b8f18d27afcc",
+ "k1": "90756c96fef41152ac9abe08819c4e95f16da2af472880192c69a2b7bac29114",
+ "k15": "7b3f53300ab0ccd0f698f4d67db87c44cf3e9e513d9df61137256652b2e94e7c"
+ },
+ {
+ "message": "Japan",
+ "d": "8080808080808080808080808080808080808080808080808080808080808080",
+ "k0": "f471e61b51d2d8db78f3dae19d973616f57cdc54caaa81c269394b8c34edcf59",
+ "k1": "6819d85b9730acc876fdf59e162bf309e9f63dd35550edf20869d23c2f3e6d17",
+ "k15": "d8e8bae3ee330a198d1f5e00ad7c5f9ed7c24c357c0a004322abca5d9cd17847"
+ },
+ {
+ "message": "Bitcoin",
+ "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "k0": "36c848ffb2cbecc5422c33a994955b807665317c1ce2a0f59c689321aaa631cc",
+ "k1": "4ed8de1ec952a4f5b3bd79d1ff96446bcd45cabb00fc6ca127183e14671bcb85",
+ "k15": "56b6f47babc1662c011d3b1f93aa51a6e9b5f6512e9f2e16821a238d450a31f8"
+ },
+ {
+ "message": "i2FLPP8WEus5WPjpoHwheXOMSobUJVaZM1JPMQZq",
+ "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "k0": "6e9b434fcc6bbb081a0463c094356b47d62d7efae7da9c518ed7bac23f4e2ed6",
+ "k1": "ae5323ae338d6117ce8520a43b92eacd2ea1312ae514d53d8e34010154c593bb",
+ "k15": "3eaa1b61d1b8ab2f1ca71219c399f2b8b3defa624719f1e96fe3957628c2c4ea"
+ },
+ {
+ "message": "lEE55EJNP7aLrMtjkeJKKux4Yg0E8E1SAJnWTCEh",
+ "d": "3881e5286abc580bb6139fe8e83d7c8271c6fe5e5c2d640c1f0ed0e1ee37edc9",
+ "k0": "5b606665a16da29cc1c5411d744ab554640479dd8abd3c04ff23bd6b302e7034",
+ "k1": "f8b25263152c042807c992eacd2ac2cc5790d1e9957c394f77ea368e3d9923bd",
+ "k15": "ea624578f7e7964ac1d84adb5b5087dd14f0ee78b49072aa19051cc15dab6f33"
+ },
+ {
+ "message": "2SaVPvhxkAPrayIVKcsoQO5DKA8Uv5X/esZFlf+y",
+ "d": "7259dff07922de7f9c4c5720d68c9745e230b32508c497dd24cb95ef18856631",
+ "k0": "3ab6c19ab5d3aea6aa0c6da37516b1d6e28e3985019b3adb388714e8f536686b",
+ "k1": "19af21b05004b0ce9cdca82458a371a9d2cf0dc35a813108c557b551c08eb52e",
+ "k15": "117a32665fca1b7137a91c4739ac5719fec0cf2e146f40f8e7c21b45a07ebc6a"
+ },
+ {
+ "message": "00A0OwO2THi7j5Z/jp0FmN6nn7N/DQd6eBnCS+/b",
+ "d": "0d6ea45d62b334777d6995052965c795a4f8506044b4fd7dc59c15656a28f7aa",
+ "k0": "79487de0c8799158294d94c0eb92ee4b567e4dc7ca18addc86e49d31ce1d2db6",
+ "k1": "9561d2401164a48a8f600882753b3105ebdd35e2358f4f808c4f549c91490009",
+ "k15": "b0d273634129ff4dbdf0df317d4062a1dbc58818f88878ffdb4ec511c77976c0"
}
- }
- ],
+ ]
+ },
"invalid": {
"recoverPubKey": [
{
@@ -219,4 +293,4 @@
}
]
}
-}
\ No newline at end of file
+}
From a492969ab265aa7aa2b43533650369e293b282ce Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 5 Jan 2015 12:42:09 +1100
Subject: [PATCH 224/291] tests: ecdsa test cleanup
---
test/ecdsa.js | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/test/ecdsa.js b/test/ecdsa.js
index 60ac6df3d..b0d13f2d1 100644
--- a/test/ecdsa.js
+++ b/test/ecdsa.js
@@ -61,23 +61,22 @@ describe('ecdsa', function() {
assert.equal(k.toString(), '53')
}))
- // TODO: this could be done better?
fixtures.valid.rfc6979.forEach(function(f) {
- it('produces the expected k values for ' + f.message + ' if k wasn\'t suitable', sinon.test(function() {
+ it('produces the expected k values for ' + f.message + ' if k wasn\'t suitable', function() {
var d = BigInteger.fromHex(f.d)
var h1 = crypto.sha256(f.message)
- var i = 0
+ var results = []
ecdsa.deterministicGenerateK(curve, h1, d, function(k) {
- var expected = f['k' + i]
+ results.push(k)
- if (expected !== undefined) {
- assert.equal(k.toHex(), expected)
- }
-
- return ++i > 15
+ return results.length === 16
})
- }))
+
+ assert.equal(results[0].toHex(), f.k0)
+ assert.equal(results[1].toHex(), f.k1)
+ assert.equal(results[15].toHex(), f.k15)
+ })
})
})
From 6938c8f8cc8f2689a83ac49ddf92f6b335f31aeb Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 6 Jan 2015 15:12:34 +1100
Subject: [PATCH 225/291] ecdsa: add default checkSig, to be removed in 2.0.0
---
src/ecdsa.js | 28 +++++++++++++++++++++++++++-
test/ecdsa.js | 11 +++++++++++
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/src/ecdsa.js b/src/ecdsa.js
index d330add33..e337feb39 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -12,7 +12,33 @@ var ONE = new Buffer([1])
function deterministicGenerateK(curve, hash, d, checkSig) {
typeForce('Buffer', hash)
typeForce('BigInteger', d)
- typeForce('Function', checkSig)
+// typeForce('Function', checkSig)
+
+ // FIXME: remove in 2.0.0
+ if (typeof checkSig !== 'function') {
+ console.warn('deterministicGenerateK requires a checkSig callback in 2.0.0, see #337 for more information')
+
+ checkSig = function(k) {
+ var G = curve.G
+ var n = curve.n
+ var e = BigInteger.fromBuffer(hash)
+
+ var Q = G.multiply(k)
+
+ if (curve.isInfinity(Q))
+ return false
+
+ var r = Q.affineX.mod(n)
+ if (r.signum() === 0)
+ return false
+
+ var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
+ if (s.signum() === 0)
+ return false
+
+ return true
+ }
+ }
// sanity check
assert.equal(hash.length, 32, 'Hash must be 256 bit')
diff --git a/test/ecdsa.js b/test/ecdsa.js
index b0d13f2d1..b95397775 100644
--- a/test/ecdsa.js
+++ b/test/ecdsa.js
@@ -27,6 +27,17 @@ describe('ecdsa', function() {
})
})
+ // FIXME: remove in 2.0.0
+ fixtures.valid.ecdsa.forEach(function(f) {
+ it('(deprecated) for \"' + f.message + '\"', function() {
+ var d = BigInteger.fromHex(f.d)
+ var h1 = crypto.sha256(f.message)
+
+ var k = ecdsa.deterministicGenerateK(curve, h1, d) // default checkSig
+ assert.equal(k.toHex(), f.k)
+ })
+ })
+
it('loops until an appropriate k value is found', sinon.test(function() {
this.mock(BigInteger).expects('fromBuffer')
.exactly(3)
From 59143a9c85f852bd1591309f1b27ea106fdce2b2 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 9 Jan 2015 09:10:16 +1100
Subject: [PATCH 226/291] ecdsa: clarify why typeForce call is disabled until
2.0.0
---
src/ecdsa.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/ecdsa.js b/src/ecdsa.js
index e337feb39..63c5ceffc 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -12,9 +12,10 @@ var ONE = new Buffer([1])
function deterministicGenerateK(curve, hash, d, checkSig) {
typeForce('Buffer', hash)
typeForce('BigInteger', d)
+
+ // FIXME: remove/uncomment for 2.0.0
// typeForce('Function', checkSig)
- // FIXME: remove in 2.0.0
if (typeof checkSig !== 'function') {
console.warn('deterministicGenerateK requires a checkSig callback in 2.0.0, see #337 for more information')
From 2223b9922b56fa3c1ca53a6f1fdbe38837777e94 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 9 Jan 2015 14:18:06 +1100
Subject: [PATCH 227/291] package: latest devDependencies
---
package.json | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/package.json b/package.json
index d91156442..1eb96dc61 100644
--- a/package.json
+++ b/package.json
@@ -56,15 +56,15 @@
},
"devDependencies": {
"async": "^0.9.0",
- "browserify": "^5.12.0",
- "bs58": "^2.0.0",
- "cb-helloblock": "^0.4.7",
+ "browserify": "^8.0.3",
+ "bs58": "^2.0.1",
+ "cb-helloblock": "^0.4.10",
"coveralls": "^2.11.2",
- "istanbul": "^0.3.2",
- "jshint": "^2.5.6",
- "mocha": "^1.21.4",
+ "istanbul": "^0.3.5",
+ "jshint": "^2.5.11",
+ "mocha": "^2.1.0",
"mocha-lcov-reporter": "0.0.1",
- "sinon": "^1.10.3",
- "uglify-js": "^2.4.15"
+ "sinon": "^1.12.2",
+ "uglify-js": "^2.4.16"
}
}
From c264941d74c26c6bfb6cac0151f0193680e58e5d Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 9 Jan 2015 14:19:32 +1100
Subject: [PATCH 228/291] package: bigi 1.4.0 and crypto-browserify 3.9.0
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 1eb96dc61..3a22db0ef 100644
--- a/package.json
+++ b/package.json
@@ -48,9 +48,9 @@
"crypto": "crypto-browserify"
},
"dependencies": {
- "bigi": "^1.1.0",
+ "bigi": "^1.4.0",
"bs58check": "1.0.3",
- "crypto-browserify": "^3.2.6",
+ "crypto-browserify": "^3.9.0",
"ecurve": "1.0.0",
"typeforce": "0.1.0"
},
From 62ebacc6d526309ce4c090076f6d0bddef0ab541 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 9 Jan 2015 14:25:48 +1100
Subject: [PATCH 229/291] 1.4.3
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 3a22db0ef..78def2b5f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.4.2",
+ "version": "1.4.3",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 912e94479c91171440b950b8e184993799b10fc7 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 13 Jan 2015 22:24:19 +1100
Subject: [PATCH 230/291] adds .npmignore
---
.npmignore | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 .npmignore
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 000000000..74e448642
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,4 @@
+.gitignore
+.travis.yml
+jshint.json
+test/
From a529b3fa0bd315f4b0254c5afa2a82c56e6d3a4f Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 23 Jan 2015 16:35:09 +1100
Subject: [PATCH 231/291] TxBuilder: copy version/locktime in fromTransaction
---
src/transaction_builder.js | 4 ++++
test/fixtures/transaction_builder.json | 23 +++++++++++++++++++++++
test/transaction_builder.js | 4 ++++
3 files changed, 31 insertions(+)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 5e0a35f83..71a46ecbc 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -19,6 +19,10 @@ function TransactionBuilder() {
TransactionBuilder.fromTransaction = function(transaction) {
var txb = new TransactionBuilder()
+ // Copy other transaction fields
+ txb.tx.version = transaction.version
+ txb.tx.locktime = transaction.locktime
+
// Extract/add inputs
transaction.ins.forEach(function(txIn) {
txb.addInput(txIn.hash, txIn.index, txIn.sequence)
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index a44078b26..ad09d7d56 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -83,6 +83,29 @@
"value": 10000
}
]
+ },
+ {
+ "description": "Transaction w/ non-default input sequence numbers, version and locktime",
+ "txid": "4503038f144af7b0c11fad6e09cf8deb4ef04645d203e1c90b86f25b7b243fe8",
+ "txhex": "0400000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000006b483045022100c5bcd521df085481e2dcc2c0f14173043f0fa2001dca582b45186a95d248d28002204c571eabcec1410bd53a7da29b9da6b4c858c3fdabbfdb110a030c507ff5bc0501210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b9c220000110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac09990400",
+ "version": 4,
+ "locktime": 301321,
+ "inputs": [
+ {
+ "index": 2,
+ "prevTx": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "sequence": 2147001,
+ "privKeys": [
+ "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+ "value": 10000
+ }
+ ]
}
]
},
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 63ad8beee..8e2b528db 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -196,6 +196,10 @@ describe('TransactionBuilder', function() {
})
})
+ // FIXME: add support for locktime/version in TransactionBuilder API
+ if (f.version !== undefined) txb.tx.version = f.version
+ if (f.locktime !== undefined) txb.tx.locktime = f.locktime
+
var tx = txb.build()
assert.equal(tx.getId(), f.txid)
From cbf8c6f9327d1fb9871f961054214d7ca71ce0e5 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 23 Jan 2015 16:37:10 +1100
Subject: [PATCH 232/291] tests: format JSON consistently
---
test/fixtures/transaction_builder.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index ad09d7d56..5b0bb325e 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -194,11 +194,11 @@
"fromTransaction": [
{
"exception": "coinbase inputs not supported",
- "hex":"01000000010000000000000000000000000000000000000000000000000000000000000000000000006b483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+ "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000000000006b483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
},
{
"exception": "nonstandard inputs not supported",
- "hex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000023aa206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000087ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+ "hex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000023aa206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000087ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
}
]
}
From 64678e71e0969b168390e2a57f4e5f1f0e859b63 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 27 Jan 2015 13:41:09 +1100
Subject: [PATCH 233/291] 1.4.4
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 78def2b5f..656b9df14 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "1.4.3",
+ "version": "1.4.4",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [
From 5e1cd6e995f2945263da6c6fec6b1f29c536bbed Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 27 Jan 2015 17:26:34 +1100
Subject: [PATCH 234/291] integration: avoid looking up all address
transactions each time
---
test/integration/advanced.js | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/test/integration/advanced.js b/test/integration/advanced.js
index b4effbb32..dd3b8e254 100644
--- a/test/integration/advanced.js
+++ b/test/integration/advanced.js
@@ -31,30 +31,27 @@ describe('bitcoinjs-lib (advanced)', function() {
blockchain.addresses.unspents(address, function(err, unspents) {
if (err) return done(err)
- // filter small unspents
- unspents = unspents.filter(function(unspent) { return unspent.value > 1e4 })
-
- // use the oldest unspent
- var unspent = unspents.pop()
-
var tx = new bitcoin.TransactionBuilder()
-
var data = new Buffer('cafedeadbeef', 'hex')
var dataScript = bitcoin.scripts.nullDataOutput(data)
+ var unspent = unspents.pop()
+
tx.addInput(unspent.txId, unspent.vout)
tx.addOutput(dataScript, 1000)
tx.sign(0, key)
- blockchain.transactions.propagate(tx.build().toHex(), function(err) {
+ var txBuilt = tx.build()
+
+ blockchain.transactions.propagate(txBuilt.toHex(), function(err) {
if (err) return done(err)
// check that the message was propagated
- blockchain.addresses.transactions(address, function(err, transactions) {
+ blockchain.transactions.get(txBuilt.getId(), function(err, transaction) {
if (err) return done(err)
- var transaction = bitcoin.Transaction.fromHex(transactions[0].txHex)
- var dataScript2 = transaction.outs[0].script
+ var actual = bitcoin.Transaction.fromHex(transaction.txHex)
+ var dataScript2 = actual.outs[0].script
var data2 = dataScript2.chunks[1]
assert.deepEqual(dataScript, dataScript2)
From 234ae84b86b646b874887e1aa447c611c671e71c Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 27 Jan 2015 17:32:20 +1100
Subject: [PATCH 235/291] integration: use 'bitcoinjs-lib' as OP_RETURN
constant
---
test/integration/advanced.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/integration/advanced.js b/test/integration/advanced.js
index dd3b8e254..482d316f8 100644
--- a/test/integration/advanced.js
+++ b/test/integration/advanced.js
@@ -32,7 +32,7 @@ describe('bitcoinjs-lib (advanced)', function() {
if (err) return done(err)
var tx = new bitcoin.TransactionBuilder()
- var data = new Buffer('cafedeadbeef', 'hex')
+ var data = new Buffer('bitcoinjs-lib')
var dataScript = bitcoin.scripts.nullDataOutput(data)
var unspent = unspents.pop()
From 51b23c658e9806488b75072ea63179758123d535 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 2 Feb 2015 19:04:16 +1100
Subject: [PATCH 236/291] package: remove crypto-browserify specific version
---
package.json | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/package.json b/package.json
index 656b9df14..723720761 100644
--- a/package.json
+++ b/package.json
@@ -44,19 +44,15 @@
"type": "git",
"url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
},
- "browser": {
- "crypto": "crypto-browserify"
- },
"dependencies": {
"bigi": "^1.4.0",
- "bs58check": "1.0.3",
- "crypto-browserify": "^3.9.0",
- "ecurve": "1.0.0",
- "typeforce": "0.1.0"
+ "bs58check": "^1.0.4",
+ "ecurve": "^1.0.0",
+ "typeforce": "^0.1.0"
},
"devDependencies": {
"async": "^0.9.0",
- "browserify": "^8.0.3",
+ "browserify": "^8.1.0",
"bs58": "^2.0.1",
"cb-helloblock": "^0.4.10",
"coveralls": "^2.11.2",
From c13f1df9bf5ae63539a0fe9ea2094ec504b8d220 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 13 Oct 2014 12:52:32 +1100
Subject: [PATCH 237/291] doc: no section headers
---
src/address.js | 2 --
src/ecsignature.js | 2 --
src/script.js | 4 ----
3 files changed, 8 deletions(-)
diff --git a/src/address.js b/src/address.js
index be2b239c9..e87351598 100644
--- a/src/address.js
+++ b/src/address.js
@@ -23,7 +23,6 @@ function Address(hash, version) {
this.version = version
}
-// Import functions
Address.fromBase58Check = function(string) {
var payload = base58check.decode(string)
var version = payload.readUInt8(0)
@@ -41,7 +40,6 @@ Address.fromOutputScript = function(script, network) {
assert(false, script.toASM() + ' has no matching Address')
}
-// Export functions
Address.prototype.toBase58Check = function () {
var payload = new Buffer(21)
payload.writeUInt8(this.version, 0)
diff --git a/src/ecsignature.js b/src/ecsignature.js
index 073d7f125..1e25a99ab 100644
--- a/src/ecsignature.js
+++ b/src/ecsignature.js
@@ -11,7 +11,6 @@ function ECSignature(r, s) {
this.s = s
}
-// Import operations
ECSignature.parseCompact = function(buffer) {
assert.equal(buffer.length, 65, 'Invalid signature length')
var i = buffer.readUInt8(0) - 27
@@ -82,7 +81,6 @@ ECSignature.parseScriptSignature = function(buffer) {
}
}
-// Export operations
ECSignature.prototype.toCompact = function(i, compressed) {
if (compressed) i += 4
i += 27
diff --git a/src/script.js b/src/script.js
index 2283495c9..e6c6aaad3 100644
--- a/src/script.js
+++ b/src/script.js
@@ -12,7 +12,6 @@ function Script(buffer, chunks) {
this.chunks = chunks
}
-// Import operations
Script.fromASM = function(asm) {
var strChunks = asm.split(' ')
@@ -90,10 +89,8 @@ Script.fromHex = function(hex) {
return Script.fromBuffer(new Buffer(hex, 'hex'))
}
-// Constants
Script.EMPTY = Script.fromChunks([])
-// Operations
Script.prototype.getHash = function() {
return crypto.hash160(this.buffer)
}
@@ -105,7 +102,6 @@ Script.prototype.without = function(needle) {
}))
}
-// Export operations
var reverseOps = []
for (var op in opcodes) {
var code = opcodes[op]
From c9db90dc4d925110b9821daa6aab77a3721539fd Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 28 Nov 2014 11:35:11 +1100
Subject: [PATCH 238/291] ECSignature: enforce valid hashType in
toScriptSignature
---
src/ecsignature.js | 7 +++++--
test/ecsignature.js | 17 +++++++++++++++--
test/fixtures/ecsignature.json | 20 ++++++++++++++++++++
3 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/src/ecsignature.js b/src/ecsignature.js
index 073d7f125..63f1426e7 100644
--- a/src/ecsignature.js
+++ b/src/ecsignature.js
@@ -69,12 +69,12 @@ ECSignature.fromDER = function(buffer) {
return new ECSignature(r, s)
}
-// FIXME: 0x00, 0x04, 0x80 are SIGHASH_* boundary constants, importing Transaction causes a circular dependency
+// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
ECSignature.parseScriptSignature = function(buffer) {
var hashType = buffer.readUInt8(buffer.length - 1)
var hashTypeMod = hashType & ~0x80
- assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType')
+ assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType ' + hashType)
return {
signature: ECSignature.fromDER(buffer.slice(0, -1)),
@@ -117,6 +117,9 @@ ECSignature.prototype.toDER = function() {
}
ECSignature.prototype.toScriptSignature = function(hashType) {
+ var hashTypeMod = hashType & ~0x80
+ assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType ' + hashType)
+
var hashTypeBuffer = new Buffer(1)
hashTypeBuffer.writeUInt8(hashType, 0)
diff --git a/test/ecsignature.js b/test/ecsignature.js
index dac7fb2e4..1866ac24e 100644
--- a/test/ecsignature.js
+++ b/test/ecsignature.js
@@ -92,6 +92,19 @@ describe('ECSignature', function() {
assert.equal(scriptSignature.toString('hex'), f.scriptSignature.hex)
})
})
+
+ fixtures.invalid.scriptSignature.forEach(function(f) {
+ it('throws ' + f.exception, function() {
+ var signature = new ECSignature(
+ new BigInteger(f.signature.r),
+ new BigInteger(f.signature.s)
+ )
+
+ assert.throws(function() {
+ signature.toScriptSignature(f.hashType)
+ }, new RegExp(f.exception))
+ })
+ })
})
describe('parseScriptSignature', function() {
@@ -106,9 +119,9 @@ describe('ECSignature', function() {
})
})
- fixtures.invalid.DER.forEach(function(f) {
+ fixtures.invalid.scriptSignature.forEach(function(f) {
it('throws on ' + f.hex, function() {
- var buffer = new Buffer(f.hex + '01', 'hex')
+ var buffer = new Buffer(f.hex, 'hex')
assert.throws(function() {
ECSignature.parseScriptSignature(buffer)
diff --git a/test/fixtures/ecsignature.json b/test/fixtures/ecsignature.json
index 3a18a8117..2c72182cd 100644
--- a/test/fixtures/ecsignature.json
+++ b/test/fixtures/ecsignature.json
@@ -173,6 +173,26 @@
"exception": "S value excessively padded",
"hex": "300c020400ffffff02040000ffff"
}
+ ],
+ "scriptSignature": [
+ {
+ "exception": "Invalid hashType 7",
+ "hashType": 7,
+ "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226207",
+ "signature": {
+ "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
+ "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
+ }
+ },
+ {
+ "exception": "Invalid hashType 140",
+ "hashType": 140,
+ "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa543422628c",
+ "signature": {
+ "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
+ "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
+ }
+ }
]
}
}
From 7ee8a85eb0c6e33c1eaf1330d7136de3e0c53798 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 5 Jan 2015 12:54:03 +1100
Subject: [PATCH 239/291] README: improve browserify instructions
---
README.md | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index e941e4f87..be9c4537c 100644
--- a/README.md
+++ b/README.md
@@ -51,16 +51,33 @@ From the repo:
### Browser
-From the repository: Compile `bitcoinjs-min.js` with the following command:
+If you're familiar with how to use browserify, ignore this and proceed normally.
+These steps are advisory only and allow you to use the API to its full extent.
- $ npm run-script compile
+[Browserify](https://github.com/substack/node-browserify) is assumed to be installed for these steps.
-From NPM:
- $ npm -g install bitcoinjs-lib browserify uglify-js
- $ browserify -r bitcoinjs-lib -s bitcoin | uglifyjs > bitcoinjs.min.js
+From your repository, create a `bitcoin.js` file
-After loading this file in your browser, you will be able to use the global `bitcoin` object.
+``` javascript
+var bitcoin = {
+ base58: require('bs58'),
+ ecurve: require('ecurve'),
+ BigInteger: require('bigi'),
+ Buffer: require('buffer')
+}
+
+var bitcoinjs = require('bitcoinjs-lib')
+for (var a in bitcoinjs) bitcoin[a] = bitcoinjs[a]
+
+module.exports = bitcoin
+```
+
+Then, using browserify, compile `bitcoin.js` for use in the browser:
+
+ $ browserify bitcoin.js -s bitcoin > dist/bitcoin.js
+
+You will then be able to load `dist/bitcoin.js` into your browser, with each of the dependencies above accessible from the global `bitcoin` object.
## Examples
From 2047567703e04d49611fef864834b653e11e3797 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 5 Jan 2015 13:00:19 +1100
Subject: [PATCH 240/291] README: add note about browserify version
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index be9c4537c..3c53f5081 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,6 @@ These steps are advisory only and allow you to use the API to its full extent.
[Browserify](https://github.com/substack/node-browserify) is assumed to be installed for these steps.
-
From your repository, create a `bitcoin.js` file
``` javascript
@@ -79,6 +78,8 @@ Then, using browserify, compile `bitcoin.js` for use in the browser:
You will then be able to load `dist/bitcoin.js` into your browser, with each of the dependencies above accessible from the global `bitcoin` object.
+**NOTE**: See the package.json for the currently supported version of browserify used by this repository.
+
## Examples
From c11f50542ee86e2f5805fbf72f0ee3ba6e3a237b Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 5 Jan 2015 13:02:58 +1100
Subject: [PATCH 241/291] README: don't use a bitcoin namespace for other deps
---
README.md | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index 3c53f5081..7eb776ba3 100644
--- a/README.md
+++ b/README.md
@@ -56,29 +56,27 @@ These steps are advisory only and allow you to use the API to its full extent.
[Browserify](https://github.com/substack/node-browserify) is assumed to be installed for these steps.
-From your repository, create a `bitcoin.js` file
+From your repository, create a `foobar.js` file
``` javascript
-var bitcoin = {
+var foobar = {
base58: require('bs58'),
+ bitcoin: require('bitcoinjs-lib'),
ecurve: require('ecurve'),
BigInteger: require('bigi'),
Buffer: require('buffer')
}
-var bitcoinjs = require('bitcoinjs-lib')
-for (var a in bitcoinjs) bitcoin[a] = bitcoinjs[a]
-
-module.exports = bitcoin
+module.exports = foobar
```
-Then, using browserify, compile `bitcoin.js` for use in the browser:
+Then, using browserify, compile `foobar.js` for use in the browser:
- $ browserify bitcoin.js -s bitcoin > dist/bitcoin.js
+ $ browserify foobar.js -s foobar > dist/foobar.js
-You will then be able to load `dist/bitcoin.js` into your browser, with each of the dependencies above accessible from the global `bitcoin` object.
+You will then be able to load `dist/foobar.js` into your browser, with each of the dependencies above accessible from the global `foobar` object.
-**NOTE**: See the package.json for the currently supported version of browserify used by this repository.
+**NOTE**: See our package.json for the currently supported version of browserify used by this repository.
## Examples
From 75ca385e42e4f0fa5eabf060d239ecf5512a7ffd Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 8 Feb 2015 11:59:59 +1100
Subject: [PATCH 242/291] README: no need to provide 'from the repo' require
Alternatively, they could also just do the standard `require('./')` if
they really wanted to do this.
---
README.md | 4 ----
1 file changed, 4 deletions(-)
diff --git a/README.md b/README.md
index 7eb776ba3..21ae379e7 100644
--- a/README.md
+++ b/README.md
@@ -44,10 +44,6 @@ If you are looking for the original, it is tagged as `0.1.3`. Unless you need it
var bitcoin = require('bitcoinjs-lib')
-From the repo:
-
- var bitcoin = require('./src/index.js')
-
### Browser
From 642315eabccacd34a71fa21ecf5ec48d59ec7693 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Sun, 8 Feb 2015 16:11:28 +1100
Subject: [PATCH 243/291] README: remove dist/ and clarify installation of
other packages
---
README.md | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 21ae379e7..c957a58d3 100644
--- a/README.md
+++ b/README.md
@@ -66,11 +66,14 @@ var foobar = {
module.exports = foobar
```
-Then, using browserify, compile `foobar.js` for use in the browser:
+Each of these included packages are seperate to `bitcoinjs-lib`, and must be installed separately.
+They are however used in the bitcoinjs-lib public API.
- $ browserify foobar.js -s foobar > dist/foobar.js
+Using browserify, compile `foobar.js` for use in the browser:
-You will then be able to load `dist/foobar.js` into your browser, with each of the dependencies above accessible from the global `foobar` object.
+ $ browserify foobar.js -s foobar > foobar.js
+
+You will then be able to load `foobar.js` into your browser, with each of the dependencies above accessible from the global `foobar` object.
**NOTE**: See our package.json for the currently supported version of browserify used by this repository.
From fa96764dadf1af7569ab1302c7316e58c414f062 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 13 Jan 2015 22:29:16 +1100
Subject: [PATCH 244/291] package: remove uglify-js
---
.gitignore | 4 ++--
package.json | 5 ++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/.gitignore b/.gitignore
index adcb09ced..0abc934bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-node_modules
-bitcoinjs-min.js
+bitcoin.js
coverage
+node_modules
diff --git a/package.json b/package.json
index 723720761..4791729f6 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
}
],
"scripts": {
- "compile": "browserify ./src/index.js -s bitcoin | uglifyjs > bitcoinjs-min.js",
+ "compile": "browserify ./src/index.js -s bitcoin > bitcoin.js",
"coverage": "istanbul cover _mocha -- test/*.js",
"coveralls": "npm run-script coverage && coveralls < coverage/lcov.info",
"integration": "mocha --reporter list test/integration/*.js",
@@ -60,7 +60,6 @@
"jshint": "^2.5.11",
"mocha": "^2.1.0",
"mocha-lcov-reporter": "0.0.1",
- "sinon": "^1.12.2",
- "uglify-js": "^2.4.16"
+ "sinon": "^1.12.2"
}
}
From c35d4b46c5d698bded428992139a7016353c0612 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 11 Feb 2015 14:01:20 +1100
Subject: [PATCH 245/291] scripts: add allowIncomplete for multisig scripts
---
src/scripts.js | 39 ++++++++++++++++++--------
src/transaction_builder.js | 18 ++++++------
test/fixtures/scripts.json | 57 ++++++++++++++++++++++++++++++++++++++
test/scripts.js | 27 ++++++++++++++++--
4 files changed, 118 insertions(+), 23 deletions(-)
diff --git a/src/scripts.js b/src/scripts.js
index 606e14b7e..e58ce999e 100644
--- a/src/scripts.js
+++ b/src/scripts.js
@@ -1,6 +1,6 @@
var assert = require('assert')
-var typeForce = require('typeforce')
var ops = require('./opcodes')
+var typeForce = require('typeforce')
var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')
@@ -63,7 +63,7 @@ function isPubKeyOutput(script) {
script.chunks[1] === ops.OP_CHECKSIG
}
-function isScriptHashInput(script) {
+function isScriptHashInput(script, allowIncomplete) {
if (script.chunks.length < 2) return false
var lastChunk = script.chunks[script.chunks.length - 1]
@@ -72,7 +72,7 @@ function isScriptHashInput(script) {
var scriptSig = Script.fromChunks(script.chunks.slice(0, -1))
var scriptPubKey = Script.fromBuffer(lastChunk)
- return classifyInput(scriptSig) === classifyOutput(scriptPubKey)
+ return classifyInput(scriptSig, allowIncomplete) === classifyOutput(scriptPubKey)
}
function isScriptHashOutput(script) {
@@ -83,9 +83,19 @@ function isScriptHashOutput(script) {
script.chunks[2] === ops.OP_EQUAL
}
-function isMultisigInput(script) {
- return script.chunks[0] === ops.OP_0 &&
- script.chunks.slice(1).every(isCanonicalSignature)
+// allowIncomplete is to account for combining signatures
+// See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197
+function isMultisigInput(script, allowIncomplete) {
+ if (script.chunks.length < 2) return false
+ if (script.chunks[0] !== ops.OP_0) return false
+
+ if (allowIncomplete) {
+ return script.chunks.slice(1).every(function(chunk) {
+ return chunk === ops.OP_0 || isCanonicalSignature(chunk)
+ })
+ }
+
+ return script.chunks.slice(1).every(isCanonicalSignature)
}
function isMultisigOutput(script) {
@@ -134,15 +144,15 @@ function classifyOutput(script) {
return 'nonstandard'
}
-function classifyInput(script) {
+function classifyInput(script, allowIncomplete) {
typeForce('Script', script)
if (isPubKeyHashInput(script)) {
return 'pubkeyhash'
- } else if (isScriptHashInput(script)) {
- return 'scripthash'
- } else if (isMultisigInput(script)) {
+ } else if (isMultisigInput(script, allowIncomplete)) {
return 'multisig'
+ } else if (isScriptHashInput(script, allowIncomplete)) {
+ return 'scripthash'
} else if (isPubKeyInput(script)) {
return 'pubkey'
}
@@ -234,8 +244,13 @@ function multisigInput(signatures, scriptPubKey) {
var m = mOp - (ops.OP_1 - 1)
var n = nOp - (ops.OP_1 - 1)
- assert(signatures.length >= m, 'Not enough signatures provided')
- assert(signatures.length <= n, 'Too many signatures provided')
+ var count = 0
+ signatures.forEach(function(signature) {
+ count += (signature !== ops.OP_0)
+ })
+
+ assert(count >= m, 'Not enough signatures provided')
+ assert(count <= n, 'Too many signatures provided')
}
return Script.fromChunks([].concat(ops.OP_0, signatures))
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 71a46ecbc..2cf785c65 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -1,4 +1,5 @@
var assert = require('assert')
+var ops = require('./opcodes')
var scripts = require('./scripts')
var ECPubKey = require('./ecpubkey')
@@ -44,23 +45,23 @@ TransactionBuilder.fromTransaction = function(transaction) {
var redeemScript
var scriptSig = txIn.script
- var scriptType = scripts.classifyInput(scriptSig)
+ var scriptType = scripts.classifyInput(scriptSig, true)
// Re-classify if P2SH
if (scriptType === 'scripthash') {
redeemScript = Script.fromBuffer(scriptSig.chunks.slice(-1)[0])
scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1))
- scriptType = scripts.classifyInput(scriptSig)
+ scriptType = scripts.classifyInput(scriptSig, true)
assert.equal(scripts.classifyOutput(redeemScript), scriptType, 'Non-matching scriptSig and scriptPubKey in input')
}
// Extract hashType, pubKeys and signatures
- var hashType, pubKeys, signatures
+ var hashType, parsed, pubKeys, signatures
switch (scriptType) {
case 'pubkeyhash':
- var parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
+ parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
var pubKey = ECPubKey.fromBuffer(scriptSig.chunks[1])
hashType = parsed.hashType
@@ -70,10 +71,9 @@ TransactionBuilder.fromTransaction = function(transaction) {
break
case 'multisig':
- var scriptSigs = scriptSig.chunks.slice(1) // ignore OP_0
- var parsed = scriptSigs.map(function(scriptSig) {
- return ECSignature.parseScriptSignature(scriptSig)
- })
+ parsed = scriptSig.chunks.slice(1).filter(function(chunk) {
+ return chunk !== ops.OP_0
+ }).map(ECSignature.parseScriptSignature)
hashType = parsed[0].hashType
pubKeys = []
@@ -82,7 +82,7 @@ TransactionBuilder.fromTransaction = function(transaction) {
break
case 'pubkey':
- var parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
+ parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
hashType = parsed.hashType
pubKeys = []
diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json
index 6ae7863cd..442c4a9c4 100644
--- a/test/fixtures/scripts.json
+++ b/test/fixtures/scripts.json
@@ -53,6 +53,51 @@
"type": "nulldata",
"data": "deadffffffffffffffffffffffffffffffffbeef",
"scriptPubKey": "OP_RETURN deadffffffffffffffffffffffffffffffffbeef"
+ },
+ {
+ "type": "nonstandard",
+ "typeIncomplete": "multisig",
+ "pubKeys": [
+ "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
+ "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34"
+ ],
+ "signatures": [
+ null,
+ "3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901",
+ "3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
+ ],
+ "scriptSig": "OP_0 OP_0 3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901 3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
+ },
+ {
+ "type": "nonstandard",
+ "typeIncomplete": "multisig",
+ "pubKeys": [
+ "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
+ "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34"
+ ],
+ "signatures": [
+ null,
+ null,
+ null
+ ],
+ "scriptSig": "OP_0 OP_0 OP_0 OP_0"
+ },
+ {
+ "type": "nonstandard",
+ "typeIncomplete": "scripthash",
+ "pubKeys": [
+ "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+ "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a"
+ ],
+ "signatures": [
+ null,
+ "30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801"
+ ],
+ "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+ "redeemScriptSig": "OP_0 OP_0 30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801",
+ "scriptSig": "OP_0 OP_0 30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
}
],
"invalid": {
@@ -121,6 +166,18 @@
}
],
"multisigInput": [
+ {
+ "description": "Not enough signatures provided",
+ "type": "multisig",
+ "pubKeys": [
+ "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340"
+ ],
+ "signatures": [
+ null,
+ null
+ ]
+ },
{
"exception": "Not enough signatures provided",
"pubKeys": [
diff --git a/test/scripts.js b/test/scripts.js
index ac35a65bb..fae41df1f 100644
--- a/test/scripts.js
+++ b/test/scripts.js
@@ -1,4 +1,5 @@
var assert = require('assert')
+var ops = require('../src/opcodes')
var scripts = require('../src/scripts')
var ECPubKey = require('../src/ecpubkey')
@@ -22,6 +23,18 @@ describe('Scripts', function() {
assert.equal(type, f.type)
})
})
+
+ fixtures.valid.forEach(function(f) {
+ if (!f.scriptSig) return
+ if (!f.typeIncomplete) return
+
+ it('classifies incomplete ' + f.scriptSig + ' as ' + f.typeIncomplete, function() {
+ var script = Script.fromASM(f.scriptSig)
+ var type = scripts.classifyInput(script, true)
+
+ assert.equal(type, f.typeIncomplete)
+ })
+ })
})
describe('classifyOutput', function() {
@@ -51,6 +64,16 @@ describe('Scripts', function() {
assert.equal(inputFn(script), expected)
})
+
+ if (f.typeIncomplete) {
+ var expectedIncomplete = type.toLowerCase() === f.typeIncomplete
+
+ it('returns ' + expected + ' for ' + f.scriptSig, function() {
+ var script = Script.fromASM(f.scriptSig)
+
+ assert.equal(inputFn(script, true), expectedIncomplete)
+ })
+ }
}
})
})
@@ -131,7 +154,7 @@ describe('Scripts', function() {
it('returns ' + f.scriptSig, function() {
var signatures = f.signatures.map(function(signature) {
- return new Buffer(signature, 'hex')
+ return signature ? new Buffer(signature, 'hex') : ops.OP_0
})
var scriptSig = scripts.multisigInput(signatures)
@@ -145,7 +168,7 @@ describe('Scripts', function() {
it('throws on ' + f.exception, function() {
var signatures = f.signatures.map(function(signature) {
- return new Buffer(signature, 'hex')
+ return signature ? new Buffer(signature, 'hex') : ops.OP_0
})
assert.throws(function() {
From 75ca355d48e2a25ed6173cb9f4c4dec2d7f1ea4b Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Wed, 4 Feb 2015 21:01:56 +1100
Subject: [PATCH 246/291] README: fix example URLs
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index c957a58d3..587bbb09a 100644
--- a/README.md
+++ b/README.md
@@ -92,8 +92,8 @@ The below examples are implemented as integration tests, they should be very eas
- [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L8)
- [Spend from a 2-of-2 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L22)
- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L7)
-- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L40)
-- [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L42)
+- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L42)
+- [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L44)
- [Recover a Private key from duplicate R values in a signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L90)
From 906accdc0f8321071d9f334e1fddf01eba711f80 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 12 Dec 2014 12:48:04 +1100
Subject: [PATCH 247/291] TxBuilder: extract extractSignatures to free function
---
src/transaction_builder.js | 131 ++++++++++++++++++++-----------------
1 file changed, 70 insertions(+), 61 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 2cf785c65..21e5c86c7 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -16,6 +16,71 @@ function TransactionBuilder() {
this.tx = new Transaction()
}
+function extractSignature(txIn) {
+ assert(!Array.prototype.every.call(txIn.hash, function(x) {
+ return x === 0
+ }), 'coinbase inputs not supported')
+
+ var redeemScript
+ var scriptSig = txIn.script
+ var scriptType = scripts.classifyInput(scriptSig, true)
+
+ // Re-classify if P2SH
+ if (scriptType === 'scripthash') {
+ redeemScript = Script.fromBuffer(scriptSig.chunks.slice(-1)[0])
+ scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1))
+
+ scriptType = scripts.classifyInput(scriptSig, true)
+ assert.equal(scripts.classifyOutput(redeemScript), scriptType, 'Non-matching scriptSig and scriptPubKey in input')
+ }
+
+ // Extract hashType, pubKeys and signatures
+ var hashType, parsed, pubKeys, signatures
+
+ switch (scriptType) {
+ case 'pubkeyhash':
+ parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
+ var pubKey = ECPubKey.fromBuffer(scriptSig.chunks[1])
+
+ hashType = parsed.hashType
+ pubKeys = [pubKey]
+ signatures = [parsed.signature]
+
+ break
+
+ case 'multisig':
+ parsed = scriptSig.chunks.slice(1).filter(function(chunk) {
+ return chunk !== ops.OP_0
+ }).map(ECSignature.parseScriptSignature)
+
+ hashType = parsed[0].hashType
+ pubKeys = []
+ signatures = parsed.map(function(p) { return p.signature })
+
+ break
+
+ case 'pubkey':
+ parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
+
+ hashType = parsed.hashType
+ pubKeys = []
+ signatures = [parsed.signature]
+
+ break
+
+ default:
+ assert(false, scriptType + ' inputs not supported')
+ }
+
+ return {
+ hashType: hashType,
+ pubKeys: pubKeys,
+ redeemScript: redeemScript,
+ scriptType: scriptType,
+ signatures: signatures
+ }
+}
+
// Static constructors
TransactionBuilder.fromTransaction = function(transaction) {
var txb = new TransactionBuilder()
@@ -35,72 +100,16 @@ TransactionBuilder.fromTransaction = function(transaction) {
})
// Extract/add signatures
- transaction.ins.forEach(function(txIn, i) {
- // Ignore empty scripts
- if (txIn.script.buffer.length === 0) return
-
+ txb.signatures = transaction.ins.map(function(txIn) {
+ // Coinbase inputs not supported
assert(!Array.prototype.every.call(txIn.hash, function(x) {
return x === 0
}), 'coinbase inputs not supported')
- var redeemScript
- var scriptSig = txIn.script
- var scriptType = scripts.classifyInput(scriptSig, true)
-
- // Re-classify if P2SH
- if (scriptType === 'scripthash') {
- redeemScript = Script.fromBuffer(scriptSig.chunks.slice(-1)[0])
- scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1))
-
- scriptType = scripts.classifyInput(scriptSig, true)
- assert.equal(scripts.classifyOutput(redeemScript), scriptType, 'Non-matching scriptSig and scriptPubKey in input')
- }
-
- // Extract hashType, pubKeys and signatures
- var hashType, parsed, pubKeys, signatures
-
- switch (scriptType) {
- case 'pubkeyhash':
- parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
- var pubKey = ECPubKey.fromBuffer(scriptSig.chunks[1])
-
- hashType = parsed.hashType
- pubKeys = [pubKey]
- signatures = [parsed.signature]
-
- break
-
- case 'multisig':
- parsed = scriptSig.chunks.slice(1).filter(function(chunk) {
- return chunk !== ops.OP_0
- }).map(ECSignature.parseScriptSignature)
-
- hashType = parsed[0].hashType
- pubKeys = []
- signatures = parsed.map(function(p) { return p.signature })
-
- break
-
- case 'pubkey':
- parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
-
- hashType = parsed.hashType
- pubKeys = []
- signatures = [parsed.signature]
-
- break
-
- default:
- assert(false, scriptType + ' inputs not supported')
- }
+ // Ignore empty scripts
+ if (txIn.script.buffer.length === 0) return
- txb.signatures[i] = {
- hashType: hashType,
- pubKeys: pubKeys,
- redeemScript: redeemScript,
- scriptType: scriptType,
- signatures: signatures
- }
+ return extractSignature(txIn)
})
return txb
From 46db11e04a60b89fb193a95244090d6dac5bafc0 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Tue, 6 Jan 2015 16:05:38 +1100
Subject: [PATCH 248/291] TxBuilder: extract isCoinbaseHash function
---
src/transaction_builder.js | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 21e5c86c7..314838675 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -7,20 +7,13 @@ var ECSignature = require('./ecsignature')
var Script = require('./script')
var Transaction = require('./transaction')
-function TransactionBuilder() {
- this.prevOutMap = {}
- this.prevOutScripts = {}
- this.prevOutTypes = {}
-
- this.signatures = []
- this.tx = new Transaction()
+function isCoinbase(txHash) {
+ return Array.prototype.every.call(txHash, function(x) {
+ return x === 0
+ })
}
function extractSignature(txIn) {
- assert(!Array.prototype.every.call(txIn.hash, function(x) {
- return x === 0
- }), 'coinbase inputs not supported')
-
var redeemScript
var scriptSig = txIn.script
var scriptType = scripts.classifyInput(scriptSig, true)
@@ -81,7 +74,15 @@ function extractSignature(txIn) {
}
}
-// Static constructors
+function TransactionBuilder() {
+ this.prevOutMap = {}
+ this.prevOutScripts = {}
+ this.prevOutTypes = {}
+
+ this.signatures = []
+ this.tx = new Transaction()
+}
+
TransactionBuilder.fromTransaction = function(transaction) {
var txb = new TransactionBuilder()
@@ -101,10 +102,8 @@ TransactionBuilder.fromTransaction = function(transaction) {
// Extract/add signatures
txb.signatures = transaction.ins.map(function(txIn) {
- // Coinbase inputs not supported
- assert(!Array.prototype.every.call(txIn.hash, function(x) {
- return x === 0
- }), 'coinbase inputs not supported')
+ // TODO: remove me after testcase added
+ assert(!isCoinbase(txIn.hash), 'coinbase inputs not supported')
// Ignore empty scripts
if (txIn.script.buffer.length === 0) return
@@ -115,7 +114,6 @@ TransactionBuilder.fromTransaction = function(transaction) {
return txb
}
-// Operations
TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOutScript) {
var prevOutHash
From ebe34db8df55ba078d7c56a372dd44b9303b1628 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 5 Jan 2015 14:50:54 +1100
Subject: [PATCH 249/291] TxBuilder: avoid var redeclaration due to hoisting
---
src/transaction_builder.js | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 314838675..2f110fc54 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -191,9 +191,8 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
switch (scriptType) {
case 'pubkeyhash':
- var signature = signatures[0]
var pubKey = input.pubKeys[0]
- scriptSig = scripts.pubKeyHashInput(signature, pubKey)
+ scriptSig = scripts.pubKeyHashInput(signatures[0], pubKey)
break
@@ -204,8 +203,7 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
break
case 'pubkey':
- var signature = signatures[0]
- scriptSig = scripts.pubKeyInput(signature)
+ scriptSig = scripts.pubKeyInput(signatures[0])
break
From ba97b5ee3422df331def82670680febd961704b5 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 12 Dec 2014 14:48:31 +1100
Subject: [PATCH 250/291] TxBuilder: re-order to avoid mutation in case of
failure
---
src/transaction_builder.js | 19 +++++++++++--------
test/transaction_builder.js | 23 +++++++++++++++++++++++
2 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 2f110fc54..35817261a 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -253,25 +253,28 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
hash = this.tx.hashForSignature(index, prevOutScript, hashType)
}
- this.prevOutScripts[index] = prevOutScript
- this.prevOutTypes[index] = prevOutType
-
- if (!(index in this.signatures)) {
- this.signatures[index] = {
+ var input = this.signatures[index]
+ if (!input) {
+ input = {
hashType: hashType,
pubKeys: [],
redeemScript: redeemScript,
scriptType: scriptType,
signatures: []
}
+
+ this.signatures[index] = input
+
} else {
assert.equal(scriptType, 'multisig', scriptType + ' doesn\'t support multiple signatures')
+ assert.equal(input.hashType, hashType, 'Inconsistent hashType')
+ assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
}
- var input = this.signatures[index]
- assert.equal(input.hashType, hashType, 'Inconsistent hashType')
- assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
+ this.prevOutScripts[index] = prevOutScript
+ this.prevOutTypes[index] = prevOutType
+ // TODO: order signatures for multisig, enforce m < n
var signature = privKey.sign(hash)
input.pubKeys.push(privKey.pub)
input.signatures.push(signature)
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 8e2b528db..cde634b23 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -153,6 +153,29 @@ describe('TransactionBuilder', function() {
}, /RedeemScript can\'t be P2SH/)
})
+ it('throws if hashType is inconsistent', function() {
+ var redeemScript = scripts.multisigOutput(1, [privKey.pub])
+
+ txb.addInput(prevTxHash, 0)
+ txb.sign(0, privKey, redeemScript, 83)
+
+ assert.throws(function() {
+ txb.sign(0, privKey, redeemScript, 82)
+ }, /Inconsistent hashType/)
+ })
+
+ it('throws if redeemScript is inconsistent', function() {
+ var firstScript = scripts.multisigOutput(1, [privKey.pub])
+ var otherScript = scripts.multisigOutput(2, [privKey.pub, privKey.pub])
+
+ txb.addInput(prevTxHash, 0)
+ txb.sign(0, privKey, firstScript)
+
+ assert.throws(function() {
+ txb.sign(0, privKey, otherScript)
+ }, /Inconsistent redeemScript/)
+ })
+
it('throws if redeemScript not supported', function() {
txb.addInput(prevTxHash, 0)
From c29b233744438e10dcd991749991f975142cfe48 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Thu, 5 Feb 2015 13:30:35 +1100
Subject: [PATCH 251/291] TxBuilder: build convenience functions don't need
extra line breaks
---
src/transaction_builder.js | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 35817261a..ede0283b4 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -162,14 +162,8 @@ TransactionBuilder.prototype.addOutput = function(scriptPubKey, value) {
return this.tx.addOutput(scriptPubKey, value)
}
-TransactionBuilder.prototype.build = function() {
- return this.__build(false)
-}
-
-TransactionBuilder.prototype.buildIncomplete = function() {
- return this.__build(true)
-}
-
+TransactionBuilder.prototype.build = function() { return this.__build(false) }
+TransactionBuilder.prototype.buildIncomplete = function() { return this.__build(true) }
TransactionBuilder.prototype.__build = function(allowIncomplete) {
if (!allowIncomplete) {
assert(this.tx.ins.length > 0, 'Transaction has no inputs')
From dfe74fa0d23b2a0c4ba3753fabfbd27405b257b3 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Fri, 12 Dec 2014 15:19:03 +1100
Subject: [PATCH 252/291] TxBuilder: sign now signs inputs in known publicKey
order
---
src/transaction_builder.js | 40 +++++++++++++++++++++++++++----------
test/transaction_builder.js | 21 +++++++++++++++++++
2 files changed, 51 insertions(+), 10 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index ede0283b4..d05ee5ba9 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -33,10 +33,9 @@ function extractSignature(txIn) {
switch (scriptType) {
case 'pubkeyhash':
parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
- var pubKey = ECPubKey.fromBuffer(scriptSig.chunks[1])
-
hashType = parsed.hashType
- pubKeys = [pubKey]
+
+ pubKeys = [ECPubKey.fromBuffer(scriptSig.chunks[1])]
signatures = [parsed.signature]
break
@@ -50,6 +49,10 @@ function extractSignature(txIn) {
pubKeys = []
signatures = parsed.map(function(p) { return p.signature })
+ if (redeemScript) {
+ pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
+ }
+
break
case 'pubkey':
@@ -59,6 +62,10 @@ function extractSignature(txIn) {
pubKeys = []
signatures = [parsed.signature]
+ if (redeemScript) {
+ pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])]
+ }
+
break
default:
@@ -249,15 +256,26 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
var input = this.signatures[index]
if (!input) {
+ var pubKeys = []
+
+ if (redeemScript && scriptType === 'multisig') {
+ pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
+
+ } else {
+ pubKeys.push(privKey.pub)
+ }
+
input = {
hashType: hashType,
- pubKeys: [],
+ pubKeys: pubKeys,
redeemScript: redeemScript,
scriptType: scriptType,
signatures: []
}
this.signatures[index] = input
+ this.prevOutScripts[index] = prevOutScript
+ this.prevOutTypes[index] = prevOutType
} else {
assert.equal(scriptType, 'multisig', scriptType + ' doesn\'t support multiple signatures')
@@ -265,13 +283,15 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
}
- this.prevOutScripts[index] = prevOutScript
- this.prevOutTypes[index] = prevOutType
+ // enforce signing in order of public keys
+ assert(input.pubKeys.some(function(pubKey, i) {
+ if (!privKey.pub.Q.equals(pubKey.Q)) return false // FIXME: could be better?
+
+ assert(!input.signatures[i], 'Signature already exists')
+ input.signatures[i] = privKey.sign(hash)
- // TODO: order signatures for multisig, enforce m < n
- var signature = privKey.sign(hash)
- input.pubKeys.push(privKey.pub)
- input.signatures.push(signature)
+ return true
+ }), 'privateKey cannot sign for this input')
}
module.exports = TransactionBuilder
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index cde634b23..a53cdaf3a 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -184,6 +184,27 @@ describe('TransactionBuilder', function() {
}, /RedeemScript not supported \(nonstandard\)/)
})
})
+
+ it('throws if signature already exists', function() {
+ var redeemScript = scripts.multisigOutput(1, [privKey.pub])
+
+ txb.addInput(prevTxHash, 0)
+ txb.sign(0, privKey, redeemScript)
+
+ assert.throws(function() {
+ txb.sign(0, privKey, redeemScript)
+ }, /Signature already exists/)
+ })
+
+ it('throws if private key is unable to sign for that input', function() {
+ var redeemScript = scripts.multisigOutput(1, [privKey.pub])
+
+ txb.addInput(prevTxHash, 0)
+
+ assert.throws(function() {
+ txb.sign(0, ECKey.makeRandom(), redeemScript)
+ }, /privateKey cannot sign for this input/)
+ })
})
describe('build', function() {
From b629a03c98521daf62f6b8b89aa82147d370ac26 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 5 Jan 2015 15:30:04 +1100
Subject: [PATCH 253/291] TxBuilder: rename prevOutMap to prevTxMap
---
src/transaction_builder.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index d05ee5ba9..ddddb1a4a 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -82,7 +82,7 @@ function extractSignature(txIn) {
}
function TransactionBuilder() {
- this.prevOutMap = {}
+ this.prevTxMap = {}
this.prevOutScripts = {}
this.prevOutTypes = {}
@@ -151,10 +151,10 @@ TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOu
}), 'No, this would invalidate signatures')
var prevOut = prevOutHash.toString('hex') + ':' + index
- assert(!(prevOut in this.prevOutMap), 'Transaction is already an input')
+ assert(!(prevOut in this.prevTxMap), 'Transaction is already an input')
var vout = this.tx.addInput(prevOutHash, index, sequence)
- this.prevOutMap[prevOut] = true
+ this.prevTxMap[prevOut] = true
this.prevOutScripts[vout] = prevOutScript
this.prevOutTypes[vout] = prevOutType
From 35fa86c1f941835547f37a6ce4d04e580ae7f771 Mon Sep 17 00:00:00 2001
From: Daniel Cousens
Date: Mon, 5 Jan 2015 14:55:52 +1100
Subject: [PATCH 254/291] tests: add [failing] raw multisig fixture for
TxBuilder
---
test/fixtures/transaction_builder.json | 25 +++++++++++++++++++++----
test/transaction_builder.js | 1 -
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index 5b0bb325e..59643113d 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -3,7 +3,6 @@
"build": [
{
"description": "pubKeyHash->pubKeyHash 1:1 transaction",
- "txid": "bd641f4b0aa8bd70189ab45e935c4762f0e1c49f294b4779d79887937b7cf42e",
"txhex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000006b483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
"inputs": [
{
@@ -23,7 +22,6 @@
},
{
"description": "pubKey->pubKeyHash 1:1 transaction",
- "txid": "a900dea133a3c51e9fe55d82bf4a4f50a4c3ac6e380c841f93651a076573320c",
"txhex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000494830450221009833abb3ab49d7004c06bcc79eafd6905ada3eee91f3376ad388548034acd9a702202e84dda6ef2678c82256afcfc459aaa68e179b2bb0e6b2dc3f1410e132c5e6c301ffffffff0100f90295000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
"inputs": [
{
@@ -44,7 +42,6 @@
},
{
"description": "2-of-2 P2SH multisig -> pubKeyHash 1:1 Transaction",
- "txid": "8c500ce6eef6c78a10de923b68394cf31120151bdc4600e4b12de865defa9d24",
"txhex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1a0100473044022040039a3d0a806d6c2c0ac8a62f2467c979c897c945f3f11905b9c5ea76b4a88002200976f187f852f7d186e8e8aa39332092aa8a504b63a7ae3d0eca09ebea1497fd0147304402205522d1949d13347054bd5ea86cdcad2344f49628a935faaee8f5e744bd3ef87e022063a28ab077817222ccd7d5a70e77ed7274840b9ba8db5dd93a33bdd41813d548014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0110270000000000001976a914faf1d99bf040ea9c7f8cc9f14ac6733ad75ce24688ac00000000",
"inputs": [
{
@@ -64,9 +61,29 @@
}
]
},
+ {
+ "description": "2-of-2 raw multisig -> pubKeyHash 1:1 Transaction",
+ "txhex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f07149000000009100473044022040039a3d0a806d6c2c0ac8a62f2467c979c897c945f3f11905b9c5ea76b4a88002200976f187f852f7d186e8e8aa39332092aa8a504b63a7ae3d0eca09ebea1497fd0147304402205522d1949d13347054bd5ea86cdcad2344f49628a935faaee8f5e744bd3ef87e022063a28ab077817222ccd7d5a70e77ed7274840b9ba8db5dd93a33bdd41813d54801ffffffff0110270000000000001976a914faf1d99bf040ea9c7f8cc9f14ac6733ad75ce24688ac00000000",
+ "inputs": [
+ {
+ "index": 0,
+ "prevTx": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+ "prevTxScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+ "privKeys": [
+ "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+ "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "script": "OP_DUP OP_HASH160 faf1d99bf040ea9c7f8cc9f14ac6733ad75ce246 OP_EQUALVERIFY OP_CHECKSIG",
+ "value": 10000
+ }
+ ]
+ },
{
"description": "Transaction w/ non-zero vin inputs",
- "txid": "7d9b699f26765fdfdd598223a952a6e129f8c159e2e05e911af822ee743fa745",
"txhex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a47304402205c80bbb5125b35d5e5a8324b1336832d29a6fc004859c8a9ff6bef47ba7fc348022018612216e57a521b2c4543f1f4fd738a76814c37c074e88adfe12464fff31cf901210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
"inputs": [
{
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index a53cdaf3a..f74330012 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -246,7 +246,6 @@ describe('TransactionBuilder', function() {
var tx = txb.build()
- assert.equal(tx.getId(), f.txid)
assert.equal(tx.toHex(), f.txhex)
})
})
From 396e4d4235c2e29a7558457803c81df3a36be5ef Mon Sep 17 00:00:00 2001
From: Daniel Cousens