├── .gitignore ├── .groc.json ├── .karma.conf.js ├── .npmignore ├── .nvmrc ├── .travis.yml ├── LICENSE ├── README.md ├── bin ├── test-parallel ├── testapp.js └── yours-bitcoin.js ├── build └── index.html ├── config.js ├── gulpfile.js ├── index.js ├── lib ├── ach.js ├── addr.js ├── address.js ├── aes.js ├── aescbc.js ├── base-58-check.js ├── base-58.js ├── bip-32.js ├── bip-39-en.js ├── bip-39-jp.js ├── bip-39.js ├── bip-68.js ├── block-header.js ├── block.js ├── bn.js ├── br.js ├── bsm.js ├── bw.js ├── cbc.js ├── cmp.js ├── constants.js ├── ecdsa.js ├── ecies.js ├── get-blocks.js ├── hash.js ├── interp.js ├── inv.js ├── kdf.js ├── key-pair.js ├── merkle.js ├── msg-addr.js ├── msg-alert.js ├── msg-block.js ├── msg-get-addr.js ├── msg-get-blocks.js ├── msg-get-data.js ├── msg-get-headers.js ├── msg-headers.js ├── msg-inv.js ├── msg-mem-pool.js ├── msg-not-found.js ├── msg-ping.js ├── msg-pong.js ├── msg-reject.js ├── msg-send-headers.js ├── msg-tx.js ├── msg-ver-ack.js ├── msg-version.js ├── msg.js ├── op-code.js ├── point.js ├── priv-key.js ├── pub-key.js ├── random.js ├── reject.js ├── script.js ├── sig.js ├── struct.js ├── tx-builder.js ├── tx-in.js ├── tx-out-map.js ├── tx-out.js ├── tx-verifier.js ├── tx.js ├── var-int.js ├── version.js ├── worker-browser.js ├── worker-node.js ├── workers-cmd.js ├── workers-result.js └── workers.js ├── npm-shrinkwrap.json ├── package.json └── test ├── ach.js ├── addr.js ├── address.js ├── aes.js ├── aescbc.js ├── base-58-check.js ├── base-58.js ├── bip-32.js ├── bip-39.js ├── bip-68.js ├── block-header.js ├── block.js ├── bn.js ├── br.js ├── bsm.js ├── bw.js ├── cbc.js ├── cmp.js ├── ecdsa.js ├── ecies.js ├── get-blocks.js ├── global.js ├── hash.js ├── helpers ├── interp.js └── tx-verifier.js ├── index.js ├── interp-vectors-1.js ├── interp-vectors-2.js ├── interp-vectors-3.js ├── interp-vectors-4.js ├── interp.js ├── inv.js ├── kdf.js ├── key-pair.js ├── merkle.js ├── msg-addr.js ├── msg-alert.js ├── msg-block.js ├── msg-get-addr.js ├── msg-get-blocks.js ├── msg-get-data.js ├── msg-get-headers.js ├── msg-headers.js ├── msg-inv.js ├── msg-mem-pool.js ├── msg-not-found.js ├── msg-ping.js ├── msg-pong.js ├── msg-reject.js ├── msg-send-header.js ├── msg-tx.js ├── msg-ver-ack.js ├── msg-version.js ├── msg.js ├── op-code.js ├── point.js ├── priv-key.js ├── pub-key.js ├── random.js ├── reject.js ├── script.js ├── sig.js ├── struct.js ├── tx-builder.js ├── tx-in.js ├── tx-out-map.js ├── tx-out.js ├── tx-verifier-vectors-1.js ├── tx-verifier-vectors-2.js ├── tx-verifier-vectors-3.js ├── tx-verifier-vectors-4.js ├── tx-verifier.js ├── tx.js ├── var-int.js ├── vectors ├── aes.json ├── aescbc.json ├── bip39.json ├── bitcoind │ ├── script_invalid.json │ ├── script_valid.json │ ├── sighash.json │ ├── tx_invalid.json │ └── tx_valid.json ├── coolest-tx-ever-sent.json ├── ecdsa.json ├── hash.json ├── kdf.json ├── largesttx.json ├── largesttxblock.json ├── sig.json └── sighash-single-bug.json ├── version.js ├── workers-cmd.js ├── workers-result.js └── workers.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | coverage 3 | node_modules 4 | build/yours-bitcoin.js 5 | build/yours-bitcoin-worker.js 6 | build/yours-bitcoin-min.js 7 | build/yours-bitcoin-worker-min.js 8 | build/tests.js 9 | npm-debug.log 10 | doc 11 | -------------------------------------------------------------------------------- /.groc.json: -------------------------------------------------------------------------------- 1 | { 2 | "glob": ["README.md", "lib/*.js", "lib/**/*.js", "lib/**/**/*.js", "examples/*.js"] 3 | } 4 | -------------------------------------------------------------------------------- /.karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Tue Jan 06 2015 16:30:03 GMT-0800 (PST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: 'build', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | {pattern: 'yours-bitcoin.js', watched: true, included: true, served: true}, 19 | {pattern: 'yours-bitcoin-worker.js', watched: true, included: false, served: true}, 20 | 'tests.js' 21 | ], 22 | 23 | 24 | // list of files to exclude 25 | exclude: [ 26 | ], 27 | 28 | 29 | // preprocess matching files before serving them to the browser 30 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 31 | preprocessors: { 32 | }, 33 | 34 | 35 | // test results reporter to use 36 | // possible values: 'dots', 'progress' 37 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 38 | reporters: ['progress'], 39 | 40 | 41 | // web server port 42 | port: 9876, 43 | 44 | 45 | // enable / disable colors in the output (reporters and logs) 46 | colors: true, 47 | 48 | 49 | // level of logging 50 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 51 | logLevel: config.LOG_DEBUG, 52 | 53 | 54 | // enable / disable watching file and executing tests whenever any file changes 55 | autoWatch: false, 56 | 57 | 58 | // start these browsers 59 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 60 | browsers: ['Firefox'], 61 | 62 | 63 | // Continuous Integration mode 64 | // if true, Karma captures browsers, runs the tests and exits 65 | singleRun: true 66 | }); 67 | }; 68 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | build 3 | coverage 4 | test 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 6.1 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '4.3' 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Yours Inc. 2 | 3 | Copyright (c) 2014-2016 Ryan X. Charles 4 | 5 | Parts of this software are based on Bitcoin Core 6 | Copyright (c) 2009-2016 The Bitcoin Core developers 7 | 8 | Parts of this software were developed by reddit 9 | Copyright (c) 2014 reddit, Inc. 10 | 11 | Parts of this software are based on bitcore 12 | Copyright (c) 2014 BitPay Inc. 13 | 14 | Parts of this software are based on BitcoinJS 15 | Copyright (c) 2011-2014 Bitcoinjs-lib contributors 16 | 17 | Parts of this software are based on BitcoinJ 18 | Copyright (c) 2011 Google Inc. 19 | 20 | Permission is hereby granted, free of charge, to any person obtaining a copy 21 | of this software and associated documentation files (the "Software"), to deal 22 | in the Software without restriction, including without limitation the rights 23 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 | copies of the Software, and to permit persons to whom the Software is 25 | furnished to do so, subject to the following conditions: 26 | 27 | The above copyright notice and this permission notice shall be included in 28 | all copies or substantial portions of the Software. 29 | 30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 | THE SOFTWARE. 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yours Bitcoin 2 | ============= 3 | 4 | Yours Bitcoin is a javascript implementation of bitcoin intended to satisfy 5 | certain goals: 6 | 7 | 1. Bring the blockchain to web browsers and node.js in a decentralized, 8 | trust-minimized manner, without the required use of a third-party API. 9 | 10 | 2. Support ease-of-use by being internally consistent. It should not be 11 | necessary to read the source code of a class or function to know how to use it. 12 | Once you know how to use part of the library, the other parts should feel 13 | natural. 14 | 15 | 3. Have 100% test coverage, or nearly so, so that the library is known to be 16 | reliable. This should include running standard test vectors from the reference 17 | implementation. 18 | 19 | 4. Library objects have an interface suitable for use with a command-line 20 | interface or other libraries and tools, in particular having toString, 21 | fromString, toJSON, fromJSON, toBuffer, fromBuffer, toHex, fromHex methods. 22 | 23 | 5. All standard features of the blockchain are implemented (or will be) and 24 | saved in lib/. All BIPs are correctly implemented and, where appropriate, saved 25 | as bip-xx.js in lib/ (since that is their standard name). In order to allow 26 | rapid development, Yours Bitcoin includes non-standard and experimental 27 | features. Any non-standard features (such as colored coins or stealth 28 | addresses) are labeled as such in index.js as well as in comments. 29 | 30 | 6. Expose everything, including dependencies. This makes it possible to develop 31 | apps that require fine-grained control over the basics, such as big numbers and 32 | points. However, it also means that you can hurt yourself if you misuse these 33 | primitives. 34 | 35 | 7. Use standard javascript conventions wherever possible so that other 36 | developers find the code easy to understand. 37 | 38 | 8. Minimize the use of dependencies so that all code can be easily audited. 39 | 40 | 9. All instance methods modify the state of the object and return the object, 41 | unless there is a good reason to do something different. To access the result 42 | of an instance method, you must access the object property(s) that it modifies. 43 | 44 | Yours Bitcoin is still being developed and does not yet support downloading the 45 | blockchain. 46 | 47 | Environment Variables 48 | --------------------- 49 | - `YOURS_BITCOIN_JS_BASE_URL` - Default "/". 50 | - `YOURS_BITCOIN_JS_BUNDLE_FILE` - Default "yours-bitcoin.js" 51 | - `YOURS_BITCOIN_JS_WORKER_FILE` - Default "yours-bitcoin-worker.js" 52 | - `YOURS_BITCOIN_JS_BUNDLE_MIN_FILE` - Default "yours-bitcoin-min.js" 53 | - `YOURS_BITCOIN_JS_WORKER_MIN_FILE` - Default "yours-bitcoin-worker-min.js" 54 | - `YOURS_BITCOIN_NETWORK` - Default "mainnet" 55 | 56 | You can change the network to run the CLI in testnet mode: 57 | ``` 58 | YOURS_BITCOIN_NETWORK=testnet ./bin/yours-bitcoin.js 59 | ``` 60 | 61 | Documentation 62 | ------------- 63 | 64 | While Yours Bitcoin is under heavy development, the API changes frequently, and 65 | the documentation is not kept up-to-date. However there is some documentation, 66 | and it can be built with groc: 67 | 68 | ``` 69 | npm install -g groc 70 | groc 71 | ``` 72 | 73 | Database Proposal 74 | ----------------- 75 | ``` 76 | block-[blockHashBuf]:[height][blockBuf] 77 | height-[height][blockHashBuf]:[workSum] 78 | work-[workSum][blockHashBuf]: 79 | tx-[txHashBuf]:[txBuf] 80 | address-[addressBuf]:[satoshiDiffBn, height, blockHashBuf, txHashBuf] (removed on reorg) 81 | chain-[height]:[blockHashBuf] (removed on reorg) 82 | ``` 83 | -------------------------------------------------------------------------------- /bin/test-parallel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This test runner passes a list of every 4th test file into 4 simultaneous 4 | # mocha processes so it can use 4 cores efficiently. This should run no faster 5 | # than 4 times faster than series. In practice, it runs about twice as fast on 6 | # a 4 core machine. You must execute this from the project root directory. You 7 | # must have "parallel" installed for this to work. On Ubuntu: "apt-get install 8 | # parallel". 9 | 10 | echo "Executing mocha tests in 6 processes." 11 | 12 | ls test/*.js \ 13 | | tee \ 14 | >(sed -n "p;n;n;n;n;n;" | xargs echo mocha -R progress) \ 15 | >(sed -n "n;p;n;n;n;n;" | xargs echo mocha -R progress) \ 16 | >(sed -n "n;n;p;n;n;n;" | xargs echo mocha -R progress) \ 17 | >(sed -n "n;n;n;p;n;n;" | xargs echo mocha -R progress) \ 18 | >(sed -n "n;n;n;n;p;n;" | xargs echo mocha -R progress) \ 19 | >(sed -n "n;n;n;n;n;p;" | xargs echo mocha -R progress) \ 20 | > /dev/null \ 21 | | parallel 22 | -------------------------------------------------------------------------------- /bin/testapp.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /** 3 | * Basic web app to facilitate running the mocha browser tests without karma. 4 | */ 5 | 'use strict' 6 | let express = require('express') 7 | let path = require('path') 8 | let app = express() 9 | 10 | app.use(express.static(path.join(__dirname, '../build'))) 11 | app.use(express.static(path.join(__dirname, '../node_modules'))) 12 | 13 | let server = app.listen(3000, function () { 14 | let host = server.address().address 15 | let port = server.address().port 16 | console.log('Run the mocha tests at http://%s:%s/', host, port) 17 | }) 18 | 19 | module.exports.app = app 20 | module.exports.server = server 21 | -------------------------------------------------------------------------------- /bin/yours-bitcoin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict' 3 | let repl = require('repl') 4 | let YoursBitcoin = require('../') 5 | // Make all Fullnode classes globally available. 6 | Object.assign(global, YoursBitcoin, {YoursBitcoin: YoursBitcoin}) 7 | repl.start({ 8 | prompt: 'yours-bitcoin> ', 9 | useGlobal: true, 10 | ignoreUndefined: true 11 | }) 12 | -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | // By default, we assume browser-loaded javascript is served from the root 2 | // directory, "/", of the http server. karma, however, assumes files are in the 3 | // "/base/" directory, thus we invented this variable to allow overriding the 4 | // directory. If you wish to put your javascript somewhere other than root, 5 | // specify it by setting this environment variable before building. You can 6 | // also override the name of the bundle and worker files or the minified 7 | // versions by setting the respective environment variables below. 8 | if (!process.env.YOURS_BITCOIN_JS_BASE_URL) { 9 | process.env.YOURS_BITCOIN_JS_BASE_URL = '/' 10 | } 11 | 12 | if (!process.env.YOURS_BITCOIN_JS_BUNDLE_FILE) { 13 | process.env.YOURS_BITCOIN_JS_BUNDLE_FILE = 'yours-bitcoin.js' 14 | } 15 | 16 | if (!process.env.YOURS_BITCOIN_JS_WORKER_FILE) { 17 | process.env.YOURS_BITCOIN_JS_WORKER_FILE = 'yours-bitcoin-worker.js' 18 | } 19 | 20 | if (!process.env.YOURS_BITCOIN_JS_BUNDLE_MIN_FILE) { 21 | process.env.YOURS_BITCOIN_JS_BUNDLE_MIN_FILE = 'yours-bitcoin-min.js' 22 | } 23 | 24 | if (!process.env.YOURS_BITCOIN_JS_WORKER_MIN_FILE) { 25 | process.env.YOURS_BITCOIN_JS_WORKER_MIN_FILE = 'yours-bitcoin-worker-min.js' 26 | } 27 | 28 | if (!process.env.YOURS_BITCOIN_NETWORK) { 29 | process.env.YOURS_BITCOIN_NETWORK = 'mainnet' 30 | } 31 | -------------------------------------------------------------------------------- /lib/ach.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ach (Aes+Cbc+Hmac) (experimental) 3 | * ================================= 4 | * 5 | * An "encrypt-then-MAC" that uses Aes, Cbc and SHA256 Hmac. This is suitable 6 | * for general encryption of data. 7 | * 8 | * The encrypted data takes the form: 9 | * (256 bit hmac)(128 bit iv)(128+ bits Aes+Cbc encrypted message) 10 | */ 11 | 'use strict' 12 | let dependencies = { 13 | Aescbc: require('./aescbc'), 14 | Hash: require('./hash'), 15 | Random: require('./random'), 16 | Workers: require('./workers'), 17 | asink: require('asink'), 18 | cmp: require('./cmp') 19 | } 20 | 21 | let inject = function (deps) { 22 | let Aescbc = deps.Aescbc 23 | let Hash = deps.Hash 24 | let Random = deps.Random 25 | let Workers = deps.Workers 26 | let asink = deps.asink 27 | let cmp = deps.cmp 28 | 29 | let Ach = {} 30 | 31 | Ach.encrypt = function (messageBuf, cipherKeyBuf, ivBuf) { 32 | let encBuf = Aescbc.encrypt(messageBuf, cipherKeyBuf, ivBuf) 33 | let hmacbuf = Hash.sha256Hmac(encBuf, cipherKeyBuf) 34 | return Buffer.concat([hmacbuf, encBuf]) 35 | } 36 | 37 | Ach.asyncEncrypt = function (messageBuf, cipherKeyBuf, ivBuf) { 38 | return asink(function * () { 39 | if (!ivBuf) { 40 | ivBuf = Random.getRandomBuffer(128 / 8) 41 | } 42 | let args = [messageBuf, cipherKeyBuf, ivBuf] 43 | let workersResult = yield Workers.asyncClassMethod('Ach', 'encrypt', args) 44 | return workersResult.resbuf 45 | }, this) 46 | } 47 | 48 | Ach.decrypt = function (encBuf, cipherKeyBuf) { 49 | if (encBuf.length < (256 + 128 + 128) / 8) { 50 | throw new Error('The encrypted data must be at least 256+128+128 bits, which is the length of the Hmac plus the iv plus the smallest encrypted data size') 51 | } 52 | let hmacbuf = encBuf.slice(0, 256 / 8) 53 | encBuf = encBuf.slice(256 / 8, encBuf.length) 54 | let hmacbuf2 = Hash.sha256Hmac(encBuf, cipherKeyBuf) 55 | if (!cmp(hmacbuf, hmacbuf2)) { 56 | throw new Error('Message authentication failed - Hmacs are not equivalent') 57 | } 58 | return Aescbc.decrypt(encBuf, cipherKeyBuf) 59 | } 60 | 61 | Ach.asyncDecrypt = function (encBuf, cipherKeyBuf) { 62 | return asink(function * () { 63 | let args = [encBuf, cipherKeyBuf] 64 | let workersResult = yield Workers.asyncClassMethod('Ach', 'decrypt', args) 65 | return workersResult.resbuf 66 | }, this) 67 | } 68 | 69 | return Ach 70 | } 71 | 72 | inject = require('injecter')(inject, dependencies) 73 | let Ach = inject() 74 | module.exports = Ach 75 | -------------------------------------------------------------------------------- /lib/addr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Addr 3 | * ==== 4 | * 5 | * An IP address and port. Note that "Addr" is completely different from 6 | * "Address". Addr is an IP address and port of a bitcoin node on the network 7 | * for connecting to using the bitcoin p2p protocol. Address is a bitcoin 8 | * address for sending a payment to. 9 | */ 10 | 'use strict' 11 | let dependencies = { 12 | Bw: require('./bw'), 13 | Struct: require('./struct') 14 | } 15 | 16 | let inject = function (deps) { 17 | let Bw = deps.Bw 18 | let Struct = deps.Struct 19 | 20 | class Addr extends Struct { 21 | constructor (time, servicesBuf, ipAddrBuf, port) { 22 | super({time, servicesBuf, ipAddrBuf, port}) 23 | } 24 | 25 | toBw (bw) { 26 | if (!bw) { 27 | bw = new Bw() 28 | } 29 | bw.writeUInt32LE(this.time) // note LE 30 | bw.write(this.servicesBuf) 31 | bw.write(this.ipAddrBuf) 32 | bw.writeUInt16BE(this.port) // note BE 33 | return bw 34 | } 35 | 36 | fromBr (br) { 37 | this.time = br.readUInt32LE() // note LE 38 | this.servicesBuf = br.read(8) 39 | this.ipAddrBuf = br.read(16) 40 | this.port = br.readUInt16BE() // note BE 41 | return this 42 | } 43 | } 44 | 45 | return Addr 46 | } 47 | 48 | inject = require('injecter')(inject, dependencies) 49 | let Addr = inject() 50 | module.exports = Addr 51 | -------------------------------------------------------------------------------- /lib/aes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Aes (experimental) 3 | * ================== 4 | * 5 | * Advanced Encryption Standard (Aes). This is a low-level tool for encrypting 6 | * or decrypting blocks of data. There is almost never a reason to use this - 7 | * don't use it unless you need to encrypt or decrypt individual blocks. 8 | */ 9 | 'use strict' 10 | let dependencies = { 11 | _Aes: require('aes') 12 | } 13 | 14 | let inject = function (deps) { 15 | let _Aes = deps._Aes 16 | let Aes = {} 17 | 18 | Aes.encrypt = function (messageBuf, keyBuf) { 19 | let key = Aes.buf2Words(keyBuf) 20 | let message = Aes.buf2Words(messageBuf) 21 | let a = new _Aes(key) 22 | let enc = a.encrypt(message) 23 | let encBuf = Aes.words2Buf(enc) 24 | return encBuf 25 | } 26 | 27 | Aes.decrypt = function (encBuf, keyBuf) { 28 | let enc = Aes.buf2Words(encBuf) 29 | let key = Aes.buf2Words(keyBuf) 30 | let a = new _Aes(key) 31 | let message = a.decrypt(enc) 32 | let messageBuf = Aes.words2Buf(message) 33 | return messageBuf 34 | } 35 | 36 | Aes.buf2Words = function (buf) { 37 | if (buf.length % 4) { 38 | throw new Error('buf length must be a multiple of 4') 39 | } 40 | 41 | let words = [] 42 | 43 | for (let i = 0; i < buf.length / 4; i++) { 44 | words.push(buf.readUInt32BE(i * 4)) 45 | } 46 | 47 | return words 48 | } 49 | 50 | Aes.words2Buf = function (words) { 51 | let buf = new Buffer(words.length * 4) 52 | 53 | for (let i = 0; i < words.length; i++) { 54 | buf.writeUInt32BE(words[i], i * 4) 55 | } 56 | 57 | return buf 58 | } 59 | 60 | return Aes 61 | } 62 | 63 | inject = require('injecter')(inject, dependencies) 64 | let Aes = inject() 65 | module.exports = Aes 66 | -------------------------------------------------------------------------------- /lib/aescbc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Aescbc (experimental) 3 | * ===================== 4 | * 5 | * This is a convenience class for using Aes with Cbc. This is a low-level tool 6 | * that does not include authentication. You should only use this if you are 7 | * authenticating your data somehow else. 8 | */ 9 | 'use strict' 10 | let dependencies = { 11 | Aes: require('./aes'), 12 | Cbc: require('./cbc'), 13 | Random: require('./random') 14 | } 15 | 16 | let inject = function (deps) { 17 | let Aes = deps.Aes 18 | let Cbc = deps.Cbc 19 | let Random = deps.Random 20 | let Aescbc = {} 21 | 22 | Aescbc.encrypt = function (messageBuf, cipherKeyBuf, ivBuf) { 23 | ivBuf = ivBuf || Random.getRandomBuffer(128 / 8) 24 | let ctBuf = Cbc.encrypt(messageBuf, ivBuf, Aes, cipherKeyBuf) 25 | return Buffer.concat([ivBuf, ctBuf]) 26 | } 27 | 28 | Aescbc.decrypt = function (encBuf, cipherKeyBuf) { 29 | let ivBuf = encBuf.slice(0, 128 / 8) 30 | let ctBuf = encBuf.slice(128 / 8) 31 | return Cbc.decrypt(ctBuf, ivBuf, Aes, cipherKeyBuf) 32 | } 33 | 34 | return Aescbc 35 | } 36 | 37 | inject = require('injecter')(inject, dependencies) 38 | let Aescbc = inject() 39 | module.exports = Aescbc 40 | -------------------------------------------------------------------------------- /lib/base-58-check.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Base58 Check Encoding 3 | * ===================== 4 | * 5 | * Base58 check encoding. The usual way to use it is 6 | * new Base58Check(buf).toString() or new Base58Check(str).toBuffer(). 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Base58: require('./base-58'), 11 | cmp: require('./cmp'), 12 | Hash: require('./hash'), 13 | Struct: require('./struct') 14 | } 15 | 16 | let inject = function (deps) { 17 | let Base58 = deps.Base58 18 | let cmp = deps.cmp 19 | let Hash = deps.Hash 20 | let Struct = deps.Struct 21 | 22 | class Base58Check extends Struct { 23 | constructor (buf) { 24 | super({buf}) 25 | } 26 | 27 | fromHex (hex) { 28 | return this.fromBuffer(new Buffer(hex, 'hex')) 29 | } 30 | 31 | toHex () { 32 | return this.toBuffer().toString('hex') 33 | } 34 | 35 | static decode (s) { 36 | if (typeof s !== 'string') { 37 | throw new Error('Input must be a string') 38 | } 39 | 40 | let buf = Base58.decode(s) 41 | 42 | if (buf.length < 4) { 43 | throw new Error('Input string too short') 44 | } 45 | 46 | let data = buf.slice(0, -4) 47 | let csum = buf.slice(-4) 48 | 49 | let hash = Hash.sha256Sha256(data) 50 | let hash4 = hash.slice(0, 4) 51 | 52 | if (!cmp(csum, hash4)) { 53 | throw new Error('Checksum mismatch') 54 | } 55 | 56 | return data 57 | } 58 | 59 | static encode (buf) { 60 | if (!Buffer.isBuffer(buf)) { 61 | throw new Error('Input must be a buffer') 62 | } 63 | let checkedBuf = new Buffer(buf.length + 4) 64 | let hash = Hash.sha256Sha256(buf) 65 | buf.copy(checkedBuf) 66 | hash.copy(checkedBuf, buf.length) 67 | return Base58.encode(checkedBuf) 68 | } 69 | 70 | fromBuffer (buf) { 71 | this.buf = buf 72 | return this 73 | } 74 | 75 | fromString (str) { 76 | let buf = Base58Check.decode(str) 77 | this.buf = buf 78 | return this 79 | } 80 | 81 | toBuffer () { 82 | return this.buf 83 | } 84 | 85 | toString () { 86 | return Base58Check.encode(this.buf) 87 | } 88 | } 89 | 90 | return Base58Check 91 | } 92 | 93 | inject = require('injecter')(inject, dependencies) 94 | let Base58Check = inject() 95 | module.exports = Base58Check 96 | -------------------------------------------------------------------------------- /lib/base-58.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Base58 Encoding 3 | * =============== 4 | * 5 | * Base58 (no check) 6 | */ 7 | 'use strict' 8 | let dependencies = { 9 | bs58: require('bs58'), 10 | Struct: require('./struct') 11 | } 12 | 13 | let inject = function (deps) { 14 | let bs58 = deps.bs58 15 | let Struct = deps.Struct 16 | 17 | class Base58 extends Struct { 18 | constructor (buf) { 19 | super({buf}) 20 | } 21 | 22 | fromHex (hex) { 23 | return this.fromBuffer(new Buffer(hex, 'hex')) 24 | } 25 | 26 | toHex () { 27 | return this.toBuffer().toString('hex') 28 | } 29 | 30 | static encode (buf) { 31 | if (!Buffer.isBuffer(buf)) { 32 | throw new Error('Input should be a buffer') 33 | } 34 | return bs58.encode(buf) 35 | } 36 | 37 | static decode (str) { 38 | if (typeof str !== 'string') { 39 | throw new Error('Input should be a string') 40 | } 41 | return new Buffer(bs58.decode(str)) 42 | } 43 | 44 | fromBuffer (buf) { 45 | this.buf = buf 46 | return this 47 | } 48 | 49 | fromString (str) { 50 | let buf = Base58.decode(str) 51 | this.buf = buf 52 | return this 53 | } 54 | 55 | toBuffer () { 56 | return this.buf 57 | } 58 | 59 | toString () { 60 | return Base58.encode(this.buf) 61 | } 62 | } 63 | 64 | return Base58 65 | } 66 | 67 | inject = require('injecter')(inject, dependencies) 68 | let Base58 = inject() 69 | module.exports = Base58 70 | -------------------------------------------------------------------------------- /lib/bip-68.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bip68: Relative Lock-Time 3 | * ========================= 4 | * 5 | * Bip68 is an important change to the interpretation of sequence numbers in 6 | * transaction inputs (called nSequence in Yours Bitcoin). Originally, sequence 7 | * numbers specified which transaction was the most "up-to-date" version, but 8 | * they did so only insecurely. BEcause they were insecure, they were disabled, 9 | * and became and almost meanIngless piece of data. Opt-in RBF (Replace-By-Fee) 10 | * changed that slightly by interpreting non-maximal sequence numbers to be 11 | * replaceable with greater fees. Bip68 reinterprets sequence numbers entirely 12 | * as relative lock-time. If the sequence number, appropriately masked, is 13 | * lower than the number of blocks since the input transaction was confirmed, 14 | * then the transaction is invalid. 15 | * 16 | * This class will embody the code from the Bip68 spec. However, some of that 17 | * code requires full node support, which (ironically) Yours Bitcoin does not yet 18 | * support. So it will be finished when appropriate. 19 | * 20 | * These functions will need to be added to this class: 21 | * CalculateSequenceLocks 22 | * EvaluateSequenceLocks 23 | * SequenceLocks 24 | * CheckSequenceLocks 25 | */ 26 | 'use strict' 27 | 28 | let dependencies = { 29 | Struct: require('./struct'), 30 | TxIn: require('./tx-in') 31 | } 32 | 33 | let inject = function (deps) { 34 | let Struct = deps.Struct 35 | let TxIn = deps.TxIn 36 | 37 | class Bip68 extends Struct { 38 | static nSequence2Height (nSequence) { 39 | return nSequence & TxIn.SEQUENCE_LOCKTIME_MASK 40 | } 41 | 42 | // 0 <= height < 65,535 blocks (1.25 years) 43 | static height2NSequence (height) { 44 | return height 45 | } 46 | 47 | static nSequence2Time (nSequence) { 48 | return (nSequence & TxIn.SEQUENCE_LOCKTIME_MASK) << TxIn.SEQUENCE_LOCKTIME_GRANULARITY 49 | } 50 | 51 | // 0 <= time < 33,554,431 seconds (1.06 years) 52 | static time2NSequence (time) { 53 | return TxIn.SEQUENCE_LOCKTIME_TYPE_FLAG | (time >> TxIn.SEQUENCE_LOCKTIME_GRANULARITY) 54 | } 55 | 56 | /** 57 | * Whether Bip68 is disabled for this nSequence. 58 | */ 59 | static nSequenceIsDisabled (nSequence) { 60 | return (nSequence & TxIn.SEQUENCE_LOCKTIME_DISABLE_FLAG) !== 0 61 | } 62 | 63 | /** 64 | * true if time, false if height 65 | */ 66 | static nSequenceIsTime (nSequence) { 67 | return (nSequence & TxIn.SEQUENCE_LOCKTIME_TYPE_FLAG) !== 0 68 | } 69 | 70 | /** 71 | * Get the "value" masked out of this nSequence - can be converted to time or 72 | * height. 73 | */ 74 | static nSequenceValue (nSequence) { 75 | return nSequence & TxIn.SEQUENCE_LOCKTIME_MASK 76 | } 77 | } 78 | 79 | return Bip68 80 | } 81 | 82 | inject = require('injecter')(inject, dependencies) 83 | let Bip68 = inject() 84 | module.exports = Bip68 85 | -------------------------------------------------------------------------------- /lib/block-header.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Block Header 3 | * ============ 4 | * 5 | * Every block contains a blockHeader. This is probably not something you will 6 | * personally use, but it's here if you need it. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Bw: require('./bw'), 11 | Struct: require('./struct') 12 | } 13 | 14 | let inject = function (deps) { 15 | let Bw = deps.Bw 16 | let Struct = deps.Struct 17 | 18 | class BlockHeader extends Struct { 19 | constructor (versionBytesNum, prevBlockHashBuf, merkleRootBuf, time, bits, nonce) { 20 | super({versionBytesNum, prevBlockHashBuf, merkleRootBuf, time, bits, nonce}) 21 | } 22 | 23 | fromJSON (json) { 24 | this.fromObject({ 25 | versionBytesNum: json.versionBytesNum, 26 | prevBlockHashBuf: new Buffer(json.prevBlockHashBuf, 'hex'), 27 | merkleRootBuf: new Buffer(json.merkleRootBuf, 'hex'), 28 | time: json.time, 29 | bits: json.bits, 30 | nonce: json.nonce 31 | }) 32 | return this 33 | } 34 | 35 | toJSON () { 36 | return { 37 | versionBytesNum: this.versionBytesNum, 38 | prevBlockHashBuf: this.prevBlockHashBuf.toString('hex'), 39 | merkleRootBuf: this.merkleRootBuf.toString('hex'), 40 | time: this.time, 41 | bits: this.bits, 42 | nonce: this.nonce 43 | } 44 | } 45 | 46 | fromBr (br) { 47 | this.versionBytesNum = br.readUInt32LE() 48 | this.prevBlockHashBuf = br.read(32) 49 | this.merkleRootBuf = br.read(32) 50 | this.time = br.readUInt32LE() 51 | this.bits = br.readUInt32LE() 52 | this.nonce = br.readUInt32LE() 53 | return this 54 | } 55 | 56 | toBw (bw) { 57 | if (!bw) { 58 | bw = new Bw() 59 | } 60 | bw.writeUInt32LE(this.versionBytesNum) 61 | bw.write(this.prevBlockHashBuf) 62 | bw.write(this.merkleRootBuf) 63 | bw.writeUInt32LE(this.time) 64 | bw.writeUInt32LE(this.bits) 65 | bw.writeUInt32LE(this.nonce) 66 | return bw 67 | } 68 | } 69 | 70 | return BlockHeader 71 | } 72 | 73 | inject = require('injecter')(inject, dependencies) 74 | let BlockHeader = inject() 75 | module.exports = BlockHeader 76 | -------------------------------------------------------------------------------- /lib/cmp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Constant-Time Buffer Compare 3 | * ============================ 4 | * 5 | * A constant-time comparison function. This should be used in any security 6 | * sensitive code where leaking timing information may lead to lessened 7 | * security. Note that if the buffers are not equal in length, this function 8 | * loops for the longest buffer, which may not be necessary. Usually this 9 | * function should be used for buffers that would otherwise be equal length, 10 | * such as a hash, particularly Hmacs. 11 | * 12 | * The algorithm here, which is XORs each byte (or, if undefined, 0) with the 13 | * corresponding other byte, and then ORs that with a running total (d), is 14 | * adapted from here: 15 | * 16 | * https://groups.google.com/forum/#!topic/keyczar-discuss/VXHsoJSLKhM 17 | */ 18 | 'use strict' 19 | module.exports = function cmp (buf1, buf2) { 20 | if (!Buffer.isBuffer(buf1) || !Buffer.isBuffer(buf2)) { 21 | throw new Error('buf1 and buf2 must be buffers') 22 | } 23 | if (buf1.length !== buf2.length) { 24 | return false 25 | } 26 | 27 | let d = 0 28 | for (let i = 0; i < buf1.length; i++) { 29 | let x = buf1[i] 30 | let y = buf2[i] 31 | d |= (x ^ y) 32 | } 33 | 34 | return d === 0 35 | } 36 | -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Constants 3 | * ========= 4 | * 5 | * Constants used to distinguish mainnet from testnet. 6 | */ 7 | 'use strict' 8 | 9 | let Constants = module.exports 10 | 11 | Constants.Mainnet = { 12 | maxsize: 0x02000000, // MAX_SIZE 13 | Address: { 14 | pubKeyHash: 0x00, 15 | scriptHash: 0x05 16 | }, 17 | Bip32: { 18 | pubKey: 0x0488b21e, 19 | privKey: 0x0488ade4 20 | }, 21 | Block: { 22 | maxNBits: 0x1d00ffff, 23 | magicNum: 0xf9beb4d9 24 | }, 25 | Msg: { 26 | magicNum: 0xf9beb4d9, 27 | versionBytesNum: 70012 // as of Bitcoin Core v0.12.0 28 | }, 29 | PrivKey: { 30 | versionByteNum: 0x80 31 | }, 32 | StealthAddress: { 33 | versionByteNum: 42 34 | }, 35 | TxBuilder: { 36 | feePerKbNum: 0.0001e8, 37 | dustNum: 546 38 | } 39 | } 40 | 41 | Constants.Testnet = Object.assign({}, Constants.Mainnet, { 42 | Address: { 43 | pubKeyHash: 0x6f, 44 | scriptHash: 0xc4 45 | }, 46 | Bip32: { 47 | pubKey: 0x043587cf, 48 | privKey: 0x04358394 49 | }, 50 | Block: { 51 | maxNBits: 0x1d00ffff, 52 | magicNum: 0x0b110907 53 | }, 54 | Msg: { 55 | magicNum: 0x0b110907, 56 | versionBytesNum: 70012 // as of Bitcoin Core v0.12.0 57 | }, 58 | Network: { 59 | maxconnections: 20, 60 | minconnections: 8, 61 | port: 8333, 62 | rendezvous: { 63 | host: 'localhost', 64 | port: 3000, 65 | path: '/' 66 | } 67 | }, 68 | PrivKey: { 69 | versionByteNum: 0xef 70 | }, 71 | StealthAddress: { 72 | versionByteNum: 43 73 | } 74 | }) 75 | 76 | Constants.Regtest = Object.assign({}, Constants.Mainnet, { 77 | Network: { 78 | maxconnections: 20, 79 | minconnections: 8, 80 | port: 18444, 81 | rendezvous: { 82 | host: 'localhost', 83 | port: 3000, 84 | path: '/' 85 | } 86 | } 87 | }) 88 | 89 | /** 90 | * Yours Bitcoin can be globally configured to mainnet, testnet, or regtest. Via the 91 | * inject pattern, you always have access to the other networks at any time. 92 | * However, it is very convenient to be able to change the default 93 | * configuration. The default is mainnet, which can be changed to testnet or 94 | * regtest. 95 | */ 96 | if (process.env.YOURS_BITCOIN_NETWORK === 'testnet') { 97 | Constants.Default = Object.assign({}, Constants.Testnet) 98 | } else if (process.env.YOURS_BITCOIN_NETWORK === 'regtest') { 99 | Constants.Default = Object.assign({}, Constants.Regtest) 100 | } else { 101 | process.env.YOURS_BITCOIN_NETWORK = 'mainnet' 102 | Constants.Default = Object.assign({}, Constants.Mainnet) 103 | } 104 | -------------------------------------------------------------------------------- /lib/ecies.js: -------------------------------------------------------------------------------- 1 | /** Ecies (experimental) 2 | * ===================== 3 | * http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme 4 | */ 5 | 'use strict' 6 | let dependencies = { 7 | Aescbc: require('./aescbc'), 8 | cmp: require('./cmp'), 9 | Hash: require('./hash'), 10 | KeyPair: require('./key-pair'), 11 | Point: require('./point'), 12 | PubKey: require('./pub-key'), 13 | Random: require('./random'), 14 | Workers: require('./workers'), 15 | asink: require('asink') 16 | } 17 | 18 | let inject = function (deps) { 19 | let Aescbc = deps.Aescbc 20 | let cmp = deps.cmp 21 | let Hash = deps.Hash 22 | let KeyPair = deps.KeyPair 23 | let Point = deps.Point 24 | let PubKey = deps.PubKey 25 | let Random = deps.Random 26 | let Workers = deps.Workers 27 | let asink = deps.asink 28 | 29 | let Ecies = {} 30 | 31 | Ecies.encrypt = function (messageBuf, toPubKey, fromKeyPair, ivBuf) { 32 | if (!fromKeyPair) { 33 | fromKeyPair = KeyPair.fromRandom() 34 | } 35 | let r = fromKeyPair.privKey.bn 36 | let RPubKey = fromKeyPair.pubKey 37 | let RBuf = RPubKey.toDer(true) 38 | let KB = toPubKey.point 39 | let P = KB.mul(r) 40 | let S = P.getX() 41 | let Sbuf = S.toBuffer({size: 32}) 42 | let kEkM = Hash.sha512(Sbuf) 43 | let kE = kEkM.slice(0, 32) 44 | let kM = kEkM.slice(32, 64) 45 | let c = Aescbc.encrypt(messageBuf, kE, ivBuf) 46 | let d = Hash.sha256Hmac(c, kM) 47 | let encBuf = Buffer.concat([RBuf, c, d]) 48 | return encBuf 49 | } 50 | 51 | Ecies.asyncEncrypt = function (messageBuf, toPubKey, fromKeyPair, ivBuf) { 52 | return asink(function * () { 53 | if (!fromKeyPair) { 54 | fromKeyPair = yield KeyPair.asyncFromRandom() 55 | } 56 | if (!ivBuf) { 57 | ivBuf = Random.getRandomBuffer(128 / 8) 58 | } 59 | let args = [messageBuf, toPubKey, fromKeyPair, ivBuf] 60 | let workersResult = yield Workers.asyncClassMethod('Ecies', 'encrypt', args) 61 | return workersResult.resbuf 62 | }, this) 63 | } 64 | 65 | Ecies.decrypt = function (encBuf, toPrivKey) { 66 | let kB = toPrivKey.bn 67 | let fromPubKey = PubKey.fromDer(encBuf.slice(0, 33)) 68 | let R = fromPubKey.point 69 | let P = R.mul(kB) 70 | if (P.eq(new Point())) { 71 | throw new Error('P equals 0') 72 | } 73 | let S = P.getX() 74 | let Sbuf = S.toBuffer({size: 32}) 75 | let kEkM = Hash.sha512(Sbuf) 76 | let kE = kEkM.slice(0, 32) 77 | let kM = kEkM.slice(32, 64) 78 | let c = encBuf.slice(33, encBuf.length - 32) 79 | let d = encBuf.slice(encBuf.length - 32, encBuf.length) 80 | let d2 = Hash.sha256Hmac(c, kM) 81 | if (!cmp(d, d2)) { 82 | throw new Error('Invalid checksum') 83 | } 84 | let messageBuf = Aescbc.decrypt(c, kE) 85 | return messageBuf 86 | } 87 | 88 | Ecies.asyncDecrypt = function (encBuf, toPrivKey) { 89 | return asink(function * () { 90 | let args = [encBuf, toPrivKey] 91 | let workersResult = yield Workers.asyncClassMethod('Ecies', 'decrypt', args) 92 | return workersResult.resbuf 93 | }, this) 94 | } 95 | 96 | return Ecies 97 | } 98 | 99 | inject = require('injecter')(inject, dependencies) 100 | let Ecies = inject() 101 | Ecies.Mainnet = inject({ 102 | KeyPair: require('./key-pair').Mainnet 103 | }) 104 | Ecies.Testnet = inject({ 105 | KeyPair: require('./key-pair').Testnet 106 | }) 107 | module.exports = Ecies 108 | -------------------------------------------------------------------------------- /lib/get-blocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * GetBlocks 3 | * ========= 4 | * 5 | * The data structure used inside the "getblocks" p2p message. Contains a list 6 | * of block header haashes to be gotten. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Bw: require('./bw'), 11 | Constants: require('./constants').Default, 12 | Struct: require('./struct'), 13 | VarInt: require('./var-int') 14 | } 15 | 16 | let inject = function (deps) { 17 | let Bw = deps.Bw 18 | let Constants = deps.Constants 19 | let Struct = deps.Struct 20 | let VarInt = deps.VarInt 21 | 22 | class GetBlocks extends Struct { 23 | constructor (versionBytesNum = Constants.Msg.versionBytesNum, hashBufsVi, hashBufs, stopHashBuf) { 24 | super({versionBytesNum, hashBufsVi, hashBufs, stopHashBuf}) 25 | } 26 | 27 | toBw (bw) { 28 | if (!bw) { 29 | bw = new Bw() 30 | } 31 | bw.writeUInt32LE(this.versionBytesNum) 32 | bw.write(this.hashBufsVi.buf) 33 | for (let i = 0; i < this.hashBufs.lenth; i++) { 34 | bw.write(this.hashBufs[i]) 35 | } 36 | bw.write(this.stopHashBuf) 37 | return bw 38 | } 39 | 40 | fromBr (br) { 41 | this.versionBytesNum = br.readUInt32LE() 42 | this.hashBufsVi = new VarInt(br.readVarIntBuf()) 43 | let len = this.hashBufsVi.toNumber() 44 | this.hashBufs = [] 45 | for (let i = 0; i < len; i++) { 46 | this.hashBufs.push(br.read(32)) 47 | } 48 | this.stopHashBuf = br.read(32) 49 | return this 50 | } 51 | 52 | /** 53 | * The last hashBuf in the list is the stopHashBuf. 54 | */ 55 | fromHashes (hashBufs) { 56 | if (hashBufs.length < 1) { 57 | throw new Error('hashBufs must have at least one buffer, the stopHashBuf') 58 | } 59 | this.hashBufsVi = new VarInt().fromNumber(hashBufs.length - 1) 60 | this.hashBufs = hashBufs.slice(0, hashBufs.length - 1) 61 | this.stopHashBuf = hashBufs[hashBufs.length - 1] 62 | return this 63 | } 64 | 65 | static fromHashes (hashBufs) { 66 | return new this().fromHashes(hashBufs) 67 | } 68 | 69 | toHashes () { 70 | return this.hashBufs.concat(this.stopHashBuf) 71 | } 72 | } 73 | 74 | return GetBlocks 75 | } 76 | 77 | inject = require('injecter')(inject, dependencies) 78 | let GetBlocks = inject() 79 | module.exports = GetBlocks 80 | -------------------------------------------------------------------------------- /lib/inv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Inv 3 | * === 4 | * 5 | * Inventory - used in p2p messages. 6 | */ 7 | 'use strict' 8 | let dependencies = { 9 | Bw: require('./bw'), 10 | Struct: require('./struct') 11 | } 12 | 13 | let inject = function (deps) { 14 | let Bw = deps.Bw 15 | let Struct = deps.Struct 16 | 17 | class Inv extends Struct { 18 | constructor (typeNum, hashBuf) { 19 | super({typeNum, hashBuf}) 20 | } 21 | 22 | fromBr (br) { 23 | this.typeNum = br.readUInt32LE() 24 | this.hashBuf = br.read(32) 25 | return this 26 | } 27 | 28 | toBw (bw) { 29 | if (!bw) { 30 | bw = new Bw() 31 | } 32 | bw.writeUInt32LE(this.typeNum) 33 | bw.write(this.hashBuf) 34 | return bw 35 | } 36 | 37 | isTx () { 38 | return this.typeNum === Inv.MSG_TX 39 | } 40 | 41 | isBlock () { 42 | return this.typeNum === Inv.MSG_BLOCK 43 | } 44 | 45 | isFilteredBlock () { 46 | return this.typeNum === Inv.MSG_FILTERED_BLOCK 47 | } 48 | } 49 | 50 | Inv.MSG_TX = 1 51 | Inv.MSG_BLOCK = 2 52 | Inv.MSG_FILTERED_BLOCK = 3 53 | 54 | return Inv 55 | } 56 | 57 | inject = require('injecter')(inject, dependencies) 58 | let Inv = inject() 59 | module.exports = Inv 60 | -------------------------------------------------------------------------------- /lib/kdf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Kdf 3 | * === 4 | * 5 | * Kdf stands for "key derivation function". A key derivation function is a 6 | * function that converts random data into a properly formatted key that can be 7 | * used by a cryptographic function. The one you probably want to use is 8 | * Pbkdf2, although various other ones are provided as a convenience. 9 | */ 10 | 'use strict' 11 | let dependencies = { 12 | Bn: require('./bn'), 13 | Hash: require('./hash'), 14 | KeyPair: require('./key-pair'), 15 | pbkdf2: require('pbkdf2-compat'), 16 | Point: require('./point'), 17 | PrivKey: require('./priv-key') 18 | } 19 | 20 | let inject = function (deps) { 21 | let Bn = deps.Bn 22 | let Hash = deps.Hash 23 | let KeyPair = deps.KeyPair 24 | let pbkdf2 = deps.pbkdf2 25 | let Point = deps.Point 26 | let PrivKey = deps.PrivKey 27 | 28 | let Kdf = {} 29 | 30 | // Pbkdf2 31 | // http://tools.ietf.org/html/rfc2898#section-5.2 32 | // http://en.wikipedia.org/wiki/Pbkdf2 33 | Kdf.Pbkdf2 = function (passBuf, saltBuf, nIterations, keyLenBits, hashFStr) { 34 | if (!nIterations) { 35 | nIterations = 1 36 | } 37 | if (!keyLenBits) { 38 | keyLenBits = 512 39 | } 40 | if (!hashFStr) { 41 | hashFStr = 'sha512' 42 | } 43 | return pbkdf2.pbkdf2Sync(passBuf, saltBuf, nIterations, keyLenBits / 8, hashFStr) 44 | } 45 | 46 | Kdf.buf2KeyPair = function (buf) { 47 | return Kdf.sha256Hmac2KeyPair(buf) 48 | } 49 | 50 | Kdf.sha256Hmac2KeyPair = function (buf) { 51 | let privKey = Kdf.sha256Hmac2PrivKey(buf) 52 | let keyPair = new KeyPair().fromPrivKey(privKey) 53 | return keyPair 54 | } 55 | 56 | Kdf.sha256Hmac2PrivKey = function (buf) { 57 | let bn, hash 58 | let concat = new Buffer([]) 59 | do { 60 | hash = Hash.sha256Hmac(buf, concat) 61 | bn = new Bn().fromBuffer(hash) 62 | concat = Buffer.concat([concat, new Buffer(0)]) 63 | } while (!bn.lt(Point.getN())) 64 | return new PrivKey().fromBn(bn) 65 | } 66 | 67 | return Kdf 68 | } 69 | 70 | inject = require('injecter')(inject, dependencies) 71 | let Kdf = inject() 72 | Kdf.Mainnet = inject({ 73 | KeyPair: require('./key-pair').Mainnet, 74 | PrivKey: require('./priv-key').Mainnet 75 | }) 76 | Kdf.Testnet = inject({ 77 | KeyPair: require('./key-pair').Testnet, 78 | PrivKey: require('./priv-key').Testnet 79 | }) 80 | module.exports = Kdf 81 | -------------------------------------------------------------------------------- /lib/key-pair.js: -------------------------------------------------------------------------------- 1 | /** 2 | * KeyPair 3 | * ======= 4 | * 5 | * A keyPair is a collection of a private key and a public key. 6 | * let keyPair = new KeyPair().fromRandom() 7 | * let keyPair = new KeyPair().fromPrivKey(privKey) 8 | * let privKey = keyPair.privKey 9 | * let pubKey = keyPair.pubKey 10 | */ 11 | 'use strict' 12 | let dependencies = { 13 | PrivKey: require('./priv-key'), 14 | PubKey: require('./pub-key'), 15 | Struct: require('./struct'), 16 | Bw: require('./bw'), 17 | asink: require('asink') 18 | } 19 | 20 | let inject = function (deps) { 21 | let PrivKey = deps.PrivKey 22 | let PubKey = deps.PubKey 23 | let Struct = deps.Struct 24 | let Bw = deps.Bw 25 | let asink = deps.asink 26 | 27 | class KeyPair extends Struct { 28 | constructor (privKey, pubKey) { 29 | super({privKey, pubKey}) 30 | } 31 | 32 | fromJSON (json) { 33 | if (json.privKey) { 34 | this.privKey = PrivKey.fromJSON(json.privKey) 35 | } 36 | if (json.pubKey) { 37 | this.pubKey = PubKey.fromJSON(json.pubKey) 38 | } 39 | return this 40 | } 41 | /* 42 | toJSON () { 43 | let json = {} 44 | if (this.privKey && this.privKey !== undefined) { 45 | json.privKey = this.privKey.toJSON() 46 | } 47 | if (this.pubKey && this.pubKey !== undefined) { 48 | json.pubKey = this.pubKey.toJSON() 49 | } 50 | return json 51 | } 52 | */ 53 | fromBr (br) { 54 | let buflen1 = br.readUInt8() 55 | if (buflen1 > 0) { 56 | this.privKey = new PrivKey().fromFastBuffer(br.read(buflen1)) 57 | } 58 | let buflen2 = br.readUInt8() 59 | if (buflen2 > 0) { 60 | this.pubKey = new PubKey().fromFastBuffer(br.read(buflen2)) 61 | } 62 | return this 63 | } 64 | 65 | toBw (bw) { 66 | if (!bw) { 67 | bw = new Bw() 68 | } 69 | if (this.privKey) { 70 | let privKeybuf = this.privKey.toFastBuffer() 71 | bw.writeUInt8(privKeybuf.length) 72 | bw.write(privKeybuf) 73 | } else { 74 | bw.writeUInt8(0) 75 | } 76 | if (this.pubKey) { 77 | let pubKeybuf = this.pubKey.toFastBuffer() 78 | bw.writeUInt8(pubKeybuf.length) 79 | bw.write(pubKeybuf) 80 | } else { 81 | bw.writeUInt8(0) 82 | } 83 | return bw 84 | } 85 | 86 | fromString (str) { 87 | return this.fromJSON(JSON.parse(str)) 88 | } 89 | 90 | toString () { 91 | return JSON.stringify(this.toJSON()) 92 | } 93 | 94 | toPublic () { 95 | let keyPair = new KeyPair().fromObject(this) 96 | keyPair.privKey = undefined 97 | return keyPair 98 | } 99 | 100 | fromPrivKey (privKey) { 101 | this.privKey = privKey 102 | this.pubKey = new PubKey().fromPrivKey(privKey) 103 | return this 104 | } 105 | 106 | static fromPrivKey (privKey) { 107 | return new this().fromPrivKey(privKey) 108 | } 109 | 110 | asyncFromPrivKey (privKey) { 111 | return asink(function * () { 112 | this.privKey = privKey 113 | this.pubKey = yield new PubKey().asyncFromPrivKey(privKey) 114 | return this 115 | }, this) 116 | } 117 | 118 | static asyncFromPrivKey (privKey) { 119 | return new this().asyncFromPrivKey(privKey) 120 | } 121 | 122 | fromRandom () { 123 | this.privKey = new PrivKey().fromRandom() 124 | this.pubKey = new PubKey().fromPrivKey(this.privKey) 125 | return this 126 | } 127 | 128 | static fromRandom () { 129 | return new this().fromRandom() 130 | } 131 | 132 | asyncFromRandom () { 133 | return asink(function * () { 134 | this.privKey = new PrivKey().fromRandom() 135 | return this.asyncFromPrivKey(this.privKey) 136 | }, this) 137 | } 138 | 139 | static asyncFromRandom () { 140 | return new this().asyncFromRandom() 141 | } 142 | } 143 | 144 | return KeyPair 145 | } 146 | 147 | inject = require('injecter')(inject, dependencies) 148 | let KeyPair = inject() 149 | KeyPair.Mainnet = inject({ 150 | PrivKey: require('./priv-key').Mainnet 151 | }) 152 | KeyPair.Testnet = inject({ 153 | PrivKey: require('./priv-key').Testnet 154 | }) 155 | module.exports = KeyPair 156 | -------------------------------------------------------------------------------- /lib/merkle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Merkle 3 | * ====== 4 | * 5 | * A node in a Merkle tree (possibly the root node, in which case it is the 6 | * Merkle root). A node either contains a buffer or links to two other nodes. 7 | */ 8 | 'use strict' 9 | 10 | let dependencies = { 11 | Hash: require('./hash'), 12 | Struct: require('./struct') 13 | } 14 | 15 | let inject = function (deps) { 16 | let Hash = deps.Hash 17 | let Struct = deps.Struct 18 | 19 | class Merkle extends Struct { 20 | constructor (hashBuf, buf, merkle1, merkle2) { 21 | super({hashBuf, buf, merkle1, merkle2}) 22 | } 23 | 24 | hash () { 25 | if (this.hashBuf) { 26 | return this.hashBuf 27 | } 28 | if (this.buf) { 29 | return Hash.sha256Sha256(this.buf) 30 | } 31 | let hashBuf1 = this.merkle1.hash() 32 | let hashBuf2 = this.merkle2.hash() 33 | this.buf = Buffer.concat([hashBuf1, hashBuf2]) 34 | return Hash.sha256Sha256(this.buf) 35 | } 36 | 37 | fromBuffers (bufs) { 38 | if (bufs.length < 1) { 39 | throw new Error('buffers must have a length') 40 | } 41 | bufs = bufs.slice() 42 | let log = Math.log2(bufs.length) 43 | if (!Number.isInteger(log)) { 44 | // If a merkle tree does not have a number of ends that is a power of 2, 45 | // then we have to copy the last value until it is a power of 2. Note 46 | // that we copy *the actual object* over and over again, which ensures 47 | // that when we finds its hash, the hash is cached. 48 | let lastval = bufs[bufs.length - 1] 49 | var len = Math.pow(2, Math.ceil(log)) 50 | for (let i = bufs.length; i < len; i++) { 51 | bufs.push(lastval) 52 | } 53 | } 54 | let bufs1 = bufs.slice(0, bufs.length / 2) 55 | let bufs2 = bufs.slice(bufs.length / 2) 56 | this.fromBufferArrays(bufs1, bufs2) 57 | return this 58 | } 59 | 60 | static fromBuffers (bufs) { 61 | return new this().fromBuffers(bufs) 62 | } 63 | 64 | /** 65 | * Takes two arrays, both of which *must* be of a length that is a power of 66 | * two. 67 | */ 68 | fromBufferArrays (bufs1, bufs2) { 69 | if (bufs1.length === 1) { 70 | this.merkle1 = new Merkle(undefined, bufs1[0]) 71 | this.merkle2 = new Merkle(undefined, bufs2[0]) 72 | return this 73 | } 74 | let bufs11 = bufs1.slice(0, bufs1.length / 2) 75 | let bufs12 = bufs1.slice(bufs1.length / 2) 76 | this.merkle1 = new Merkle().fromBufferArrays(bufs11, bufs12) 77 | let bufs21 = bufs2.slice(0, bufs2.length / 2) 78 | let bufs22 = bufs2.slice(bufs2.length / 2) 79 | this.merkle2 = new Merkle().fromBufferArrays(bufs21, bufs22) 80 | return this 81 | } 82 | 83 | static fromBufferArrays (bufs1, bufs2) { 84 | return new this().fromBufferArrays(bufs1, bufs2) 85 | } 86 | 87 | leavesNum () { 88 | if (this.merkle1) { 89 | return this.merkle1.leavesNum() + this.merkle2.leavesNum() 90 | } 91 | if (this.buf) { 92 | return 1 93 | } 94 | throw new Error('invalid number of leaves') 95 | } 96 | } 97 | 98 | return Merkle 99 | } 100 | 101 | inject = require('injecter')(inject, dependencies) 102 | let Merkle = inject() 103 | module.exports = Merkle 104 | -------------------------------------------------------------------------------- /lib/msg-addr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgAddr 3 | * ====== 4 | * 5 | * Sends a a list of addrs (IP addresses) of nodes we are connected to. 6 | */ 7 | 'use strict' 8 | let dependencies = { 9 | Addr: require('./addr'), 10 | Br: require('./br'), 11 | Bw: require('./bw'), 12 | Msg: require('./msg') 13 | } 14 | 15 | let inject = function (deps) { 16 | let Addr = deps.Addr 17 | let Br = deps.Br 18 | let Bw = deps.Bw 19 | let Msg = deps.Msg 20 | 21 | class MsgAddr extends Msg { 22 | initialize () { 23 | Msg.prototype.initialize.call(this) 24 | this.setCmd('addr') 25 | return this 26 | } 27 | 28 | static dataBufFromAddrs (addrs) { 29 | let bw = new Bw() 30 | bw.writeVarIntNum(addrs.length) 31 | for (let i = 0; i < addrs.length; i++) { 32 | bw.write(addrs[i].toBuffer()) 33 | } 34 | return bw.toBuffer() 35 | } 36 | 37 | fromAddrs (addrs) { 38 | this.setData(MsgAddr.dataBufFromAddrs(addrs)) 39 | return this 40 | } 41 | 42 | static fromAddrs (addrs) { 43 | return new this().fromAddrs(addrs) 44 | } 45 | 46 | asyncFromAddrs (addrs) { 47 | return this.asyncSetData(MsgAddr.dataBufFromAddrs(addrs)) 48 | } 49 | 50 | static asyncFromAddrs (addrs) { 51 | return new this().asyncFromAddrs(addrs) 52 | } 53 | 54 | toAddrs () { 55 | let br = new Br(this.dataBuf) 56 | let len = br.readVarIntNum() 57 | let addrs = [] 58 | for (let i = 0; i < len; i++) { 59 | let addrbuf = br.read(4 + 8 + 16 + 2) 60 | let addr = new Addr().fromBuffer(addrbuf) 61 | addrs.push(addr) 62 | } 63 | return addrs 64 | } 65 | 66 | isValid () { 67 | return this.getCmd() === 'addr' 68 | } 69 | } 70 | 71 | return MsgAddr 72 | } 73 | 74 | inject = require('injecter')(inject, dependencies) 75 | let MsgAddr = inject() 76 | MsgAddr.Mainnet = inject({ 77 | Msg: require('./msg').Mainnet 78 | }) 79 | MsgAddr.Testnet = inject({ 80 | Msg: require('./msg').Testnet 81 | }) 82 | module.exports = MsgAddr 83 | -------------------------------------------------------------------------------- /lib/msg-alert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgAlert 3 | * ====== 4 | * 5 | * An alert sent across the network by a developer with access to a primary 6 | * private key. Since this message type is almost entirely unused and will be 7 | * removed from bitcoin soon, it is not fully implemented here. 8 | */ 9 | 'use strict' 10 | let dependencies = { 11 | Msg: require('./msg') 12 | } 13 | 14 | let inject = function (deps) { 15 | let Msg = deps.Msg 16 | 17 | class MsgAlert extends Msg { 18 | initialize () { 19 | Msg.prototype.initialize.call(this) 20 | this.setCmd('alert') 21 | return this 22 | } 23 | 24 | isValid () { 25 | return this.getCmd() === 'alert' 26 | } 27 | } 28 | 29 | return MsgAlert 30 | } 31 | 32 | inject = require('injecter')(inject, dependencies) 33 | let MsgAlert = inject() 34 | MsgAlert.Mainnet = inject({ 35 | Msg: require('./msg').Mainnet 36 | }) 37 | MsgAlert.Testnet = inject({ 38 | Msg: require('./msg').Testnet 39 | }) 40 | module.exports = MsgAlert 41 | -------------------------------------------------------------------------------- /lib/msg-block.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgBlock 3 | * ======== 4 | * 5 | * Sends one block. 6 | */ 7 | 'use strict' 8 | let dependencies = { 9 | Block: require('./block'), 10 | Msg: require('./msg') 11 | } 12 | 13 | let inject = function (deps) { 14 | let Block = deps.Block 15 | let Msg = deps.Msg 16 | 17 | class MsgBlock extends Msg { 18 | initialize () { 19 | Msg.prototype.initialize.call(this) 20 | this.setCmd('block') 21 | return this 22 | } 23 | 24 | fromBlock (block) { 25 | this.setData(block.toBuffer()) 26 | return this 27 | } 28 | 29 | static fromBlock (block) { 30 | return new this().fromBlock(block) 31 | } 32 | 33 | asyncFromBlock (block) { 34 | return this.asyncSetData(block.toBuffer()) 35 | } 36 | 37 | static asyncFromBlock (block) { 38 | return new this().asyncFromBlock(block) 39 | } 40 | 41 | toBlock () { 42 | return new Block().fromBuffer(this.dataBuf) 43 | } 44 | 45 | isValid () { 46 | return this.getCmd() === 'block' 47 | } 48 | } 49 | 50 | return MsgBlock 51 | } 52 | 53 | inject = require('injecter')(inject, dependencies) 54 | let MsgBlock = inject() 55 | MsgBlock.Mainnet = inject({ 56 | Block: require('./block').Mainnet, 57 | Msg: require('./msg').Mainnet 58 | }) 59 | MsgBlock.Testnet = inject({ 60 | Block: require('./block').Testnet, 61 | Msg: require('./msg').Testnet 62 | }) 63 | module.exports = MsgBlock 64 | -------------------------------------------------------------------------------- /lib/msg-get-addr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgGetAddr 3 | * ========== 4 | * 5 | * Requests an addr message. This message has no data (dataBuf), and as such is 6 | * very simple. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Msg: require('./msg') 11 | } 12 | 13 | let inject = function (deps) { 14 | let Msg = deps.Msg 15 | 16 | class MsgGetAddr extends Msg { 17 | initialize () { 18 | Msg.prototype.initialize.call(this) 19 | this.setCmd('getaddr') 20 | this.datasize = 0 21 | this.dataBuf = new Buffer(0) 22 | this.checksumbuf = new Buffer('5df6e0e2', 'hex') 23 | return this 24 | } 25 | 26 | isValid () { 27 | return this.getCmd() === 'getaddr' && this.dataBuf.length === 0 28 | } 29 | } 30 | 31 | return MsgGetAddr 32 | } 33 | 34 | inject = require('injecter')(inject, dependencies) 35 | let MsgGetAddr = inject() 36 | MsgGetAddr.Mainnet = inject({ 37 | Msg: require('./msg').Mainnet 38 | }) 39 | MsgGetAddr.Testnet = inject({ 40 | Msg: require('./msg').Testnet 41 | }) 42 | module.exports = MsgGetAddr 43 | -------------------------------------------------------------------------------- /lib/msg-get-blocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgGetBlocks 3 | * ============ 4 | * 5 | * Gets what blocks are available from a given peer. 6 | */ 7 | 'use strict' 8 | let dependencies = { 9 | GetBlocks: require('./get-blocks'), 10 | Msg: require('./msg'), 11 | asink: require('asink') 12 | } 13 | 14 | let inject = function (deps) { 15 | let GetBlocks = deps.GetBlocks 16 | let Msg = deps.Msg 17 | let asink = deps.asink 18 | 19 | class MsgGetBlocks extends Msg { 20 | initialize () { 21 | Msg.prototype.initialize.call(this) 22 | this.setCmd('getblocks') 23 | return this 24 | } 25 | 26 | fromGetBlocks (getblocks) { 27 | return this.setData(getblocks.toBuffer()) 28 | } 29 | 30 | static fromGetBlocks (getblocks) { 31 | return new this().fromGetBlocks(getblocks) 32 | } 33 | 34 | fromHashes (hashes) { 35 | let getblocks = new GetBlocks().fromHashes(hashes) 36 | return this.fromGetBlocks(getblocks) 37 | } 38 | 39 | static fromHashes (hashes) { 40 | return new this().fromHashes(hashes) 41 | } 42 | 43 | asyncFromGetBlocks (getblocks) { 44 | return this.asyncSetData(getblocks.toBuffer()) 45 | } 46 | 47 | static asyncFromGetBlocks (getblocks) { 48 | return new this().asyncFromGetBlocks(getblocks) 49 | } 50 | 51 | asyncFromHashes (hashes) { 52 | return asink(function * () { 53 | let getblocks = new GetBlocks().fromHashes(hashes) 54 | return this.asyncFromGetBlocks(getblocks) 55 | }, this) 56 | } 57 | 58 | static asyncFromHashes (hashes) { 59 | return new this().asyncFromHashes(hashes) 60 | } 61 | 62 | toGetBlocks () { 63 | return new GetBlocks().fromBuffer(this.dataBuf) 64 | } 65 | 66 | toHashes () { 67 | return new GetBlocks().fromBuffer(this.dataBuf).toHashes() 68 | } 69 | 70 | isValid () { 71 | return this.getCmd() === 'getblocks' 72 | } 73 | } 74 | 75 | return MsgGetBlocks 76 | } 77 | 78 | inject = require('injecter')(inject, dependencies) 79 | let MsgGetBlocks = inject() 80 | MsgGetBlocks.Mainnet = inject({ 81 | Block: require('./block').Mainnet, 82 | Msg: require('./msg').Mainnet 83 | }) 84 | MsgGetBlocks.Testnet = inject({ 85 | Block: require('./block').Testnet, 86 | Msg: require('./msg').Testnet 87 | }) 88 | module.exports = MsgGetBlocks 89 | -------------------------------------------------------------------------------- /lib/msg-get-data.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgGetData 3 | * ========== 4 | * 5 | * This is identical to MsgInv, except the command is "getdata", and it is used 6 | * in slightly different cases. As such as simply inherit from MsgInv. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | MsgInv: require('./msg-inv') 11 | } 12 | 13 | let inject = function (deps) { 14 | let MsgInv = deps.MsgInv 15 | 16 | class MsgGetData extends MsgInv { 17 | initialize () { 18 | MsgInv.prototype.initialize.call(this) 19 | this.setCmd('getdata') 20 | return this 21 | } 22 | 23 | isValid () { 24 | return this.getCmd() === 'getdata' 25 | } 26 | } 27 | 28 | return MsgGetData 29 | } 30 | 31 | inject = require('injecter')(inject, dependencies) 32 | let MsgGetData = inject() 33 | MsgGetData.Mainnet = inject({ 34 | MsgInv: require('./msg-inv').Mainnet 35 | }) 36 | MsgGetData.Testnet = inject({ 37 | MsgInv: require('./msg-inv').Testnet 38 | }) 39 | module.exports = MsgGetData 40 | -------------------------------------------------------------------------------- /lib/msg-get-headers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgGetHeaders 3 | * ============= 4 | * 5 | * This is identical to MsgGetBlocks, except the command is "getheaders", and 6 | * it is used in slightly different cases. As such as simply inherit from 7 | * MsgGetBlocks. 8 | */ 9 | 'use strict' 10 | let dependencies = { 11 | MsgGetBlocks: require('./msg-get-blocks') 12 | } 13 | 14 | let inject = function (deps) { 15 | let MsgGetBlocks = deps.MsgGetBlocks 16 | 17 | function MsgGetHeaders (magicNum, cmdbuf, datasize, checksumbuf, dataBuf) { 18 | if (!(this instanceof MsgGetHeaders)) { 19 | return new MsgGetHeaders(magicNum, cmdbuf, datasize, checksumbuf, dataBuf) 20 | } 21 | this.initialize() 22 | this.fromObject({magicNum, cmdbuf, datasize, checksumbuf, dataBuf}) 23 | } 24 | 25 | MsgGetHeaders.prototype = Object.create(MsgGetBlocks.prototype) 26 | MsgGetHeaders.prototype.constructor = MsgGetHeaders 27 | 28 | MsgGetHeaders.prototype.initialize = function () { 29 | MsgGetBlocks.prototype.initialize.call(this) 30 | this.setCmd('getheaders') 31 | return this 32 | } 33 | 34 | MsgGetHeaders.prototype.isValid = function () { 35 | return this.getCmd() === 'getheaders' 36 | } 37 | 38 | return MsgGetHeaders 39 | } 40 | 41 | inject = require('injecter')(inject, dependencies) 42 | let MsgGetHeaders = inject() 43 | MsgGetHeaders.Mainnet = inject({ 44 | MsgGetBlocks: require('./msg-get-blocks').Mainnet 45 | }) 46 | MsgGetHeaders.Testnet = inject({ 47 | MsgGetBlocks: require('./msg-get-blocks').Testnet 48 | }) 49 | module.exports = MsgGetHeaders 50 | -------------------------------------------------------------------------------- /lib/msg-headers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgHeaders 3 | * ========== 4 | * 5 | * Sends a list of block headers. 6 | */ 7 | 'use strict' 8 | let dependencies = { 9 | BlockHeader: require('./block-header'), 10 | Br: require('./br'), 11 | Bw: require('./bw'), 12 | Msg: require('./msg') 13 | } 14 | 15 | let inject = function (deps) { 16 | let BlockHeader = deps.BlockHeader 17 | let Br = deps.Br 18 | let Bw = deps.Bw 19 | let Msg = deps.Msg 20 | 21 | class MsgHeaders extends Msg { 22 | initialize () { 23 | Msg.prototype.initialize.call(this) 24 | this.setCmd('headers') 25 | return this 26 | } 27 | 28 | static dataBufFromBlockHeaders (blockHeaders) { 29 | let bw = new Bw() 30 | bw.writeVarIntNum(blockHeaders.length) 31 | for (let i = 0; i < blockHeaders.length; i++) { 32 | bw.write(blockHeaders[i].toBuffer()) 33 | } 34 | return bw.toBuffer() 35 | } 36 | 37 | fromBlockHeaders (blockHeaders) { 38 | this.setData(MsgHeaders.dataBufFromBlockHeaders(blockHeaders)) 39 | return this 40 | } 41 | 42 | static fromBlockHeaders (blockHeaders) { 43 | return new this().fromBlockHeaders(blockHeaders) 44 | } 45 | 46 | asyncFromBlockHeaders (blockHeaders) { 47 | return this.asyncSetData(MsgHeaders.dataBufFromBlockHeaders(blockHeaders)) 48 | } 49 | 50 | toBlockHeaders () { 51 | let br = new Br(this.dataBuf) 52 | let len = br.readVarIntNum() 53 | let blockHeaders = [] 54 | for (let i = 0; i < len; i++) { 55 | let blockHeaderbuf = br.read(80) 56 | let blockHeader = new BlockHeader().fromBuffer(blockHeaderbuf) 57 | blockHeaders.push(blockHeader) 58 | } 59 | return blockHeaders 60 | } 61 | 62 | isValid () { 63 | return this.getCmd() === 'headers' 64 | } 65 | } 66 | 67 | return MsgHeaders 68 | } 69 | 70 | inject = require('injecter')(inject, dependencies) 71 | let MsgHeaders = inject() 72 | MsgHeaders.Mainnet = inject({ 73 | Msg: require('./msg').Mainnet 74 | }) 75 | MsgHeaders.Testnet = inject({ 76 | Msg: require('./msg').Testnet 77 | }) 78 | module.exports = MsgHeaders 79 | -------------------------------------------------------------------------------- /lib/msg-inv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgInv 3 | * ====== 4 | * 5 | * Sends an inventory, or list of "inv" structures, i.e. a list of objects that 6 | * we have. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Br: require('./br'), 11 | Bw: require('./bw'), 12 | Inv: require('./inv'), 13 | Msg: require('./msg') 14 | } 15 | 16 | let inject = function (deps) { 17 | let Br = deps.Br 18 | let Bw = deps.Bw 19 | let Inv = deps.Inv 20 | let Msg = deps.Msg 21 | 22 | class MsgInv extends Msg { 23 | initialize () { 24 | Msg.prototype.initialize.call(this) 25 | this.setCmd('inv') 26 | return this 27 | } 28 | 29 | static dataBufFromInvs (invs) { 30 | let bw = new Bw() 31 | bw.writeVarIntNum(invs.length) 32 | for (let i = 0; i < invs.length; i++) { 33 | bw.write(invs[i].toBuffer()) 34 | } 35 | return bw.toBuffer() 36 | } 37 | 38 | fromInvs (invs) { 39 | this.setData(MsgInv.dataBufFromInvs(invs)) 40 | return this 41 | } 42 | 43 | static fromInvs (invs) { 44 | return new this().fromInvs(invs) 45 | } 46 | 47 | asyncFromInvs (invs) { 48 | return this.asyncSetData(MsgInv.dataBufFromInvs(invs)) 49 | } 50 | 51 | static asyncFromInvs (invs) { 52 | return new this().asyncFromInvs(invs) 53 | } 54 | 55 | toInvs () { 56 | let br = new Br(this.dataBuf) 57 | let len = br.readVarIntNum() 58 | let invs = [] 59 | for (let i = 0; i < len; i++) { 60 | let invbuf = br.read(4 + 32) 61 | let inv = new Inv().fromBuffer(invbuf) 62 | invs.push(inv) 63 | } 64 | return invs 65 | } 66 | 67 | isValid () { 68 | return this.getCmd() === 'inv' 69 | } 70 | } 71 | 72 | return MsgInv 73 | } 74 | 75 | inject = require('injecter')(inject, dependencies) 76 | let MsgInv = inject() 77 | MsgInv.Mainnet = inject({ 78 | Msg: require('./msg').Mainnet 79 | }) 80 | MsgInv.Testnet = inject({ 81 | Msg: require('./msg').Testnet 82 | }) 83 | module.exports = MsgInv 84 | -------------------------------------------------------------------------------- /lib/msg-mem-pool.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgMemPool 3 | * ========== 4 | * 5 | * Requests transactions in the mempool. This message has no data (dataBuf), 6 | * and as such is very simple. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Msg: require('./msg') 11 | } 12 | 13 | let inject = function (deps) { 14 | let Msg = deps.Msg 15 | 16 | class MsgMemPool extends Msg { 17 | initialize () { 18 | Msg.prototype.initialize.call(this) 19 | this.setCmd('mempool') 20 | this.datasize = 0 21 | this.dataBuf = new Buffer(0) 22 | this.checksumbuf = new Buffer('5df6e0e2', 'hex') 23 | return this 24 | } 25 | 26 | isValid () { 27 | return this.getCmd() === 'mempool' && this.dataBuf.length === 0 28 | } 29 | } 30 | 31 | return MsgMemPool 32 | } 33 | 34 | inject = require('injecter')(inject, dependencies) 35 | let MsgMemPool = inject() 36 | MsgMemPool.Mainnet = inject({ 37 | Msg: require('./msg').Mainnet 38 | }) 39 | MsgMemPool.Testnet = inject({ 40 | Msg: require('./msg').Testnet 41 | }) 42 | module.exports = MsgMemPool 43 | -------------------------------------------------------------------------------- /lib/msg-not-found.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgNotFound 3 | * =========== 4 | * 5 | * Sent when requested data is not found. This is identical to MsgInv, except 6 | * the command is "notfound", and it is used in slightly different cases. As 7 | * such it simply inherits from MsgInv. 8 | */ 9 | 'use strict' 10 | let dependencies = { 11 | MsgInv: require('./msg-inv') 12 | } 13 | 14 | let inject = function (deps) { 15 | let MsgInv = deps.MsgInv 16 | 17 | class MsgNotFound extends MsgInv { 18 | initialize () { 19 | MsgInv.prototype.initialize.call(this) 20 | this.setCmd('notfound') 21 | return this 22 | } 23 | 24 | isValid () { 25 | return this.getCmd() === 'notfound' 26 | } 27 | } 28 | 29 | return MsgNotFound 30 | } 31 | 32 | inject = require('injecter')(inject, dependencies) 33 | let MsgNotFound = inject() 34 | MsgNotFound.Mainnet = inject({ 35 | MsgInv: require('./msg-inv').Mainnet 36 | }) 37 | MsgNotFound.Testnet = inject({ 38 | MsgInv: require('./msg-inv').Testnet 39 | }) 40 | module.exports = MsgNotFound 41 | -------------------------------------------------------------------------------- /lib/msg-ping.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgPing 3 | * ======= 4 | * 5 | * A ping p2p message. This is defined as a msg with command "ping" and where 6 | * dataBuf is a randomly selected 8 byte buffer. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Msg: require('./msg'), 11 | Random: require('./random') 12 | } 13 | 14 | let inject = function (deps) { 15 | let Msg = deps.Msg 16 | let Random = deps.Random 17 | 18 | class MsgPing extends Msg { 19 | initialize () { 20 | Msg.prototype.initialize.call(this) 21 | this.setCmd('ping') 22 | return this 23 | } 24 | 25 | fromRandom () { 26 | this.setData(Random.getRandomBuffer(8)) 27 | return this 28 | } 29 | 30 | static fromRandom () { 31 | return new this().fromRandom() 32 | } 33 | 34 | asyncFromRandom () { 35 | return this.asyncSetData(Random.getRandomBuffer(8)) 36 | } 37 | 38 | static asyncFromRandom () { 39 | return new this().asyncFromRandom() 40 | } 41 | 42 | isValid () { 43 | return this.dataBuf.length === 8 && this.getCmd() === 'ping' 44 | } 45 | } 46 | 47 | return MsgPing 48 | } 49 | 50 | inject = require('injecter')(inject, dependencies) 51 | let MsgPing = inject() 52 | MsgPing.Mainnet = inject({ 53 | Msg: require('./msg').Mainnet 54 | }) 55 | MsgPing.Testnet = inject({ 56 | Msg: require('./msg').Testnet 57 | }) 58 | module.exports = MsgPing 59 | -------------------------------------------------------------------------------- /lib/msg-pong.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgPong 3 | * ======= 4 | * 5 | * A pong message on the p2p network is a reponse to a ping. A pong is almost 6 | * the same as a ping, in that it contains a randomly selected 8 byte dataBuf. 7 | * The dataBuf is always the same as the ping it is responding to. And also, 8 | * the command is set to "pong" instead of "ping". 9 | */ 10 | 'use strict' 11 | let dependencies = { 12 | Msg: require('./msg') 13 | } 14 | 15 | let inject = function (deps) { 16 | let Msg = deps.Msg 17 | 18 | class MsgPong extends Msg { 19 | initialize () { 20 | Msg.prototype.initialize.call(this) 21 | this.setCmd('pong') 22 | return this 23 | } 24 | 25 | fromMsgPing (msgping) { 26 | this.fromObject(msgping) 27 | this.setCmd('pong') 28 | return this 29 | } 30 | 31 | static fromMsgPing (msgping) { 32 | return new this().fromMsgPing(msgping) 33 | } 34 | 35 | isValid () { 36 | return this.dataBuf.length === 8 && this.getCmd() === 'pong' 37 | } 38 | } 39 | 40 | return MsgPong 41 | } 42 | 43 | inject = require('injecter')(inject, dependencies) 44 | let MsgPong = inject() 45 | MsgPong.Mainnet = inject({ 46 | Msg: require('./msg').Mainnet 47 | }) 48 | MsgPong.Testnet = inject({ 49 | Msg: require('./msg').Testnet 50 | }) 51 | module.exports = MsgPong 52 | -------------------------------------------------------------------------------- /lib/msg-reject.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgReject 3 | * ============ 4 | * 5 | * Sent when a message is rejected, analous to a "404" or other HTTP error. 6 | * Conveys the reason why the message was rejected. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Reject: require('./reject'), 11 | Msg: require('./msg') 12 | } 13 | 14 | let inject = function (deps) { 15 | let Reject = deps.Reject 16 | let Msg = deps.Msg 17 | 18 | class MsgReject extends Msg { 19 | initialize () { 20 | Msg.prototype.initialize.call(this) 21 | this.setCmd('reject') 22 | return this 23 | } 24 | 25 | fromReject (reject) { 26 | return this.setData(reject.toBuffer()) 27 | } 28 | 29 | static fromReject (reject) { 30 | return new this().fromReject(reject) 31 | } 32 | 33 | asyncFromReject (reject) { 34 | return this.asyncSetData(reject.toBuffer()) 35 | } 36 | 37 | static asyncFromReject (reject) { 38 | return new this().asyncFromReject(reject) 39 | } 40 | 41 | toReject () { 42 | return new Reject().fromBuffer(this.dataBuf) 43 | } 44 | 45 | isValid () { 46 | return this.getCmd() === 'reject' 47 | } 48 | } 49 | 50 | return MsgReject 51 | } 52 | 53 | inject = require('injecter')(inject, dependencies) 54 | let MsgReject = inject() 55 | MsgReject.Mainnet = inject({ 56 | Msg: require('./msg').Mainnet 57 | }) 58 | MsgReject.Testnet = inject({ 59 | Msg: require('./msg').Testnet 60 | }) 61 | module.exports = MsgReject 62 | -------------------------------------------------------------------------------- /lib/msg-send-headers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgSendHeaders 3 | * ============== 4 | * 5 | * Tell peer to send block announcements using a "headers" message rather than 6 | * an "inv" message. This message has no data. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Msg: require('./msg') 11 | } 12 | 13 | let inject = function (deps) { 14 | let Msg = deps.Msg 15 | 16 | class MsgSendHeaders extends Msg { 17 | initialize () { 18 | Msg.prototype.initialize.call(this) 19 | this.setCmd('sendheaders') 20 | this.datasize = 0 21 | this.dataBuf = new Buffer(0) 22 | this.checksumbuf = new Buffer('5df6e0e2', 'hex') 23 | return this 24 | } 25 | 26 | isValid () { 27 | return this.getCmd() === 'sendheaders' && this.dataBuf.length === 0 28 | } 29 | } 30 | 31 | return MsgSendHeaders 32 | } 33 | 34 | inject = require('injecter')(inject, dependencies) 35 | let MsgSendHeaders = inject() 36 | MsgSendHeaders.Mainnet = inject({ 37 | MsgInv: require('./msg-inv').Mainnet 38 | }) 39 | MsgSendHeaders.Testnet = inject({ 40 | MsgInv: require('./msg-inv').Testnet 41 | }) 42 | module.exports = MsgSendHeaders 43 | -------------------------------------------------------------------------------- /lib/msg-tx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgTx 3 | * ===== 4 | * 5 | * Sends one tx. 6 | */ 7 | 'use strict' 8 | let dependencies = { 9 | Tx: require('./tx'), 10 | Msg: require('./msg') 11 | } 12 | 13 | let inject = function (deps) { 14 | let Tx = deps.Tx 15 | let Msg = deps.Msg 16 | 17 | class MsgTx extends Msg { 18 | initialize () { 19 | Msg.prototype.initialize.call(this) 20 | this.setCmd('tx') 21 | return this 22 | } 23 | 24 | fromTx (tx) { 25 | this.setData(tx.toBuffer()) 26 | return this 27 | } 28 | 29 | static fromTx (tx) { 30 | return new this().fromTx(tx) 31 | } 32 | 33 | asyncFromTx (tx) { 34 | return this.asyncSetData(tx.toBuffer()) 35 | } 36 | 37 | static asyncFromTx (tx) { 38 | return new this().asyncFromTx(tx) 39 | } 40 | 41 | toTx () { 42 | return new Tx().fromBuffer(this.dataBuf) 43 | } 44 | 45 | isValid () { 46 | return this.getCmd() === 'tx' 47 | } 48 | } 49 | 50 | return MsgTx 51 | } 52 | 53 | inject = require('injecter')(inject, dependencies) 54 | let MsgTx = inject() 55 | MsgTx.Mainnet = inject({ 56 | Msg: require('./msg').Mainnet 57 | }) 58 | MsgTx.Testnet = inject({ 59 | Msg: require('./msg').Testnet 60 | }) 61 | module.exports = MsgTx 62 | -------------------------------------------------------------------------------- /lib/msg-ver-ack.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgVerAck 3 | * ========= 4 | * 5 | * Acknowledge a version message. 6 | */ 7 | 'use strict' 8 | let dependencies = { 9 | Msg: require('./msg-inv') 10 | } 11 | 12 | let inject = function (deps) { 13 | let Msg = deps.Msg 14 | 15 | class MsgVerAck extends Msg { 16 | initialize () { 17 | Msg.prototype.initialize.call(this) 18 | this.setCmd('verack') 19 | this.datasize = 0 20 | this.dataBuf = new Buffer(0) 21 | this.checksumbuf = new Buffer('5df6e0e2', 'hex') 22 | return this 23 | } 24 | 25 | isValid () { 26 | return this.getCmd() === 'verack' && this.dataBuf.length === 0 27 | } 28 | } 29 | 30 | return MsgVerAck 31 | } 32 | 33 | inject = require('injecter')(inject, dependencies) 34 | let MsgVerAck = inject() 35 | MsgVerAck.Mainnet = inject({ 36 | MsgInv: require('./msg-inv').Mainnet 37 | }) 38 | MsgVerAck.Testnet = inject({ 39 | MsgInv: require('./msg-inv').Testnet 40 | }) 41 | module.exports = MsgVerAck 42 | -------------------------------------------------------------------------------- /lib/msg-version.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MsgVersion 3 | * ========== 4 | * 5 | * Sends version information about what p2p features this node or another 6 | * accepts. Confusingly, this "version" is not a number, but a data structure 7 | * used to communicate version information. 8 | */ 9 | 'use strict' 10 | let dependencies = { 11 | Version: require('./version'), 12 | Msg: require('./msg') 13 | } 14 | 15 | let inject = function (deps) { 16 | let Version = deps.Version 17 | let Msg = deps.Msg 18 | 19 | class MsgVersion extends Msg { 20 | initialize () { 21 | Msg.prototype.initialize.call(this) 22 | this.setCmd('version') 23 | return this 24 | } 25 | 26 | fromVersion (version) { 27 | this.setData(version.toBuffer()) 28 | return this 29 | } 30 | 31 | static fromVersion (version) { 32 | return new this().fromVersion(version) 33 | } 34 | 35 | asyncFromVersion (version) { 36 | return this.asyncSetData(version.toBuffer()) 37 | } 38 | 39 | static asyncFromVersion (version) { 40 | return new this().asyncFromVersion(version) 41 | } 42 | 43 | toVersion () { 44 | return new Version().fromBuffer(this.dataBuf) 45 | } 46 | 47 | isValid () { 48 | // TODO: More validation 49 | return this.getCmd() === 'version' 50 | } 51 | } 52 | 53 | return MsgVersion 54 | } 55 | 56 | inject = require('injecter')(inject, dependencies) 57 | let MsgVersion = inject() 58 | MsgVersion.Mainnet = inject({ 59 | Version: require('./version').Mainnet, 60 | Msg: require('./msg').Mainnet 61 | }) 62 | MsgVersion.Testnet = inject({ 63 | Version: require('./version').Testnet, 64 | Msg: require('./msg').Testnet 65 | }) 66 | module.exports = MsgVersion 67 | -------------------------------------------------------------------------------- /lib/point.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Point (on secp256k1) 3 | * ==================== 4 | * 5 | * A point is a point on the secp256k1 curve which is the elliptic curve used 6 | * by bitcoin. This code is a wrapper for Fedor Indutny's Point class from his 7 | * elliptic library. This code adds a few minor conveniences, but is mostly the 8 | * same. Since Fedor's code returns points and big numbers that are instances 9 | * of his point and big number classes, we have to wrap all the methods such as 10 | * getX() to return the Yours Bitcoin point and big number types. 11 | */ 12 | 'use strict' 13 | let dependencies = { 14 | Bn: require('./bn'), 15 | elliptic: require('elliptic') 16 | } 17 | 18 | let inject = function (deps) { 19 | let Bn = deps.Bn 20 | let elliptic = deps.elliptic 21 | 22 | let ec = elliptic.curves.secp256k1 23 | let _point = ec.curve.point() 24 | let _Point = _point.constructor 25 | 26 | class Point extends _Point { 27 | constructor (x, y, isRed) { 28 | super(ec.curve, x, y, isRed) 29 | } 30 | 31 | static fromX (isOdd, x) { 32 | let _point = ec.curve.pointFromX(x, isOdd) 33 | let point = Object.create(Point.prototype) 34 | return point.copyFrom(_point) 35 | } 36 | 37 | copyFrom (point) { 38 | if (!(point instanceof _Point)) { 39 | throw new Error('point should be an external point') 40 | } 41 | Object.keys(point).forEach(function (key) { 42 | this[key] = point[key] 43 | }.bind(this)) 44 | return this 45 | } 46 | 47 | add (p) { 48 | p = _Point.prototype.add.call(this, p) 49 | let point = Object.create(Point.prototype) 50 | return point.copyFrom(p) 51 | } 52 | 53 | mul (bn) { 54 | let p = _Point.prototype.mul.call(this, bn) 55 | let point = Object.create(Point.prototype) 56 | return point.copyFrom(p) 57 | } 58 | 59 | mulAdd (bn1, point, bn2) { 60 | let p = _Point.prototype.mulAdd.call(this, bn1, point, bn2) 61 | point = Object.create(Point.prototype) 62 | return point.copyFrom(p) 63 | } 64 | 65 | getX () { 66 | let _x = _Point.prototype.getX.call(this) 67 | let x = Object.create(Bn.prototype) 68 | _x.copy(x) 69 | return x 70 | } 71 | 72 | getY () { 73 | let _y = _Point.prototype.getY.call(this) 74 | let y = Object.create(Bn.prototype) 75 | _y.copy(y) 76 | return y 77 | } 78 | 79 | fromX (isOdd, x) { 80 | let point = Point.fromX(isOdd, x) 81 | return this.copyFrom(point) 82 | } 83 | 84 | toJSON () { 85 | return { 86 | x: this.getX().toString(), 87 | y: this.getY().toString() 88 | } 89 | } 90 | 91 | fromJSON (json) { 92 | let x = new Bn().fromString(json.x) 93 | let y = new Bn().fromString(json.y) 94 | let point = new Point(x, y) 95 | return this.copyFrom(point) 96 | } 97 | 98 | toString () { 99 | return JSON.stringify(this.toJSON()) 100 | } 101 | 102 | fromString (str) { 103 | let json = JSON.parse(str) 104 | let p = new Point().fromJSON(json) 105 | return this.copyFrom(p) 106 | } 107 | 108 | static getG () { 109 | let _g = ec.curve.g 110 | let g = Object.create(Point.prototype) 111 | return g.copyFrom(_g) 112 | } 113 | 114 | static getN () { 115 | return new Bn(ec.curve.n.toArray()) 116 | } 117 | 118 | // https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf 119 | validate () { 120 | let p2 = Point.fromX(this.getY().isOdd(), this.getX()) 121 | if (!(p2.getY().cmp(this.getY()) === 0)) { 122 | throw new Error('Invalid y value of public key') 123 | } 124 | if (!(this.getX().gt(-1) && this.getX().lt(Point.getN())) || 125 | !(this.getY().gt(-1) && this.getY().lt(Point.getN()))) { 126 | throw new Error('Point does not lie on the curve') 127 | } 128 | if (!(this.mul(Point.getN()).isInfinity())) { 129 | throw new Error('Point times N must be infinity') 130 | } 131 | return this 132 | } 133 | } 134 | 135 | return Point 136 | } 137 | 138 | inject = require('injecter')(inject, dependencies) 139 | let Point = inject() 140 | module.exports = Point 141 | -------------------------------------------------------------------------------- /lib/priv-key.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Private Key 3 | * =========== 4 | * 5 | * A private key is used for signIng transactions (or messages). The primary 6 | * way to use this is new PrivKey().fromRandom(), or new PrivKey().fromBuffer(buf). 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Bn: require('./bn'), 11 | Point: require('./point'), 12 | Constants: require('./constants').Default.PrivKey, 13 | Base58Check: require('./base-58-check'), 14 | Random: require('./random'), 15 | Struct: require('./struct') 16 | } 17 | 18 | let inject = function (deps) { 19 | let Bn = deps.Bn 20 | let Point = deps.Point 21 | let Constants = deps.Constants 22 | let Base58Check = deps.Base58Check 23 | let Random = deps.Random 24 | let Struct = deps.Struct 25 | 26 | class PrivKey extends Struct { 27 | constructor (bn, compressed) { 28 | super({bn, compressed}) 29 | } 30 | 31 | fromJSON (json) { 32 | this.fromHex(json) 33 | return this 34 | } 35 | 36 | toJSON () { 37 | return this.toHex() 38 | } 39 | 40 | fromRandom () { 41 | let privBuf, bn, condition 42 | 43 | do { 44 | privBuf = Random.getRandomBuffer(32) 45 | bn = new Bn().fromBuffer(privBuf) 46 | condition = bn.lt(Point.getN()) 47 | } while (!condition) 48 | 49 | this.fromObject({ 50 | bn: bn, 51 | compressed: true 52 | }) 53 | return this 54 | } 55 | 56 | static fromRandom () { 57 | return new this().fromRandom() 58 | } 59 | 60 | toBuffer () { 61 | let compressed = this.compressed 62 | 63 | if (compressed === undefined) { 64 | compressed = true 65 | } 66 | 67 | let privBuf = this.bn.toBuffer({size: 32}) 68 | let buf 69 | if (compressed) { 70 | buf = Buffer.concat([new Buffer([Constants.versionByteNum]), privBuf, new Buffer([0x01])]) 71 | } else { 72 | buf = Buffer.concat([new Buffer([Constants.versionByteNum]), privBuf]) 73 | } 74 | 75 | return buf 76 | } 77 | 78 | fromBuffer (buf) { 79 | if (buf.length === 1 + 32 + 1 && buf[1 + 32 + 1 - 1] === 1) { 80 | this.compressed = true 81 | } else if (buf.length === 1 + 32) { 82 | this.compressed = false 83 | } else { 84 | throw new Error('LEngth of privKey buffer must be 33 (uncompressed pubKey) or 34 (compressed pubKey)') 85 | } 86 | 87 | if (buf[0] !== Constants.versionByteNum) { 88 | throw new Error('Invalid versionByteNum byte') 89 | } 90 | 91 | return this.fromBn(new Bn().fromBuffer(buf.slice(1, 1 + 32))) 92 | } 93 | 94 | toBn () { 95 | return this.bn 96 | } 97 | 98 | fromBn (bn) { 99 | this.bn = bn 100 | return this 101 | } 102 | 103 | static fromBn (bn) { 104 | return new this().fromBn(bn) 105 | } 106 | 107 | validate () { 108 | if (!this.bn.lt(Point.getN())) { 109 | throw new Error('Number must be less than N') 110 | } 111 | if (typeof this.compressed !== 'boolean') { 112 | throw new Error('Must specify whether the corresponding public key is compressed or not (true or false)') 113 | } 114 | return this 115 | } 116 | 117 | /** 118 | * Output the private key a Wallet Import Format (Wif) string. 119 | */ 120 | toWif () { 121 | return Base58Check.encode(this.toBuffer()) 122 | } 123 | 124 | /** 125 | * Input the private key from a Wallet Import Format (Wif) string. 126 | */ 127 | fromWif (str) { 128 | return this.fromBuffer(Base58Check.decode(str)) 129 | } 130 | 131 | static fromWif (str) { 132 | return new this().fromWif(str) 133 | } 134 | 135 | toString () { 136 | return this.toWif() 137 | } 138 | 139 | fromString (str) { 140 | return this.fromWif(str) 141 | } 142 | } 143 | 144 | return PrivKey 145 | } 146 | 147 | inject = require('injecter')(inject, dependencies) 148 | let PrivKey = inject() 149 | PrivKey.Mainnet = inject({ 150 | Constants: require('./constants').Mainnet.PrivKey 151 | }) 152 | PrivKey.Testnet = inject({ 153 | Constants: require('./constants').Testnet.PrivKey 154 | }) 155 | module.exports = PrivKey 156 | -------------------------------------------------------------------------------- /lib/random.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Random Number Generator 3 | * ======================= 4 | * 5 | * Random numbers are important in bitcoin primarily for generating private 6 | * keys. It is also important for creating signatures if you are using a random 7 | * value of k, but Yours Bitcoin defaults to using deterministic k. That means 8 | * computing a random private key, or a random seed for use in Bip39 or Bip32, 9 | * is the primary use of the random number generator. Note that the simplicity 10 | * of this class is extremely carefully considered. It is easy to audit that 11 | * this code runs node's randomBytes function. It is also easy to audit that 12 | * the randomBytes method is correctly interpreted as 13 | * window.crypto.getRandomValues when this code is browserified by browserify, 14 | * and thus also works correctly in the browser. We deliberately do not do 15 | * anything else to this random number in order to minimize possible errors in 16 | * this absolutely critical code. 17 | */ 18 | 'use strict' 19 | let dependencies = { 20 | randomBytes: require('randombytes') 21 | } 22 | 23 | let inject = function (deps) { 24 | let randomBytes = deps.randomBytes 25 | 26 | let Random = {} 27 | 28 | Random.getRandomBuffer = function (size) { 29 | return randomBytes(size) 30 | } 31 | 32 | return Random 33 | } 34 | 35 | inject = require('injecter')(inject, dependencies) 36 | let Random = inject() 37 | module.exports = Random 38 | -------------------------------------------------------------------------------- /lib/reject.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Reject 3 | * ========= 4 | * 5 | * The data structure used inside the "reject" p2p message. Contains a reason 6 | * why a particular message was rejected. Useful for debugging. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Bw: require('./bw'), 11 | Struct: require('./struct'), 12 | VarInt: require('./var-int') 13 | } 14 | 15 | let inject = function (deps) { 16 | let Bw = deps.Bw 17 | let Struct = deps.Struct 18 | let VarInt = deps.VarInt 19 | 20 | class Reject extends Struct { 21 | constructor (typeVi, typeStr, codeNum, reasonVi, reasonStr, extraBuf) { 22 | super({typeVi, typeStr, codeNum, reasonVi, reasonStr, extraBuf}) 23 | } 24 | 25 | toBw (bw) { 26 | if (!bw) { 27 | bw = new Bw() 28 | } 29 | bw.write(this.typeVi.buf) 30 | bw.write(new Buffer(this.typeStr)) 31 | bw.writeUInt8(this.codeNum) 32 | bw.write(this.reasonVi.buf) 33 | bw.write(new Buffer(this.reasonStr)) 34 | bw.write(this.extraBuf) 35 | return bw 36 | } 37 | 38 | fromBr (br) { 39 | this.typeVi = new VarInt(br.readVarIntBuf()) 40 | this.typeStr = br.read(this.typeVi.toNumber()).toString() 41 | this.codeNum = br.readUInt8() 42 | this.reasonVi = new VarInt(br.readVarIntBuf()) 43 | this.reasonStr = br.read(this.reasonVi.toNumber()).toString() 44 | this.extraBuf = br.read() 45 | return this 46 | } 47 | } 48 | 49 | return Reject 50 | } 51 | 52 | inject = require('injecter')(inject, dependencies) 53 | let Reject = inject() 54 | module.exports = Reject 55 | -------------------------------------------------------------------------------- /lib/tx-out-map.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Transaction Output Map 3 | * ====================== 4 | * 5 | * A map from a transaction hash and output number to that particular output. 6 | * Note that the map is from the transaction *hash*, which is the value that 7 | * occurs in the blockchain, not the id, which is the reverse of the hash. 8 | */ 9 | 'use strict' 10 | let dependencies = { 11 | Struct: require('./struct'), 12 | TxOut: require('./tx-out') 13 | } 14 | 15 | let inject = function (deps) { 16 | let Struct = deps.Struct 17 | let TxOut = deps.TxOut 18 | 19 | class TxOutMap extends Struct { 20 | constructor (map = new Map()) { 21 | super({map}) 22 | } 23 | 24 | toJSON () { 25 | let json = {} 26 | this.map.forEach((txOut, label) => { 27 | json[label] = txOut.toHex() 28 | }) 29 | return json 30 | } 31 | 32 | fromJSON (json) { 33 | Object.keys(json).forEach((label) => { 34 | this.map.set(label, TxOut.fromHex(json[label])) 35 | }) 36 | return this 37 | } 38 | 39 | add (txHashBuf, txOutNum, txOut) { 40 | let label = txHashBuf.toString('hex') + ':' + txOutNum 41 | this.map.set(label, txOut) 42 | return this 43 | } 44 | 45 | get (txHashBuf, txOutNum) { 46 | let label = txHashBuf.toString('hex') + ':' + txOutNum 47 | return this.map.get(label) 48 | } 49 | 50 | addTx (tx) { 51 | let txhashhex = tx.hash().toString('hex') 52 | tx.txOuts.forEach((txOut, index) => { 53 | let label = txhashhex + ':' + index 54 | this.map.set(label, txOut) 55 | }) 56 | return this 57 | } 58 | } 59 | 60 | return TxOutMap 61 | } 62 | 63 | inject = require('injecter')(inject, dependencies) 64 | let TxOutMap = inject() 65 | module.exports = TxOutMap 66 | -------------------------------------------------------------------------------- /lib/tx-out.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Transaction Output 3 | * ================== 4 | * 5 | * An output to a transaction. The way you normally want to make one is with 6 | * new TxOut(valueBn, script) (i.e., just as with TxIn, you can leave out the 7 | * scriptVi, since it can be computed automatically. 8 | */ 9 | 'use strict' 10 | let dependencies = { 11 | Bn: require('./bn'), 12 | Bw: require('./bw'), 13 | Script: require('./script'), 14 | Struct: require('./struct'), 15 | VarInt: require('./var-int') 16 | } 17 | 18 | let inject = function (deps) { 19 | let Bn = deps.Bn 20 | let Bw = deps.Bw 21 | let Script = deps.Script 22 | let Struct = deps.Struct 23 | let VarInt = deps.VarInt 24 | 25 | class TxOut extends Struct { 26 | constructor (valueBn, scriptVi, script) { 27 | super({valueBn, scriptVi, script}) 28 | } 29 | 30 | setScript (script) { 31 | this.scriptVi = VarInt.fromNumber(script.toBuffer().length) 32 | this.script = script 33 | return this 34 | } 35 | 36 | fromProperties (valueBn, script) { 37 | this.fromObject({valueBn}) 38 | this.setScript(script) 39 | return this 40 | } 41 | 42 | static fromProperties (valueBn, script) { 43 | return new this().fromProperties(valueBn, script) 44 | } 45 | 46 | fromJSON (json) { 47 | this.fromObject({ 48 | valueBn: new Bn().fromJSON(json.valueBn), 49 | scriptVi: new VarInt().fromJSON(json.scriptVi), 50 | script: new Script().fromJSON(json.script) 51 | }) 52 | return this 53 | } 54 | 55 | toJSON () { 56 | return { 57 | valueBn: this.valueBn.toJSON(), 58 | scriptVi: this.scriptVi.toJSON(), 59 | script: this.script.toJSON() 60 | } 61 | } 62 | 63 | fromBr (br) { 64 | this.valueBn = br.readUInt64LEBn() 65 | this.scriptVi = VarInt.fromNumber(br.readVarIntNum()) 66 | this.script = new Script().fromBuffer(br.read(this.scriptVi.toNumber())) 67 | return this 68 | } 69 | 70 | toBw (bw) { 71 | if (!bw) { 72 | bw = new Bw() 73 | } 74 | bw.writeUInt64LEBn(this.valueBn) 75 | bw.write(this.scriptVi.buf) 76 | bw.write(this.script.toBuffer()) 77 | return bw 78 | } 79 | } 80 | 81 | return TxOut 82 | } 83 | 84 | inject = require('injecter')(inject, dependencies) 85 | let TxOut = inject() 86 | module.exports = TxOut 87 | -------------------------------------------------------------------------------- /lib/var-int.js: -------------------------------------------------------------------------------- 1 | /** 2 | * VarInt (a.k.a. Compact Size) 3 | * ============================ 4 | * 5 | * A varInt is a varible sized integer, and it is a format that is unique to 6 | * bitcoin, and used throughout bitcoin to represent the length of binary data 7 | * in a compact format that can take up as little as 1 byte or as much as 9 8 | * bytes. 9 | */ 10 | 'use strict' 11 | let dependencies = { 12 | Br: require('./br'), 13 | Bw: require('./bw'), 14 | Struct: require('./struct') 15 | } 16 | 17 | let inject = function (deps) { 18 | let Br = deps.Br 19 | let Bw = deps.Bw 20 | let Struct = deps.Struct 21 | 22 | class VarInt extends Struct { 23 | constructor (buf) { 24 | super({buf}) 25 | } 26 | 27 | fromJSON (json) { 28 | this.fromObject({ 29 | buf: new Buffer(json, 'hex') 30 | }) 31 | return this 32 | } 33 | 34 | toJSON () { 35 | return this.buf.toString('hex') 36 | } 37 | 38 | fromBuffer (buf) { 39 | this.buf = buf 40 | return this 41 | } 42 | 43 | fromBr (br) { 44 | this.buf = br.readVarIntBuf() 45 | return this 46 | } 47 | 48 | fromBn (bn) { 49 | this.buf = new Bw().writeVarIntBn(bn).toBuffer() 50 | return this 51 | } 52 | 53 | static fromBn (bn) { 54 | return new this().fromBn(bn) 55 | } 56 | 57 | fromNumber (num) { 58 | this.buf = new Bw().writeVarIntNum(num).toBuffer() 59 | return this 60 | } 61 | 62 | static fromNumber (num) { 63 | return new this().fromNumber(num) 64 | } 65 | 66 | toBuffer () { 67 | return this.buf 68 | } 69 | 70 | toBn () { 71 | return new Br(this.buf).readVarIntBn() 72 | } 73 | 74 | toNumber () { 75 | return new Br(this.buf).readVarIntNum() 76 | } 77 | } 78 | 79 | return VarInt 80 | } 81 | 82 | inject = require('injecter')(inject, dependencies) 83 | let VarInt = inject() 84 | module.exports = VarInt 85 | -------------------------------------------------------------------------------- /lib/version.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Version 3 | * ======= 4 | * 5 | * This data structure is used to specify details about what version of the 6 | * p2p network is supported by this or other nodes. 7 | */ 8 | 'use strict' 9 | let dependencies = { 10 | Bw: require('./bw'), 11 | Struct: require('./struct'), 12 | VarInt: require('./var-int') 13 | } 14 | 15 | let inject = function (deps) { 16 | let Bw = deps.Bw 17 | let Struct = deps.Struct 18 | let VarInt = deps.VarInt 19 | 20 | class Version extends Struct { 21 | constructor (versionBytesNum, servicesBuf, timeBn, addrRecvServicesBuf, addrRecvIpAddrBuf, addrRecvPort, addrTransServicesBuf, addrTransIpAddrBuf, addrTransPortBuf, nonceBuf, userAgentVi, userAgentBuf, startHeightNum, relay) { 22 | super({versionBytesNum, servicesBuf, timeBn, addrRecvServicesBuf, addrRecvIpAddrBuf, addrRecvPort, addrTransServicesBuf, addrTransIpAddrBuf, addrTransPortBuf, nonceBuf, userAgentVi, userAgentBuf, startHeightNum, relay}) 23 | } 24 | 25 | toBw (bw) { 26 | if (!bw) { 27 | bw = new Bw() 28 | } 29 | bw.writeUInt32LE(this.versionBytesNum) 30 | bw.write(this.servicesBuf) 31 | bw.writeUInt64LEBn(this.timeBn) 32 | bw.write(this.addrRecvServicesBuf) 33 | bw.write(this.addrRecvIpAddrBuf) 34 | bw.writeUInt16BE(this.addrRecvPort) // note BE 35 | bw.write(this.addrTransServicesBuf) 36 | bw.write(this.addrTransIpAddrBuf) 37 | bw.writeUInt16BE(this.addrTransPort) // note BE 38 | bw.write(this.nonceBuf) 39 | bw.write(this.userAgentVi.buf) 40 | bw.write(this.userAgentBuf) 41 | bw.writeUInt32LE(this.startHeightNum) 42 | bw.writeUInt8(Number(this.relay)) 43 | return bw 44 | } 45 | 46 | fromBr (br) { 47 | this.versionBytesNum = br.readUInt32LE() 48 | this.servicesBuf = br.read(8) 49 | this.timeBn = br.readUInt64LEBn() 50 | this.addrRecvServicesBuf = br.read(8) 51 | this.addrRecvIpAddrBuf = br.read(16) 52 | this.addrRecvPort = br.readUInt16BE() // note BE 53 | this.addrTransServicesBuf = br.read(8) 54 | this.addrTransIpAddrBuf = br.read(16) 55 | this.addrTransPort = br.readUInt16BE() // note BE 56 | this.nonceBuf = br.read(8) 57 | this.userAgentVi = new VarInt(br.readVarIntBuf()) 58 | this.userAgentBuf = br.read(this.userAgentVi.toNumber()) 59 | this.startHeightNum = br.readUInt32LE() 60 | this.relay = Boolean(br.readUInt8()) 61 | return this 62 | } 63 | } 64 | 65 | return Version 66 | } 67 | 68 | inject = require('injecter')(inject, dependencies) 69 | let Version = inject() 70 | module.exports = Version 71 | -------------------------------------------------------------------------------- /lib/worker-browser.js: -------------------------------------------------------------------------------- 1 | /* global importScripts,YoursBitcoin,postMessage */ 2 | /** 3 | * Worker 4 | * ====== 5 | * 6 | * This class is for running CPU-heavy, blocking operations. It either runs in 7 | * a separate process (in node), or in a web worker thread (in a browser). It 8 | * receives messages from outside, performs the computation, and then sends 9 | * back the result. You probably don't want to use this file directly, but 10 | * rather Work, which will automatically spawn workers if necessary and send 11 | * commands to them. Note that the source code for worker-node and 12 | * worker-browser are almost equivalent, except for code that manages the 13 | * differences at the bottom. This is done deliberately, so that the browser 14 | * version can be minimized properly. 15 | */ 16 | 'use strict' 17 | 18 | // The Yours Bitcoin "classes" that the worker can access. Objects sent from the 19 | // main process/thread must be one of these types. They are defined below in a 20 | // different way for node and the browser. 21 | let classes 22 | 23 | // The function to send data back to the main process/thread. This is different 24 | // for node and browsers and thus is defined below. 25 | let send 26 | 27 | // len is the length of the data being sent to the worker - which may come in 28 | // pieces. bw is a BufferWriter used to assemble the pieces, if necessary. 29 | let len 30 | let bw 31 | 32 | /** 33 | * The generic "receive data" method that works both in node and the browser. 34 | * It reconstitutes the data into an object of class classname, and then runs 35 | * the method methodname on it with arguments args. 36 | */ 37 | function receive (buf) { 38 | let WorkersCmd = classes['WorkersCmd'] 39 | let WorkersResult = classes['WorkersResult'] 40 | let Bw = classes['Bw'] 41 | let remainderbuf 42 | 43 | // buffers sent to us are prefixed with the length. If the buffer has been 44 | // broken up into pieces, we need to assemble them. 45 | if (!bw) { 46 | if (buf.length < 4) { 47 | let workersResult = new WorkersResult().fromError(new Error('buf must be prefixed with length')) 48 | send(workersResult.toFastBuffer()) 49 | return 50 | } 51 | len = buf.readUInt32BE(0) 52 | if (len > buf.length - 4) { 53 | bw = new Bw() 54 | bw.write(buf.slice(4)) 55 | // need to wait for the rest of the message 56 | return 57 | } else if (len < buf.length - 4) { 58 | // sent more than one message 59 | remainderbuf = buf.slice(len + 4) 60 | buf = buf.slice(0, len + 4) 61 | } 62 | 63 | // else, the entire buf was sent in one message, can continue 64 | buf = buf.slice(4) 65 | } else { 66 | // getting a new piece of the message 67 | bw.write(buf) 68 | if (bw.getLength() < len) { 69 | // need to wait for more data 70 | return 71 | } 72 | // got all data! 73 | buf = bw.toBuffer() 74 | bw = undefined 75 | } 76 | 77 | let obj, result, id 78 | try { 79 | let workersCmd = new WorkersCmd().fromFastBuffer(buf, classes) 80 | id = workersCmd.id 81 | if (workersCmd.isobj) { 82 | obj = new classes[workersCmd.classname]().fromFastBuffer(workersCmd.objbuf) 83 | } else { 84 | obj = classes[workersCmd.classname] 85 | } 86 | result = obj[workersCmd.methodname].apply(obj, workersCmd.args) 87 | } catch (error) { 88 | if (!id) { 89 | id = 0 // must be uint 90 | } 91 | let workersResult = new WorkersResult().fromError(error, id) 92 | send(workersResult.toFastBuffer()) 93 | return 94 | } 95 | let workersResult = new WorkersResult().fromResult(result, id) 96 | send(workersResult.toFastBuffer()) 97 | 98 | if (remainderbuf) { 99 | receive(remainderbuf) 100 | } 101 | } 102 | 103 | // Load the main Yours Bitcoin library so we have access to classes like Msg; it 104 | // is assumed the full library is available. It is usually called 105 | // yours-bitcoin.js. It sets a global object called YoursBitcoin. 106 | importScripts(process.env.YOURS_BITCOIN_JS_BASE_URL + process.env.YOURS_BITCOIN_JS_BUNDLE_FILE) 107 | classes = YoursBitcoin 108 | // Web workers use the global functions onmessage to receive, and postMessage 109 | // to send. 110 | onmessage = function (event) { // eslint-disable-line 111 | let buf = new YoursBitcoin.deps.Buffer(event.data) 112 | return receive(buf) 113 | } 114 | send = postMessage 115 | -------------------------------------------------------------------------------- /lib/worker-node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Worker 3 | * ====== 4 | * 5 | * This class is for running CPU-heavy, blocking operations. It either runs in 6 | * a separate process (in node), or in a web worker thread (in a browser). It 7 | * receives messages from outside, performs the computation, and then sends 8 | * back the result. You probably don't want to use this file directly, but 9 | * rather Work, which will automatically spawn workers if necessary and send 10 | * commands to them. Note that the source code for worker-node and 11 | * worker-browser are almost equivalent, except for code that manages the 12 | * differences at the bottom. This is done deliberately, so that the browser 13 | * version can be minimized properly. 14 | */ 15 | 'use strict' 16 | 17 | // The Yours Bitcoin "classes" that the worker can access. Objects sent from the 18 | // main process/thread must be one of these types. They are defined below in a 19 | // different way for node and the browser. 20 | let classes 21 | 22 | // The function to send data back to the main process/thread. This is different 23 | // for node and browsers and thus is defined below. 24 | let send 25 | 26 | // len is the length of the data being sent to the worker - which may come in 27 | // pieces. bw is a BufferWriter used to assemble the pieces, if necessary. 28 | let len 29 | let bw 30 | 31 | /** 32 | * The generic "receive data" method that works both in node and the browser. 33 | * It reconstitutes the data into an object of class classname, and then runs 34 | * the method methodname on it with arguments args. 35 | */ 36 | function receive (buf) { 37 | let WorkersCmd = classes['WorkersCmd'] 38 | let WorkersResult = classes['WorkersResult'] 39 | let Bw = classes['Bw'] 40 | let remainderbuf 41 | 42 | // buffers sent to us are prefixed with the length. If the buffer has been 43 | // broken up into pieces, we need to assemble them. 44 | if (!bw) { 45 | if (buf.length < 4) { 46 | let workersResult = new WorkersResult().fromError(new Error('buf must be prefixed with length')) 47 | send(workersResult.toFastBuffer()) 48 | return 49 | } 50 | len = buf.readUInt32BE(0) 51 | if (len > buf.length - 4) { 52 | bw = new Bw() 53 | bw.write(buf.slice(4)) 54 | // need to wait for the rest of the message 55 | return 56 | } else if (len < buf.length - 4) { 57 | // sent more than one message 58 | remainderbuf = buf.slice(len + 4) 59 | buf = buf.slice(0, len + 4) 60 | } 61 | 62 | // else, the entire buf was sent in one message, can continue 63 | buf = buf.slice(4) 64 | } else { 65 | // getting a new piece of the message 66 | bw.write(buf) 67 | if (bw.getLength() < len) { 68 | // need to wait for more data 69 | return 70 | } 71 | // got all data! 72 | buf = bw.toBuffer() 73 | bw = undefined 74 | } 75 | 76 | let obj, result, id 77 | try { 78 | let workersCmd = new WorkersCmd().fromFastBuffer(buf, classes) 79 | id = workersCmd.id 80 | if (workersCmd.isobj) { 81 | obj = new classes[workersCmd.classname]().fromFastBuffer(workersCmd.objbuf) 82 | } else { 83 | obj = classes[workersCmd.classname] 84 | } 85 | result = obj[workersCmd.methodname].apply(obj, workersCmd.args) 86 | } catch (error) { 87 | if (!id) { 88 | id = 0 // must be uint 89 | } 90 | let workersResult = new WorkersResult().fromError(error, id) 91 | send(workersResult.toFastBuffer()) 92 | return 93 | } 94 | let workersResult = new WorkersResult().fromResult(result, id) 95 | send(workersResult.toFastBuffer()) 96 | 97 | if (remainderbuf) { 98 | receive(remainderbuf) 99 | } 100 | } 101 | 102 | // Node uses process.on and process.send to receive and send messages. 103 | classes = require('../index') 104 | process.stdin.on('data', function (buf) { 105 | return receive(buf) 106 | }) 107 | send = process.stdout.write.bind(process.stdout) 108 | -------------------------------------------------------------------------------- /lib/workers-result.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WorkersResult 3 | * ============= 4 | * 5 | * A response sent back from a worker to the main thread. Contains the "result" 6 | * of the computation in the form of a buffer, resbuf. If the actual result is 7 | * an object with a .toFastBuffer method, the object is converted to a buffer 8 | * using that method. Otherwise it is JSON serialized into a buffer. The result 9 | * can also be an error, in which case the isError flag is set. 10 | */ 11 | 'use strict' 12 | let dependencies = { 13 | Bw: require('./bw'), 14 | Struct: require('./struct') 15 | } 16 | 17 | let inject = function (deps) { 18 | let Bw = deps.Bw 19 | let Struct = deps.Struct 20 | 21 | class WorkersResult extends Struct { 22 | constructor (resbuf, isError, id) { 23 | super({resbuf, isError, id}) 24 | } 25 | 26 | fromResult (result, id) { 27 | if (result.toFastBuffer) { 28 | this.resbuf = result.toFastBuffer() 29 | } else if (Buffer.isBuffer(result)) { 30 | this.resbuf = result 31 | } else { 32 | this.resbuf = new Buffer(JSON.stringify(result)) 33 | } 34 | this.isError = false 35 | this.id = id 36 | return this 37 | } 38 | 39 | static fromResult (result, id) { 40 | return new this().fromResult(result, id) 41 | } 42 | 43 | fromError (error, id) { 44 | this.resbuf = new Buffer(JSON.stringify(error.message)) 45 | this.isError = true 46 | this.id = id 47 | return this 48 | } 49 | 50 | toBw (bw) { 51 | if (!bw) { 52 | bw = new Bw() 53 | } 54 | bw.writeVarIntNum(this.resbuf.length) 55 | bw.write(this.resbuf) 56 | bw.writeUInt8(Number(this.isError)) 57 | bw.writeVarIntNum(this.id) 58 | return bw 59 | } 60 | 61 | fromBr (br) { 62 | let resbuflen = br.readVarIntNum() 63 | this.resbuf = br.read(resbuflen) 64 | this.isError = Boolean(br.readUInt8()) 65 | this.id = br.readVarIntNum() 66 | return this 67 | } 68 | } 69 | 70 | return WorkersResult 71 | } 72 | 73 | inject = require('injecter')(inject, dependencies) 74 | let WorkersResult = inject() 75 | module.exports = WorkersResult 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yours-bitcoin", 3 | "version": "0.14.14", 4 | "description": "Javascript implementation of Bitcoin.", 5 | "author": "Ryan X. Charles ", 6 | "homepage": "https://github.com/yoursnetwork/yours-bitcoin", 7 | "main": "index.js", 8 | "scripts": { 9 | "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- --recursive -R progress", 10 | "parallel": "./node_modules/.bin/standard && ./bin/test-parallel", 11 | "test-node": "./node_modules/.bin/standard && ./node_modules/.bin/mocha --recursive -R progress", 12 | "test-browser": "./node_modules/.bin/gulp test-karma", 13 | "test": "npm run test-node && npm run test-browser", 14 | "build": "./node_modules/.bin/gulp build" 15 | }, 16 | "browserify": { 17 | "transform": [ 18 | [ 19 | "babelify", 20 | { 21 | "presets": [ 22 | "es2015" 23 | ] 24 | } 25 | ] 26 | ] 27 | }, 28 | "contributors": [ 29 | { 30 | "name": "Daniel Cousens", 31 | "email": "bitcoin@dcousens.com" 32 | }, 33 | { 34 | "name": "Gordon Hall", 35 | "email": "gordon@bitpay.com" 36 | }, 37 | { 38 | "name": "Jeff Garzik", 39 | "email": "jgarzik@bitpay.com" 40 | }, 41 | { 42 | "name": "Kyle Drake", 43 | "email": "kyle@kyledrake.net" 44 | }, 45 | { 46 | "name": "Manuel Araoz", 47 | "email": "manuelaraoz@gmail.com" 48 | }, 49 | { 50 | "name": "Matias Alejo Garcia", 51 | "email": "ematiu@gmail.com" 52 | }, 53 | { 54 | "name": "Ryan X. Charles", 55 | "email": "ryanxcharles@gmail.com" 56 | }, 57 | { 58 | "name": "Stefan Thomas", 59 | "email": "moon@justmoon.net" 60 | }, 61 | { 62 | "name": "Stephen Pair", 63 | "email": "stephen@bitpay.com" 64 | }, 65 | { 66 | "name": "Wei Lu", 67 | "email": "luwei.here@gmail.com" 68 | } 69 | ], 70 | "keywords": [ 71 | "bitcoin", 72 | "blockchain", 73 | "bip32", 74 | "bip39", 75 | "bip68", 76 | "multisig" 77 | ], 78 | "repository": { 79 | "type": "git", 80 | "url": "https://github.com/yoursnetwork/yours-bitcoin.git" 81 | }, 82 | "engines": { 83 | "node": ">=6.1.0" 84 | }, 85 | "dependencies": { 86 | "aes": "0.1.0", 87 | "asink": "1.0.4", 88 | "babel-polyfill": "6.9.1", 89 | "babel-preset-es2015": "6.9.0", 90 | "babel-preset-react": "6.11.1", 91 | "babelify": "7.3.0", 92 | "bn.js": "4.11.4", 93 | "browserify": "13.0.1", 94 | "bs58": "3.0.0", 95 | "elliptic": "6.3.1", 96 | "envify": "3.4.1", 97 | "express": "4.14.0", 98 | "glob": "7.0.5", 99 | "gulp": "3.9.1", 100 | "gulp-mocha": "2.2.0", 101 | "hash.js": "1.0.3", 102 | "injecter": "1.0.2", 103 | "istanbul": "0.4.4", 104 | "karma": "1.1.0", 105 | "karma-mocha": "1.1.1", 106 | "mocha": "2.5.3", 107 | "pbkdf2-compat": "4.0.0", 108 | "randombytes": "2.0.3", 109 | "standard": "7.1.2", 110 | "uglifyify": "3.0.2" 111 | }, 112 | "devDependencies": { 113 | "chai": "3.5.0", 114 | "express": "4.13.4", 115 | "istanbul": "0.4.3", 116 | "karma": "0.13.22", 117 | "karma-firefox-launcher": "1.0.0", 118 | "karma-mocha": "1.0.1", 119 | "mocha": "2.4.5", 120 | "sinon": "1.17.4", 121 | "standard": "7.0.1" 122 | }, 123 | "license": "MIT" 124 | } 125 | -------------------------------------------------------------------------------- /test/addr.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Addr = require('../lib/addr') 4 | let should = require('chai').should() 5 | 6 | describe('Addr', function () { 7 | it('should exist', function () { 8 | should.exist(Addr) 9 | should.exist(new Addr()) 10 | }) 11 | 12 | describe('#toBuffer', function () { 13 | it('should convert an addr to a buffer', function () { 14 | let addr = new Addr().fromObject({ 15 | time: 1000, 16 | servicesBuf: new Buffer(8).fill(0), 17 | ipAddrBuf: new Buffer(16).fill(0), 18 | port: 8333 19 | }) 20 | addr.toBuffer().length.should.equal(4 + 8 + 16 + 2) 21 | }) 22 | }) 23 | 24 | describe('#toBuffer', function () { 25 | it('should convert an addr to a buffer', function () { 26 | let addr = new Addr().fromObject({ 27 | time: 1000, 28 | servicesBuf: new Buffer(8).fill(0), 29 | ipAddrBuf: new Buffer(16).fill(0), 30 | port: 8333 31 | }) 32 | let addr2 = new Addr().fromBuffer(addr.toBuffer()) 33 | addr2.time.should.equal(addr.time) 34 | Buffer.compare(addr.servicesBuf, addr2.servicesBuf).should.equal(0) 35 | Buffer.compare(addr.ipAddrBuf, addr2.ipAddrBuf).should.equal(0) 36 | addr2.port.should.equal(addr.port) 37 | }) 38 | }) 39 | 40 | describe('@fromBuffer', function () { 41 | it('should convert from a buffer', function () { 42 | let addr = Addr.fromObject({ 43 | time: 1000, 44 | servicesBuf: new Buffer(8).fill(0), 45 | ipAddrBuf: new Buffer(16).fill(0), 46 | port: 8333 47 | }) 48 | let addr2 = Addr.fromBuffer(addr.toBuffer()) 49 | addr2.time.should.equal(addr.time) 50 | Buffer.compare(addr.servicesBuf, addr2.servicesBuf).should.equal(0) 51 | Buffer.compare(addr.ipAddrBuf, addr2.ipAddrBuf).should.equal(0) 52 | addr2.port.should.equal(addr.port) 53 | }) 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /test/aes.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let should = require('chai').should() 4 | let Hash = require('../lib/hash') 5 | let Aes = require('../lib/aes') 6 | let vectors = require('./vectors/aes') 7 | 8 | describe('Aes', function () { 9 | let m128 = Hash.sha256(new Buffer('test1')).slice(0, 128 / 8) 10 | 11 | let k128 = Hash.sha256(new Buffer('test2')).slice(0, 128 / 8) 12 | let k192 = Hash.sha256(new Buffer('test2')).slice(0, 192 / 8) 13 | let k256 = Hash.sha256(new Buffer('test2')).slice(0, 256 / 8) 14 | 15 | let e128 = new Buffer('3477e13884125038f4dc24e9d2cfbbc7', 'hex') 16 | let e192 = new Buffer('b670954c0e2da1aaa5f9063de04eb961', 'hex') 17 | let e256 = new Buffer('dd2ce24581183a4a7c0b1068f8bc79f0', 'hex') 18 | 19 | should.exist(Aes) 20 | 21 | describe('@encrypt', function () { 22 | it('should encrypt with a 128 bit key', function () { 23 | let encBuf = Aes.encrypt(m128, k128) 24 | encBuf.toString('hex').should.equal(e128.toString('hex')) 25 | }) 26 | 27 | it('should encrypt with a 192 bit key', function () { 28 | let encBuf = Aes.encrypt(m128, k192) 29 | encBuf.toString('hex').should.equal(e192.toString('hex')) 30 | }) 31 | 32 | it('should encrypt with a 256 bit key', function () { 33 | let encBuf = Aes.encrypt(m128, k256) 34 | encBuf.toString('hex').should.equal(e256.toString('hex')) 35 | }) 36 | }) 37 | 38 | describe('@decrypt', function () { 39 | it('should encrypt/decrypt with a 128 bit key', function () { 40 | let encBuf = Aes.encrypt(m128, k128) 41 | let m = Aes.decrypt(encBuf, k128) 42 | m.toString('hex').should.equal(m128.toString('hex')) 43 | }) 44 | 45 | it('should encrypt/decrypt with a 192 bit key', function () { 46 | let encBuf = Aes.encrypt(m128, k192) 47 | let m = Aes.decrypt(encBuf, k192) 48 | m.toString('hex').should.equal(m128.toString('hex')) 49 | }) 50 | 51 | it('should encrypt/decrypt with a 256 bit key', function () { 52 | let encBuf = Aes.encrypt(m128, k256) 53 | let m = Aes.decrypt(encBuf, k256) 54 | m.toString('hex').should.equal(m128.toString('hex')) 55 | }) 56 | }) 57 | 58 | describe('@buf2Words', function () { 59 | it('should convert this 4 length buffer into an array', function () { 60 | let buf = new Buffer([0, 0, 0, 0]) 61 | let words = Aes.buf2Words(buf) 62 | words.length.should.equal(1) 63 | }) 64 | 65 | it('should throw an error on this 5 length buffer', function () { 66 | let buf = new Buffer([0, 0, 0, 0, 0]) 67 | ;(function () { 68 | Aes.buf2Words(buf) 69 | }).should.throw() 70 | }) 71 | }) 72 | 73 | describe('@words2Buf', function () { 74 | it('should convert this array into a buffer', function () { 75 | let a = [100, 0] 76 | let buf = Aes.words2Buf(a) 77 | buf.length.should.equal(8) 78 | }) 79 | }) 80 | 81 | describe('vectors', function () { 82 | vectors.forEach(function (vector, i) { 83 | it('should pass sjcl test vector ' + i, function () { 84 | let keyBuf = new Buffer(vector.key, 'hex') 85 | let ptbuf = new Buffer(vector.pt, 'hex') 86 | let ctBuf = new Buffer(vector.ct, 'hex') 87 | 88 | Aes.encrypt(ptbuf, keyBuf).toString('hex').should.equal(ctBuf.toString('hex')) 89 | Aes.decrypt(ctBuf, keyBuf).toString('hex').should.equal(ptbuf.toString('hex')) 90 | }) 91 | }) 92 | }) 93 | }) 94 | -------------------------------------------------------------------------------- /test/aescbc.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let should = require('chai').should() 4 | let Aescbc = require('../lib/aescbc') 5 | let vectors = require('./vectors/aescbc') 6 | 7 | describe('Aescbc', function () { 8 | should.exist(Aescbc) 9 | 10 | describe('@encrypt', function () { 11 | it('should return encrypt one block', function () { 12 | let cipherKeyBuf = new Buffer(256 / 8) 13 | cipherKeyBuf.fill(0x10) 14 | let ivBuf = new Buffer(128 / 8) 15 | ivBuf.fill(0) 16 | let messageBuf = new Buffer(128 / 8 - 1) 17 | messageBuf.fill(0) 18 | let encBuf = Aescbc.encrypt(messageBuf, cipherKeyBuf, ivBuf) 19 | encBuf.length.should.equal(128 / 8 + 128 / 8) 20 | }) 21 | 22 | it('should return encrypt two blocks', function () { 23 | let cipherKeyBuf = new Buffer(256 / 8) 24 | cipherKeyBuf.fill(0x10) 25 | let ivBuf = new Buffer(128 / 8) 26 | ivBuf.fill(0) 27 | let messageBuf = new Buffer(128 / 8) 28 | messageBuf.fill(0) 29 | let encBuf = Aescbc.encrypt(messageBuf, cipherKeyBuf, ivBuf) 30 | encBuf.length.should.equal(128 / 8 + 128 / 8 + 128 / 8) 31 | }) 32 | }) 33 | 34 | describe('@decrypt', function () { 35 | it('should decrypt that which was encrypted', function () { 36 | let cipherKeyBuf = new Buffer(256 / 8) 37 | cipherKeyBuf.fill(0x10) 38 | let ivBuf = new Buffer(128 / 8) 39 | ivBuf.fill(0) 40 | let messageBuf = new Buffer(128 / 8) 41 | messageBuf.fill(0) 42 | let encBuf = Aescbc.encrypt(messageBuf, cipherKeyBuf, ivBuf) 43 | let messageBuf2 = Aescbc.decrypt(encBuf, cipherKeyBuf) 44 | messageBuf2.toString('hex').should.equal(messageBuf.toString('hex')) 45 | }) 46 | }) 47 | 48 | describe('vectors', function () { 49 | vectors.forEach(function (vector, i) { 50 | it('should pass sjcl test vector ' + i, function () { 51 | let keyBuf = new Buffer(vector.key, 'hex') 52 | let ivBuf = new Buffer(vector.iv, 'hex') 53 | let ptbuf = new Buffer(vector.pt, 'hex') 54 | let ctBuf = new Buffer(vector.ct, 'hex') 55 | Aescbc.encrypt(ptbuf, keyBuf, ivBuf).slice(128 / 8).toString('hex').should.equal(vector.ct) 56 | Aescbc.decrypt(Buffer.concat([ivBuf, ctBuf]), keyBuf).toString('hex').should.equal(vector.pt) 57 | }) 58 | }) 59 | }) 60 | }) 61 | -------------------------------------------------------------------------------- /test/base-58-check.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let should = require('chai').should() 4 | let Base58Check = require('../lib/base-58-check') 5 | let base58 = require('../lib/base-58') 6 | 7 | describe('Base58Check', function () { 8 | let buf = new Buffer([0, 1, 2, 3, 253, 254, 255]) 9 | let enc = '14HV44ipwoaqfg' 10 | 11 | it('should make an instance with "new"', function () { 12 | let b58 = new Base58Check() 13 | should.exist(b58) 14 | }) 15 | 16 | it('should make an instance without "new"', function () { 17 | let b58 = new Base58Check() 18 | should.exist(b58) 19 | }) 20 | 21 | it('should allow this handy syntax', function () { 22 | new Base58Check(buf).toString().should.equal(enc) 23 | new Base58Check().fromString(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')) 24 | }) 25 | 26 | describe('#fromObject', function () { 27 | it('should set a buf', function () { 28 | should.exist(new Base58Check().fromObject({buf: buf}).buf) 29 | }) 30 | }) 31 | 32 | describe('@encode', function () { 33 | it('should encode the buffer accurately', function () { 34 | Base58Check.encode(buf).should.equal(enc) 35 | }) 36 | 37 | it('should throw an error when the input is not a buffer', function () { 38 | (function () { 39 | Base58Check.encode('string') 40 | }).should.throw('Input must be a buffer') 41 | }) 42 | }) 43 | 44 | describe('@decode', function () { 45 | it('should decode this encoded value correctly', function () { 46 | Base58Check.decode(enc).toString('hex').should.equal(buf.toString('hex')) 47 | }) 48 | 49 | it('should throw an error when input is not a string', function () { 50 | (function () { 51 | Base58Check.decode(5) 52 | }).should.throw('Input must be a string') 53 | }) 54 | 55 | it('should throw an error when input is too short', function () { 56 | (function () { 57 | Base58Check.decode(enc.slice(0, 1)) 58 | }).should.throw('Input string too short') 59 | }) 60 | 61 | it('should throw an error when there is a checksum mismatch', function () { 62 | let buf2 = base58.decode(enc) 63 | buf2[0] = buf2[0] + 1 64 | let enc2 = base58.encode(buf2) 65 | ;(function () { 66 | Base58Check.decode(enc2) 67 | }).should.throw('Checksum mismatch') 68 | }) 69 | }) 70 | 71 | describe('#fromHex', function () { 72 | it('should set buffer from hex', function () { 73 | let b58 = new Base58Check().fromHex(buf.toString('hex')) 74 | b58.buf.toString('hex').should.equal(buf.toString('hex')) 75 | }) 76 | }) 77 | 78 | describe('#fromBuffer', function () { 79 | it('should not fail', function () { 80 | should.exist(new Base58Check().fromBuffer(buf)) 81 | }) 82 | 83 | it('should set buffer', function () { 84 | let b58 = new Base58Check().fromBuffer(buf) 85 | b58.buf.toString('hex').should.equal(buf.toString('hex')) 86 | }) 87 | }) 88 | 89 | describe('#fromString', function () { 90 | it('should convert this known string to a buffer', function () { 91 | new Base58Check().fromString(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')) 92 | }) 93 | }) 94 | 95 | describe('#toHex', function () { 96 | it('should return the buffer', function () { 97 | let b58 = new Base58Check(buf) 98 | b58.toHex().should.equal(buf.toString('hex')) 99 | }) 100 | }) 101 | 102 | describe('#toBuffer', function () { 103 | it('should return the buffer', function () { 104 | let b58 = new Base58Check(buf) 105 | b58.toBuffer().toString('hex').should.equal(buf.toString('hex')) 106 | }) 107 | }) 108 | 109 | describe('#toString', function () { 110 | it('should return the buffer', function () { 111 | let b58 = new Base58Check(buf) 112 | b58.toString().should.equal(enc) 113 | }) 114 | }) 115 | }) 116 | -------------------------------------------------------------------------------- /test/base-58.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Base58 = require('../lib/base-58') 4 | let should = require('chai').should() 5 | 6 | describe('Base58', function () { 7 | let buf = new Buffer([0, 1, 2, 3, 253, 254, 255]) 8 | let enc = '1W7N4RuG' 9 | 10 | it('should make an instance with "new"', function () { 11 | let b58 = new Base58() 12 | should.exist(b58) 13 | }) 14 | 15 | it('should make an instance without "new"', function () { 16 | let b58 = new Base58() 17 | should.exist(b58) 18 | }) 19 | 20 | it('should allow this handy syntax', function () { 21 | new Base58(buf).toString().should.equal(enc) 22 | new Base58().fromString(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')) 23 | }) 24 | 25 | describe('#fromObject', function () { 26 | it('should set a blank buffer', function () { 27 | new Base58().fromObject({buf: new Buffer([])}) 28 | }) 29 | }) 30 | 31 | describe('@encode', function () { 32 | it('should encode the buffer accurately', function () { 33 | Base58.encode(buf).should.equal(enc) 34 | }) 35 | 36 | it('should throw an error when the Input is not a buffer', function () { 37 | (function () { 38 | Base58.encode('string') 39 | }).should.throw('Input should be a buffer') 40 | }) 41 | }) 42 | 43 | describe('@decode', function () { 44 | it('should decode this encoded value correctly', function () { 45 | Base58.decode(enc).toString('hex').should.equal(buf.toString('hex')) 46 | Buffer.isBuffer(Base58.decode(enc)).should.equal(true) 47 | }) 48 | 49 | it('should throw an error when Input is not a string', function () { 50 | (function () { 51 | Base58.decode(5) 52 | }).should.throw('Input should be a string') 53 | }) 54 | }) 55 | 56 | describe('#fromHex', function () { 57 | it('should set buffer', function () { 58 | let b58 = new Base58().fromHex(buf.toString('hex')) 59 | b58.buf.toString('hex').should.equal(buf.toString('hex')) 60 | }) 61 | }) 62 | 63 | describe('#fromBuffer', function () { 64 | it('should not fail', function () { 65 | should.exist(new Base58().fromBuffer(buf)) 66 | }) 67 | 68 | it('should set buffer', function () { 69 | let b58 = new Base58().fromBuffer(buf) 70 | b58.buf.toString('hex').should.equal(buf.toString('hex')) 71 | }) 72 | }) 73 | 74 | describe('#fromString', function () { 75 | it('should convert this known string to a buffer', function () { 76 | new Base58().fromString(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')) 77 | }) 78 | }) 79 | 80 | describe('#toHex', function () { 81 | it('should return the buffer in hex', function () { 82 | let b58 = new Base58(buf) 83 | b58.toHex().should.equal(buf.toString('hex')) 84 | }) 85 | }) 86 | 87 | describe('#toBuffer', function () { 88 | it('should return the buffer', function () { 89 | let b58 = new Base58(buf) 90 | b58.toBuffer().toString('hex').should.equal(buf.toString('hex')) 91 | }) 92 | }) 93 | 94 | describe('#toString', function () { 95 | it('should return the buffer', function () { 96 | let b58 = new Base58(buf) 97 | b58.toString().should.equal(enc) 98 | }) 99 | }) 100 | }) 101 | -------------------------------------------------------------------------------- /test/bip-68.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Bip68 = require('../lib/bip-68') 4 | let should = require('chai').should() 5 | 6 | describe('Bip68', function () { 7 | it('should exist', function () { 8 | should.exist(Bip68) 9 | should.exist(new Bip68()) 10 | }) 11 | 12 | describe('@nSequence2Height', function () { 13 | it('should convert nSequence to height', function () { 14 | Bip68.nSequence2Height(0xffffffff).should.equal(0x0000ffff) 15 | }) 16 | }) 17 | 18 | describe('@height2NSequence', function () { 19 | it('should convert height to nSequence', function () { 20 | Bip68.height2NSequence(0x0000ffff).should.equal(0x0000ffff) 21 | }) 22 | }) 23 | 24 | describe('@nSequence2Time', function () { 25 | it('should convert nSequence to time', function () { 26 | Bip68.nSequence2Time(0x0000000f).should.equal(0x0000000f << 9) 27 | Bip68.nSequence2Time(0x0fffffff).should.equal(0x0000ffff << 9) 28 | }) 29 | }) 30 | 31 | describe('@time2NSequence', function () { 32 | it('should convert time to nSequence', function () { 33 | Bip68.time2NSequence(0x00000001 << 9).should.equal(0x00000001 | (1 << 22)) 34 | Bip68.time2NSequence(0x000000ff << 9).should.equal(0x000000ff | (1 << 22)) 35 | }) 36 | }) 37 | 38 | describe('@nSequenceIsDisabled', function () { 39 | it('should know if nSequence interpretation as lock time is disabled', function () { 40 | Bip68.nSequenceIsDisabled(1 << 31).should.equal(true) 41 | Bip68.nSequenceIsDisabled(1 << 30).should.equal(false) 42 | }) 43 | }) 44 | 45 | describe('@nSequenceIsTime', function () { 46 | it('should know if nSequence is time', function () { 47 | Bip68.nSequenceIsTime(1 << 22).should.equal(true) 48 | Bip68.nSequenceIsTime(1 << 21).should.equal(false) 49 | }) 50 | }) 51 | 52 | describe('@nSequenceValue', function () { 53 | it('should get the value', function () { 54 | Bip68.nSequenceValue(0xfffffff).should.equal(0x0000ffff) 55 | }) 56 | }) 57 | }) 58 | -------------------------------------------------------------------------------- /test/block-header.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let BlockHeader = require('../lib/block-header') 4 | let Bw = require('../lib/bw') 5 | let Br = require('../lib/br') 6 | let should = require('chai').should() 7 | 8 | describe('BlockHeader', function () { 9 | let bh = new BlockHeader() 10 | let versionBytesNum = 1 11 | let prevBlockHashBuf = new Buffer(32) 12 | prevBlockHashBuf.fill(5) 13 | let merkleRootBuf = new Buffer(32) 14 | merkleRootBuf.fill(9) 15 | let time = 2 16 | let bits = 3 17 | let nonce = 4 18 | bh.fromObject({ 19 | versionBytesNum: versionBytesNum, 20 | prevBlockHashBuf: prevBlockHashBuf, 21 | merkleRootBuf: merkleRootBuf, 22 | time: time, 23 | bits: bits, 24 | nonce: nonce 25 | }) 26 | let bhhex = '0100000005050505050505050505050505050505050505050505050505050505050505050909090909090909090909090909090909090909090909090909090909090909020000000300000004000000' 27 | let bhbuf = new Buffer(bhhex, 'hex') 28 | 29 | it('should make a new blockHeader', function () { 30 | let blockHeader = new BlockHeader() 31 | should.exist(blockHeader) 32 | blockHeader = new BlockHeader() 33 | should.exist(blockHeader) 34 | }) 35 | 36 | describe('#fromObject', function () { 37 | it('should set all the variables', function () { 38 | bh.fromObject({ 39 | versionBytesNum: versionBytesNum, 40 | prevBlockHashBuf: prevBlockHashBuf, 41 | merkleRootBuf: merkleRootBuf, 42 | time: time, 43 | bits: bits, 44 | nonce: nonce 45 | }) 46 | should.exist(bh.versionBytesNum) 47 | should.exist(bh.prevBlockHashBuf) 48 | should.exist(bh.merkleRootBuf) 49 | should.exist(bh.time) 50 | should.exist(bh.bits) 51 | should.exist(bh.nonce) 52 | }) 53 | }) 54 | 55 | describe('#fromJSON', function () { 56 | it('should set all the variables', function () { 57 | let bh = new BlockHeader().fromJSON({ 58 | versionBytesNum: versionBytesNum, 59 | prevBlockHashBuf: prevBlockHashBuf.toString('hex'), 60 | merkleRootBuf: merkleRootBuf.toString('hex'), 61 | time: time, 62 | bits: bits, 63 | nonce: nonce 64 | }) 65 | should.exist(bh.versionBytesNum) 66 | should.exist(bh.prevBlockHashBuf) 67 | should.exist(bh.merkleRootBuf) 68 | should.exist(bh.time) 69 | should.exist(bh.bits) 70 | should.exist(bh.nonce) 71 | }) 72 | }) 73 | 74 | describe('#toJSON', function () { 75 | it('should set all the variables', function () { 76 | let json = bh.toJSON() 77 | should.exist(json.versionBytesNum) 78 | should.exist(json.prevBlockHashBuf) 79 | should.exist(json.merkleRootBuf) 80 | should.exist(json.time) 81 | should.exist(json.bits) 82 | should.exist(json.nonce) 83 | }) 84 | }) 85 | 86 | describe('#fromHex', function () { 87 | it('should parse this known hex string', function () { 88 | new BlockHeader().fromHex(bhhex).toBuffer().toString('hex').should.equal(bhhex) 89 | }) 90 | }) 91 | 92 | describe('#fromBuffer', function () { 93 | it('should parse this known buffer', function () { 94 | new BlockHeader().fromBuffer(bhbuf).toBuffer().toString('hex').should.equal(bhhex) 95 | }) 96 | }) 97 | 98 | describe('#fromBr', function () { 99 | it('should parse this known buffer', function () { 100 | new BlockHeader().fromBr(new Br(bhbuf)).toBuffer().toString('hex').should.equal(bhhex) 101 | }) 102 | }) 103 | 104 | describe('#toHex', function () { 105 | it('should output this known hex string', function () { 106 | new BlockHeader().fromBuffer(bhbuf).toHex().should.equal(bhhex) 107 | }) 108 | }) 109 | 110 | describe('#toBuffer', function () { 111 | it('should output this known buffer', function () { 112 | new BlockHeader().fromBuffer(bhbuf).toBuffer().toString('hex').should.equal(bhhex) 113 | }) 114 | }) 115 | 116 | describe('#toBw', function () { 117 | it('should output this known buffer', function () { 118 | new BlockHeader().fromBuffer(bhbuf).toBw().toBuffer().toString('hex').should.equal(bhhex) 119 | let bw = new Bw() 120 | new BlockHeader().fromBuffer(bhbuf).toBw(bw) 121 | bw.toBuffer().toString('hex').should.equal(bhhex) 122 | }) 123 | }) 124 | }) 125 | -------------------------------------------------------------------------------- /test/cmp.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let cmp = require('../lib/cmp') 4 | require('chai').should() 5 | 6 | describe('cmp', function () { 7 | it('should know if these buffers are equal', function () { 8 | let buf1, buf2 9 | 10 | buf1 = new Buffer([]) 11 | buf2 = new Buffer([]) 12 | cmp(buf1, buf2).should.equal(true) 13 | 14 | buf1 = new Buffer([1]) 15 | buf2 = new Buffer([]) 16 | cmp(buf1, buf2).should.equal(false) 17 | 18 | buf1 = new Buffer([]) 19 | buf2 = new Buffer([1]) 20 | cmp(buf1, buf2).should.equal(false) 21 | 22 | buf1 = new Buffer([1]) 23 | buf2 = new Buffer([1]) 24 | cmp(buf1, buf2).should.equal(true) 25 | 26 | buf1 = new Buffer([1, 1]) 27 | buf2 = new Buffer([1]) 28 | cmp(buf1, buf2).should.equal(false) 29 | 30 | buf1 = new Buffer([1]) 31 | buf2 = new Buffer([1, 1]) 32 | cmp(buf1, buf2).should.equal(false) 33 | 34 | buf1 = new Buffer([1, 1]) 35 | buf2 = new Buffer([1, 1]) 36 | cmp(buf1, buf2).should.equal(true) 37 | 38 | buf1 = new Buffer([1, 0]) 39 | buf2 = new Buffer([1, 1]) 40 | cmp(buf1, buf2).should.equal(false) 41 | 42 | buf1 = new Buffer([1]) 43 | buf2 = new Buffer([1, 0]) 44 | cmp(buf1, buf2).should.equal(false) 45 | ;(function () { 46 | let buf1 = '' 47 | let buf2 = new Buffer([0]) 48 | cmp(buf1, buf2) 49 | }).should.throw('buf1 and buf2 must be buffers') 50 | ;(function () { 51 | let buf1 = new Buffer([0]) 52 | let buf2 = '' 53 | cmp(buf1, buf2) 54 | }).should.throw('buf1 and buf2 must be buffers') 55 | }) 56 | }) 57 | -------------------------------------------------------------------------------- /test/ecies.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Ecies = require('../lib/ecies') 4 | let should = require('chai').should() 5 | let KeyPair = require('../lib/key-pair') 6 | let Hash = require('../lib/hash') 7 | let asink = require('asink') 8 | 9 | describe('#Ecies', function () { 10 | it('should make a new Ecies object', function () { 11 | should.exist(Ecies) 12 | }) 13 | 14 | let fromkey = new KeyPair().fromRandom() 15 | let tokey = new KeyPair().fromRandom() 16 | let messageBuf = Hash.sha256(new Buffer('my message is the hash of this string')) 17 | 18 | describe('@encrypt', function () { 19 | it('should return a buffer', function () { 20 | let encBuf = Ecies.encrypt(messageBuf, tokey.pubKey, fromkey) 21 | Buffer.isBuffer(encBuf).should.equal(true) 22 | }) 23 | 24 | it('should return a buffer if fromkey is not present', function () { 25 | let encBuf = Ecies.encrypt(messageBuf, tokey.pubKey) 26 | Buffer.isBuffer(encBuf).should.equal(true) 27 | }) 28 | }) 29 | 30 | describe('@asyncEncrypt', function () { 31 | it('should return a buffer', function () { 32 | return asink(function * () { 33 | let encBuf = yield Ecies.asyncEncrypt(messageBuf, tokey.pubKey, fromkey) 34 | Buffer.isBuffer(encBuf).should.equal(true) 35 | }, this) 36 | }) 37 | 38 | it('should return a buffer if fromkey is not present', function () { 39 | return asink(function * () { 40 | let encBuf = yield Ecies.asyncEncrypt(messageBuf, tokey.pubKey) 41 | Buffer.isBuffer(encBuf).should.equal(true) 42 | }, this) 43 | }) 44 | }) 45 | 46 | describe('@decrypt', function () { 47 | it('should decrypt that which was encrypted', function () { 48 | let encBuf = Ecies.encrypt(messageBuf, tokey.pubKey, fromkey) 49 | let messageBuf2 = Ecies.decrypt(encBuf, tokey.privKey) 50 | messageBuf2.toString('hex').should.equal(messageBuf.toString('hex')) 51 | }) 52 | 53 | it('should decrypt that which was encrypted if fromKeyPair was randomly generated', function () { 54 | let encBuf = Ecies.encrypt(messageBuf, tokey.pubKey) 55 | let messageBuf2 = Ecies.decrypt(encBuf, tokey.privKey) 56 | messageBuf2.toString('hex').should.equal(messageBuf.toString('hex')) 57 | }) 58 | }) 59 | 60 | describe('@asyncDecrypt', function () { 61 | it('should decrypt that which was encrypted', function () { 62 | return asink(function * () { 63 | let encBuf = yield Ecies.asyncEncrypt(messageBuf, tokey.pubKey, fromkey) 64 | let messageBuf2 = Ecies.decrypt(encBuf, tokey.privKey) 65 | messageBuf2.toString('hex').should.equal(messageBuf.toString('hex')) 66 | }, this) 67 | }) 68 | 69 | it('should decrypt that which was encrypted if fromKeyPair was randomly generated', function () { 70 | return asink(function * () { 71 | let encBuf = yield Ecies.asyncEncrypt(messageBuf, tokey.pubKey) 72 | let messageBuf2 = Ecies.decrypt(encBuf, tokey.privKey) 73 | messageBuf2.toString('hex').should.equal(messageBuf.toString('hex')) 74 | }, this) 75 | }) 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /test/get-blocks.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let GetBlocks = require('../lib/get-blocks') 4 | let should = require('chai').should() 5 | 6 | describe('GetBlocks', function () { 7 | it('should exist', function () { 8 | should.exist(GetBlocks) 9 | should.exist(new GetBlocks()) 10 | }) 11 | 12 | describe('#toBuffer', function () { 13 | it('should convert to a buffer', function () { 14 | let buf = new Buffer(32) 15 | buf.fill(0) 16 | let hashes = [buf] 17 | let getblocks = new GetBlocks().fromHashes(hashes) 18 | let getblocksbuf = getblocks.toBuffer() 19 | getblocksbuf.length.should.equal(4 + 1 + 0 + 32) 20 | }) 21 | }) 22 | 23 | describe('#fromBuffer', function () { 24 | it('should convert from a buffer', function () { 25 | let buf = new Buffer(32) 26 | buf.fill(0) 27 | let hashes = [buf] 28 | let getblocks = new GetBlocks().fromHashes(hashes) 29 | let getblocksbuf = getblocks.toBuffer() 30 | let getblocks2 = new GetBlocks().fromBuffer(getblocksbuf) 31 | should.exist(getblocks2.versionBytesNum) 32 | should.exist(getblocks2.hashBufsVi) 33 | should.exist(getblocks2.hashBufs) 34 | should.exist(getblocks2.stopHashBuf) 35 | }) 36 | }) 37 | 38 | describe('#fromHashes', function () { 39 | it('should convert from a list of one hash', function () { 40 | let buf = new Buffer(32) 41 | buf.fill(0) 42 | let hashes = [buf] 43 | let getblocks = new GetBlocks().fromHashes(hashes) 44 | should.exist(getblocks) 45 | getblocks.hashBufs.length.should.equal(0) 46 | should.exist(getblocks.stopHashBuf) 47 | }) 48 | 49 | it('should convert from a list of two hashes', function () { 50 | let buf = new Buffer(32) 51 | buf.fill(0) 52 | let hashes = [buf, buf] 53 | let getblocks = new GetBlocks().fromHashes(hashes) 54 | should.exist(getblocks) 55 | getblocks.hashBufs.length.should.equal(1) 56 | should.exist(getblocks.stopHashBuf) 57 | }) 58 | }) 59 | 60 | describe('@fromHashes', function () { 61 | it('should convert from a list of one hash', function () { 62 | let buf = new Buffer(32) 63 | buf.fill(0) 64 | let hashes = [buf] 65 | let getblocks = GetBlocks.fromHashes(hashes) 66 | should.exist(getblocks) 67 | getblocks.hashBufs.length.should.equal(0) 68 | should.exist(getblocks.stopHashBuf) 69 | }) 70 | 71 | it('should convert from a list of two hashes', function () { 72 | let buf = new Buffer(32) 73 | buf.fill(0) 74 | let hashes = [buf, buf] 75 | let getblocks = GetBlocks.fromHashes(hashes) 76 | should.exist(getblocks) 77 | getblocks.hashBufs.length.should.equal(1) 78 | should.exist(getblocks.stopHashBuf) 79 | }) 80 | }) 81 | 82 | describe('#toHashes', function () { 83 | it('should give a list of hashes', function () { 84 | let buf = new Buffer(32) 85 | buf.fill(0) 86 | let hashes = [buf, buf] 87 | let getblocks = new GetBlocks().fromHashes(hashes) 88 | let hashes2 = getblocks.toHashes() 89 | hashes2.length.should.equal(2) 90 | }) 91 | }) 92 | }) 93 | -------------------------------------------------------------------------------- /test/global.js: -------------------------------------------------------------------------------- 1 | /* global after */ 2 | /** 3 | * Global "before" and "after" to run before and after all tests. These can be 4 | * used to establish and also tear down global database connections, network 5 | * connections, and worker connections. It's important not to leave thins 6 | * hanging when the tests are done running so that the tests end properly. 7 | */ 8 | 'use strict' 9 | let Workers = require('../lib/workers') 10 | 11 | after(function () { 12 | Workers.endGlobalWorkers() 13 | }) 14 | -------------------------------------------------------------------------------- /test/helpers/interp.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | let Interp = require('../../lib/interp') 3 | let Script = require('../../lib/script') 4 | let Tx = require('../../lib/tx') 5 | let Bn = require('../../lib/bn') 6 | 7 | module.exports.testInterpPartial = function testInterpPartial (it, scriptValid, scriptInvalid, mod = 0) { 8 | let c 9 | 10 | c = 0 11 | scriptValid.forEach(function (vector, i) { 12 | if (vector.length === 1) { 13 | return 14 | } 15 | c++ 16 | if ((c + mod) % 4) { 17 | return 18 | } 19 | it('should verify scriptValid vector ' + c, function () { 20 | let scriptSig = new Script().fromBitcoindString(vector[0]) 21 | let scriptPubKey = new Script().fromBitcoindString(vector[1]) 22 | let flags = Interp.getFlags(vector[2]) 23 | 24 | let hashBuf = new Buffer(32) 25 | hashBuf.fill(0) 26 | let credtx = new Tx() 27 | credtx.addTxIn(hashBuf, 0xffffffff, new Script().writeString('OP_0 OP_0'), 0xffffffff) 28 | credtx.addTxOut(new Bn(0), scriptPubKey) 29 | 30 | let idbuf = credtx.hash() 31 | let spendtx = new Tx() 32 | spendtx.addTxIn(idbuf, 0, scriptSig, 0xffffffff) 33 | spendtx.addTxOut(new Bn(0), new Script()) 34 | 35 | let interp = new Interp() 36 | let verified = interp.verify(scriptSig, scriptPubKey, spendtx, 0, flags) 37 | verified.should.equal(true) 38 | }) 39 | }) 40 | 41 | c = 0 42 | scriptInvalid.forEach(function (vector, i) { 43 | if (vector.length === 1) { 44 | return 45 | } 46 | c++ 47 | if ((c + mod) % 4) { 48 | return 49 | } 50 | it('should unverify scriptInvalid vector ' + c, function () { 51 | let scriptSig = new Script().fromBitcoindString(vector[0]) 52 | let scriptPubKey = new Script().fromBitcoindString(vector[1]) 53 | let flags = Interp.getFlags(vector[2]) 54 | 55 | let hashBuf = new Buffer(32) 56 | hashBuf.fill(0) 57 | let credtx = new Tx() 58 | credtx.addTxIn(hashBuf, 0xffffffff, new Script().writeString('OP_0 OP_0'), 0xffffffff) 59 | credtx.addTxOut(new Bn(0), scriptPubKey) 60 | 61 | let idbuf = credtx.hash() 62 | let spendtx = new Tx() 63 | spendtx.addTxIn(idbuf, 0, scriptSig, 0xffffffff) 64 | spendtx.addTxOut(new Bn(0), new Script()) 65 | 66 | let interp = new Interp() 67 | let verified = interp.verify(scriptSig, scriptPubKey, spendtx, 0, flags) 68 | verified.should.equal(false) 69 | }) 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let should = require('chai').should() 4 | let YoursBitcoin = require('../') 5 | 6 | describe('yours-bitcoin', function () { 7 | it('should pass this sanity check on loading the main package', function () { 8 | should.exist(YoursBitcoin) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /test/interp-vectors-1.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let scriptValid = require('./vectors/bitcoind/script_valid') 4 | let scriptInvalid = require('./vectors/bitcoind/script_invalid') 5 | let testInterpPartial = require('./helpers/interp').testInterpPartial 6 | 7 | describe('Interp Vectors 1/4', function () { 8 | testInterpPartial(it, scriptValid, scriptInvalid, 0) 9 | }) 10 | -------------------------------------------------------------------------------- /test/interp-vectors-2.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let scriptValid = require('./vectors/bitcoind/script_valid') 4 | let scriptInvalid = require('./vectors/bitcoind/script_invalid') 5 | let testInterpPartial = require('./helpers/interp').testInterpPartial 6 | 7 | describe('Interp Vectors 2/4', function () { 8 | testInterpPartial(it, scriptValid, scriptInvalid, 1) 9 | }) 10 | -------------------------------------------------------------------------------- /test/interp-vectors-3.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let scriptValid = require('./vectors/bitcoind/script_valid') 4 | let scriptInvalid = require('./vectors/bitcoind/script_invalid') 5 | let testInterpPartial = require('./helpers/interp').testInterpPartial 6 | 7 | describe('Interp Vectors 3/4', function () { 8 | testInterpPartial(it, scriptValid, scriptInvalid, 2) 9 | }) 10 | -------------------------------------------------------------------------------- /test/interp-vectors-4.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let scriptValid = require('./vectors/bitcoind/script_valid') 4 | let scriptInvalid = require('./vectors/bitcoind/script_invalid') 5 | let testInterpPartial = require('./helpers/interp').testInterpPartial 6 | 7 | describe('Interp Vectors 4/4', function () { 8 | testInterpPartial(it, scriptValid, scriptInvalid, 3) 9 | }) 10 | -------------------------------------------------------------------------------- /test/inv.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Inv = require('../lib/inv') 4 | let Hash = require('../lib/hash') 5 | let Bw = require('../lib/bw') 6 | let should = require('chai').should() 7 | 8 | describe('Inv', function () { 9 | it('should exist', function () { 10 | let inv = new Inv() 11 | should.exist(inv) 12 | should.exist(Inv) 13 | }) 14 | 15 | describe('#fromBuffer', function () { 16 | it('should convert from a buffer', function () { 17 | let hashBuf = Hash.sha256(new Buffer(0)) 18 | let typeNum = 1 19 | let typebuf = new Bw().writeUInt32LE(typeNum).toBuffer() 20 | let buf = Buffer.concat([typebuf, hashBuf]) 21 | let inv = new Inv().fromBuffer(buf) 22 | inv.typeNum.should.equal(typeNum) 23 | Buffer.compare(inv.hashBuf, hashBuf).should.equal(0) 24 | }) 25 | }) 26 | 27 | describe('#toBuffer', function () { 28 | it('should convert to a buffer', function () { 29 | let hashBuf = Hash.sha256(new Buffer(0)) 30 | let typeNum = 1 31 | let typebuf = new Bw().writeUInt32LE(typeNum).toBuffer() 32 | let buf = Buffer.concat([typebuf, hashBuf]) 33 | let inv = new Inv().fromBuffer(buf) 34 | let buf2 = inv.toBuffer() 35 | Buffer.compare(buf, buf2).should.equal(0) 36 | }) 37 | }) 38 | 39 | describe('#isTx', function () { 40 | it('should know this is a tx hash', function () { 41 | let hashBuf = Hash.sha256(new Buffer(0)) 42 | let typeNum = Inv.MSG_TX 43 | let inv = new Inv(typeNum, hashBuf) 44 | inv.isTx().should.equal(true) 45 | }) 46 | }) 47 | 48 | describe('#isBlock', function () { 49 | it('should know this is a block hash', function () { 50 | let hashBuf = Hash.sha256(new Buffer(0)) 51 | let typeNum = Inv.MSG_BLOCK 52 | let inv = new Inv(typeNum, hashBuf) 53 | inv.isBlock().should.equal(true) 54 | }) 55 | }) 56 | 57 | describe('#isFilteredBlock', function () { 58 | it('should know this is a filtered block hash', function () { 59 | let hashBuf = Hash.sha256(new Buffer(0)) 60 | let typeNum = Inv.MSG_FILTERED_BLOCK 61 | let inv = new Inv(typeNum, hashBuf) 62 | inv.isFilteredBlock().should.equal(true) 63 | }) 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /test/kdf.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | require('chai').should() 4 | let Kdf = require('../lib/kdf') 5 | let Hash = require('../lib/hash') 6 | let vectors = require('./vectors/kdf') 7 | 8 | describe('Kdf', function () { 9 | it('should satisfy this basic API', function () { 10 | Kdf.Testnet.should.equal(Kdf.Testnet) 11 | Kdf.Mainnet.should.equal(Kdf.Mainnet) 12 | Kdf.Mainnet.should.not.equal(Kdf.Testnet) 13 | }) 14 | 15 | describe('@Pbkdf2', function () { 16 | it('should return values of the right size', function () { 17 | let passBuf = new Buffer([0]) 18 | let saltBuf = new Buffer([0]) 19 | let key1 = Kdf.Pbkdf2(passBuf, saltBuf) 20 | key1.length.should.equal(512 / 8) 21 | let key2 = Kdf.Pbkdf2(passBuf, saltBuf, 2) 22 | key2.length.should.equal(512 / 8) 23 | key1.toString('hex').should.not.equal(key2.toString('hex')) 24 | let key3 = Kdf.Pbkdf2(passBuf, saltBuf, 2, 1024) 25 | key3.length.should.equal(1024 / 8) 26 | let key4 = Kdf.Pbkdf2(passBuf, saltBuf, 2, 256, 'sha256') 27 | key4.length.should.equal(256 / 8) 28 | }) 29 | 30 | // Test vectors from: http://tools.ietf.org/html/rfc6070#section-2 31 | vectors.PBKDF2.valid.forEach(function (obj, i) { 32 | it('should work for Pbkdf2 test vector ' + i, function () { 33 | let passBuf = new Buffer(obj.p, 'hex') 34 | let saltBuf = new Buffer(obj.s, 'hex') 35 | let nIterations = obj.c 36 | let keyLenBits = obj.dkLen * 8 37 | let hmacf = obj.hmacf 38 | let key = Kdf.Pbkdf2(passBuf, saltBuf, nIterations, keyLenBits, hmacf) 39 | key.toString('hex').should.equal(obj.key) 40 | }) 41 | }) 42 | }) 43 | 44 | describe('@buf2KeyPair', function () { 45 | it('should compute these known values', function () { 46 | let buf = Hash.sha256(new Buffer('test')) 47 | let keyPair = Kdf.buf2KeyPair(buf) 48 | keyPair.privKey.toString().should.equal('KxxVszVMFLGzmxpxR7sMSaWDmqMKLVhKebX5vZbGHyuR8spreQ7V') 49 | keyPair.pubKey.toString().should.equal('03774f761ae89a0d2fda0d532bad62286ae8fcda9bc38c060036296085592a97c1') 50 | }) 51 | }) 52 | 53 | describe('@sha256Hmac2KeyPair', function () { 54 | it('should compute these known values', function () { 55 | let buf = Hash.sha256(new Buffer('test')) 56 | let keyPair = Kdf.sha256Hmac2KeyPair(buf) 57 | keyPair.privKey.toString().should.equal('KxxVszVMFLGzmxpxR7sMSaWDmqMKLVhKebX5vZbGHyuR8spreQ7V') 58 | keyPair.pubKey.toString().should.equal('03774f761ae89a0d2fda0d532bad62286ae8fcda9bc38c060036296085592a97c1') 59 | }) 60 | }) 61 | 62 | describe('@sha256Hmac2PrivKey', function () { 63 | it('should compute this known privKey', function () { 64 | let buf = Hash.sha256(new Buffer('test')) 65 | let privKey = Kdf.sha256Hmac2PrivKey(buf) 66 | privKey.toString().should.equal('KxxVszVMFLGzmxpxR7sMSaWDmqMKLVhKebX5vZbGHyuR8spreQ7V') 67 | }) 68 | }) 69 | }) 70 | -------------------------------------------------------------------------------- /test/msg-addr.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Addr = require('../lib/addr') 4 | let MsgAddr = require('../lib/msg-addr') 5 | let asink = require('asink') 6 | let should = require('chai').should() 7 | 8 | describe('MsgAddr', function () { 9 | let addrhex = 'e8030000000000000000000000000000000000000000000000000000208d' 10 | 11 | it('should exist', function () { 12 | should.exist(MsgAddr) 13 | should.exist(new MsgAddr()) 14 | }) 15 | 16 | describe('#fromAddrs', function () { 17 | it('should convert from addrs', function () { 18 | let addr = new Addr().fromHex(addrhex) 19 | let msgaddr = new MsgAddr().fromAddrs([addr]) 20 | msgaddr.getCmd().should.equal('addr') 21 | msgaddr.dataBuf.length.should.equal(1 + addrhex.length / 2) 22 | }) 23 | }) 24 | 25 | describe('@fromAddrs', function () { 26 | it('should convert from addrs', function () { 27 | let addr = Addr.fromHex(addrhex) 28 | let msgaddr = MsgAddr.fromAddrs([addr]) 29 | msgaddr.getCmd().should.equal('addr') 30 | msgaddr.dataBuf.length.should.equal(1 + addrhex.length / 2) 31 | }) 32 | }) 33 | 34 | describe('#asyncFromAddrs', function () { 35 | it('should convert from addrs', function () { 36 | return asink(function * () { 37 | let addr = new Addr().fromHex(addrhex) 38 | let msgaddr = yield new MsgAddr().asyncFromAddrs([addr]) 39 | msgaddr.getCmd().should.equal('addr') 40 | msgaddr.dataBuf.length.should.equal(1 + addrhex.length / 2) 41 | }, this) 42 | }) 43 | }) 44 | 45 | describe('@asyncFromAddrs', function () { 46 | it('should convert from addrs', function () { 47 | return asink(function * () { 48 | let addr = new Addr().fromHex(addrhex) 49 | let msgaddr = yield MsgAddr.asyncFromAddrs([addr]) 50 | msgaddr.getCmd().should.equal('addr') 51 | msgaddr.dataBuf.length.should.equal(1 + addrhex.length / 2) 52 | }, this) 53 | }) 54 | }) 55 | 56 | describe('#toAddrs', function () { 57 | it('should convert to addrs', function () { 58 | let addr = new Addr().fromHex(addrhex) 59 | let msgaddr = new MsgAddr().fromAddrs([addr]) 60 | let addrs2 = msgaddr.toAddrs() 61 | addrs2.length.should.equal(1) 62 | ;(addrs2[0] instanceof Addr).should.equal(true) 63 | }) 64 | 65 | it('should convert to multiple addrs', function () { 66 | let addr = new Addr().fromHex(addrhex) 67 | let msgaddr = new MsgAddr().fromAddrs([addr, addr, addr]) 68 | let addrs2 = msgaddr.toAddrs() 69 | addrs2.length.should.equal(3) 70 | ;(addrs2[0] instanceof Addr).should.equal(true) 71 | }) 72 | }) 73 | 74 | describe('#isValid', function () { 75 | it('should know this is a valid msg addrs', function () { 76 | let addr = new Addr().fromHex(addrhex) 77 | let msgaddr = new MsgAddr().fromAddrs([addr]) 78 | msgaddr.isValid().should.equal(true) 79 | }) 80 | }) 81 | }) 82 | -------------------------------------------------------------------------------- /test/msg-alert.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let MsgAlert = require('../lib/msg-alert') 4 | let should = require('chai').should() 5 | 6 | describe('MsgAlert', function () { 7 | it('should exist', function () { 8 | should.exist(MsgAlert) 9 | should.exist(new MsgAlert()) 10 | }) 11 | 12 | describe('#isValid', function () { 13 | it('should know this is a possibly-valid msgalert', function () { 14 | let msgalert = new MsgAlert() 15 | .setData(new Buffer(0)) 16 | msgalert.isValid().should.equal(true) 17 | }) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /test/msg-block.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Block = require('../lib/block') 4 | let MsgBlock = require('../lib/msg-block') 5 | let asink = require('asink') 6 | let should = require('chai').should() 7 | 8 | describe('MsgBlock', function () { 9 | let blockhex = 'f9beb4d93200000001000000050505050505050505050505050505050505050505050505050505050505050509090909090909090909090909090909090909090909090909090909090909090200000003000000040000000101000000029e8d016a7b0dc49a325922d05da1f916d1e4d4f0cb840c9727f3d22ce8d1363f000000008c493046022100e9318720bee5425378b4763b0427158b1051eec8b08442ce3fbfbf7b30202a44022100d4172239ebd701dae2fbaaccd9f038e7ca166707333427e3fb2a2865b19a7f27014104510c67f46d2cbb29476d1f0b794be4cb549ea59ab9cc1e731969a7bf5be95f7ad5e7f904e5ccf50a9dc1714df00fbeb794aa27aaff33260c1032d931a75c56f2ffffffffa3195e7a1ab665473ff717814f6881485dc8759bebe97e31c301ffe7933a656f020000008b48304502201c282f35f3e02a1f32d2089265ad4b561f07ea3c288169dedcf2f785e6065efa022100e8db18aadacb382eed13ee04708f00ba0a9c40e3b21cf91da8859d0f7d99e0c50141042b409e1ebbb43875be5edde9c452c82c01e3903d38fa4fd89f3887a52cb8aea9dc8aec7e2c9d5b3609c03eb16259a2537135a1bf0f9c5fbbcbdbaf83ba402442ffffffff02206b1000000000001976a91420bb5c3bfaef0231dc05190e7f1c8e22e098991e88acf0ca0100000000001976a9149e3e2d23973a04ec1b02be97c30ab9f2f27c3b2c88ac00000000' 10 | 11 | it('should exist', function () { 12 | let msgblock = new MsgBlock() 13 | should.exist(MsgBlock) 14 | should.exist(msgblock) 15 | }) 16 | 17 | describe('#fromBlock', function () { 18 | it('should convert a block into a msgblock', function () { 19 | let block = new Block().fromHex(blockhex) 20 | let msgblock = new MsgBlock().fromBlock(block) 21 | msgblock.isValid().should.equal(true) 22 | }) 23 | }) 24 | 25 | describe('@fromBlock', function () { 26 | it('should convert a block into a msgblock', function () { 27 | let block = Block.fromHex(blockhex) 28 | let msgblock = MsgBlock.fromBlock(block) 29 | msgblock.isValid().should.equal(true) 30 | }) 31 | }) 32 | 33 | describe('#asyncFromBlock', function () { 34 | it('should convert a block into a msgblock', function () { 35 | return asink(function * () { 36 | let block = new Block().fromHex(blockhex) 37 | let msgblock = yield new MsgBlock().asyncFromBlock(block) 38 | msgblock.isValid().should.equal(true) 39 | }, this) 40 | }) 41 | }) 42 | 43 | describe('@asyncFromBlock', function () { 44 | it('should convert a block into a msgblock', function () { 45 | return asink(function * () { 46 | let block = new Block().fromHex(blockhex) 47 | let msgblock = yield MsgBlock.asyncFromBlock(block) 48 | msgblock.isValid().should.equal(true) 49 | }, this) 50 | }) 51 | }) 52 | 53 | describe('#toBlock', function () { 54 | it('should convert a msgblock into a block', function () { 55 | let block = new Block().fromHex(blockhex) 56 | let msgblock = new MsgBlock().fromBlock(block) 57 | let block2 = msgblock.toBlock() 58 | block.toHex().should.equal(block2.toHex()) 59 | }) 60 | }) 61 | 62 | describe('#isValid', function () { 63 | it('should know this msgblock is or is not valid', function () { 64 | let block = new Block().fromHex(blockhex) 65 | let msgblock = new MsgBlock().fromBlock(block) 66 | msgblock.isValid().should.equal(true) 67 | msgblock.setCmd('blocko') 68 | msgblock.isValid().should.equal(false) 69 | }) 70 | }) 71 | }) 72 | -------------------------------------------------------------------------------- /test/msg-get-addr.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let MsgGetAddr = require('../lib/msg-get-addr') 4 | let should = require('chai').should() 5 | 6 | describe('MsgGetAddr', function () { 7 | it('should exist', function () { 8 | should.exist(MsgGetAddr) 9 | should.exist(new MsgGetAddr()) 10 | }) 11 | 12 | describe('#isValid', function () { 13 | it('should know this is a valid getaddr msg', function () { 14 | new MsgGetAddr().isValid().should.equal(true) 15 | }) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /test/msg-get-blocks.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let GetBlocks = require('../lib/get-blocks') 4 | let MsgGetBlocks = require('../lib/msg-get-blocks') 5 | let asink = require('asink') 6 | let should = require('chai').should() 7 | 8 | describe('MsgGetBlocks', function () { 9 | let hashBuf = new Buffer(32) 10 | hashBuf.fill(0) 11 | let hashes = [hashBuf] 12 | let getblocks = new GetBlocks().fromHashes(hashes) 13 | 14 | it('should exist', function () { 15 | should.exist(MsgGetBlocks) 16 | should.exist(new MsgGetBlocks()) 17 | }) 18 | 19 | describe('#fromGetBlocks', function () { 20 | it('should convert from getblocks', function () { 21 | let msggetblocks = new MsgGetBlocks().fromGetBlocks(getblocks) 22 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 23 | }) 24 | }) 25 | 26 | describe('@fromGetBlocks', function () { 27 | it('should convert from getblocks', function () { 28 | let msggetblocks = MsgGetBlocks.fromGetBlocks(getblocks) 29 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 30 | }) 31 | }) 32 | 33 | describe('#asyncFromGetBlocks', function () { 34 | it('should convert from getblocks', function () { 35 | return asink(function * () { 36 | let msggetblocks = yield new MsgGetBlocks().asyncFromGetBlocks(getblocks) 37 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 38 | }, this) 39 | }) 40 | }) 41 | 42 | describe('@asyncFromGetBlocks', function () { 43 | it('should convert from getblocks', function () { 44 | return asink(function * () { 45 | let msggetblocks = yield MsgGetBlocks.asyncFromGetBlocks(getblocks) 46 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 47 | }, this) 48 | }) 49 | }) 50 | 51 | describe('#fromHashes', function () { 52 | it('should convert from hashes', function () { 53 | let msggetblocks = new MsgGetBlocks().fromHashes(hashes) 54 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 55 | }) 56 | }) 57 | 58 | describe('@fromHashes', function () { 59 | it('should convert from hashes', function () { 60 | let msggetblocks = MsgGetBlocks.fromHashes(hashes) 61 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 62 | }) 63 | }) 64 | 65 | describe('#asyncFromHashes', function () { 66 | it('should convert from hashes', function () { 67 | return asink(function * () { 68 | let msggetblocks = yield new MsgGetBlocks().asyncFromHashes(hashes) 69 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 70 | }, this) 71 | }) 72 | }) 73 | 74 | describe('@asyncFromHashes', function () { 75 | it('should convert from hashes', function () { 76 | return asink(function * () { 77 | let msggetblocks = yield MsgGetBlocks.asyncFromHashes(hashes) 78 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 79 | }, this) 80 | }) 81 | }) 82 | 83 | describe('#toGetBlocks', function () { 84 | it('should return getblocks', function () { 85 | let msggetblocks = new MsgGetBlocks().fromHashes(hashes) 86 | let getblocks2 = msggetblocks.toGetBlocks() 87 | getblocks2.toHex().should.equal(getblocks2.toHex()) 88 | }) 89 | }) 90 | 91 | describe('#toHashes', function () { 92 | it('should return getblocks', function () { 93 | let msggetblocks = new MsgGetBlocks().fromHashes(hashes) 94 | let hashes2 = msggetblocks.toHashes() 95 | hashes2.length.should.equal(1) 96 | }) 97 | }) 98 | 99 | describe('#isValid', function () { 100 | it('should know this is a valid getblocks msg', function () { 101 | let msggetblocks = new MsgGetBlocks().fromHashes(hashes) 102 | msggetblocks.isValid().should.equal(true) 103 | }) 104 | }) 105 | }) 106 | -------------------------------------------------------------------------------- /test/msg-get-data.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Inv = require('../lib/inv') 4 | let MsgGetData = require('../lib/msg-get-data') 5 | let should = require('chai').should() 6 | 7 | describe('MsgGetData', function () { 8 | it('should exist', function () { 9 | should.exist(MsgGetData) 10 | should.exist(new MsgGetData()) 11 | }) 12 | 13 | describe('#fromInvs', function () { 14 | it('should convert from invs', function () { 15 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 16 | let msginv = new MsgGetData().fromInvs([inv]) 17 | msginv.getCmd().should.equal('getdata') 18 | msginv.dataBuf.length.should.equal(1 + 4 + 32) 19 | }) 20 | }) 21 | 22 | describe('#toInvs', function () { 23 | it('should convert to invs', function () { 24 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 25 | let msginv = new MsgGetData().fromInvs([inv]) 26 | let invs2 = msginv.toInvs() 27 | invs2.length.should.equal(1) 28 | ;(invs2[0] instanceof Inv).should.equal(true) 29 | }) 30 | }) 31 | 32 | describe('#isValid', function () { 33 | it('should know this is a valid msg invs', function () { 34 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 35 | let msginv = new MsgGetData().fromInvs([inv]) 36 | msginv.isValid().should.equal(true) 37 | }) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /test/msg-get-headers.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let GetBlocks = require('../lib/get-blocks') 4 | let MsgGetHeaders = require('../lib/msg-get-headers') 5 | let asink = require('asink') 6 | let should = require('chai').should() 7 | 8 | describe('MsgGetHeaders', function () { 9 | let hashBuf = new Buffer(32) 10 | hashBuf.fill(0) 11 | let hashes = [hashBuf] 12 | let getblocks = new GetBlocks().fromHashes(hashes) 13 | 14 | it('should exist', function () { 15 | should.exist(MsgGetHeaders) 16 | should.exist(new MsgGetHeaders()) 17 | }) 18 | 19 | describe('#fromGetBlocks', function () { 20 | it('should convert from getblocks', function () { 21 | let msggetblocks = new MsgGetHeaders().fromGetBlocks(getblocks) 22 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 23 | }) 24 | }) 25 | 26 | describe('#asyncFromGetBlocks', function () { 27 | it('should convert from getblocks', function () { 28 | return asink(function * () { 29 | let msggetblocks = yield new MsgGetHeaders().asyncFromGetBlocks(getblocks) 30 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 31 | }, this) 32 | }) 33 | }) 34 | 35 | describe('#fromHashes', function () { 36 | it('should convert from hashes', function () { 37 | let msggetblocks = new MsgGetHeaders().fromHashes(hashes) 38 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 39 | }) 40 | }) 41 | 42 | describe('#asyncFromHashes', function () { 43 | it('should convert from hashes', function () { 44 | return asink(function * () { 45 | let msggetblocks = yield new MsgGetHeaders().asyncFromHashes(hashes) 46 | msggetblocks.dataBuf.length.should.equal(4 + 1 + 0 + 32) 47 | }, this) 48 | }) 49 | }) 50 | 51 | describe('#toGetBlocks', function () { 52 | it('should return getblocks', function () { 53 | let msggetblocks = new MsgGetHeaders().fromHashes(hashes) 54 | let getblocks2 = msggetblocks.toGetBlocks() 55 | getblocks2.toHex().should.equal(getblocks2.toHex()) 56 | }) 57 | }) 58 | 59 | describe('#toHashes', function () { 60 | it('should return getblocks', function () { 61 | let msggetblocks = new MsgGetHeaders().fromHashes(hashes) 62 | let hashes2 = msggetblocks.toHashes() 63 | hashes2.length.should.equal(1) 64 | }) 65 | }) 66 | 67 | describe('#isValid', function () { 68 | it('should know this is a valid getheaders msg', function () { 69 | let msggetblocks = new MsgGetHeaders().fromHashes(hashes) 70 | msggetblocks.getCmd().should.equal('getheaders') 71 | msggetblocks.isValid().should.equal(true) 72 | }) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/msg-headers.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Block = require('../lib/block') 4 | let BlockHeader = require('../lib/block-header') 5 | let MsgHeaders = require('../lib/msg-headers') 6 | let asink = require('asink') 7 | let should = require('chai').should() 8 | 9 | describe('MsgHeaders', function () { 10 | let blockhex = 'f9beb4d93200000001000000050505050505050505050505050505050505050505050505050505050505050509090909090909090909090909090909090909090909090909090909090909090200000003000000040000000101000000029e8d016a7b0dc49a325922d05da1f916d1e4d4f0cb840c9727f3d22ce8d1363f000000008c493046022100e9318720bee5425378b4763b0427158b1051eec8b08442ce3fbfbf7b30202a44022100d4172239ebd701dae2fbaaccd9f038e7ca166707333427e3fb2a2865b19a7f27014104510c67f46d2cbb29476d1f0b794be4cb549ea59ab9cc1e731969a7bf5be95f7ad5e7f904e5ccf50a9dc1714df00fbeb794aa27aaff33260c1032d931a75c56f2ffffffffa3195e7a1ab665473ff717814f6881485dc8759bebe97e31c301ffe7933a656f020000008b48304502201c282f35f3e02a1f32d2089265ad4b561f07ea3c288169dedcf2f785e6065efa022100e8db18aadacb382eed13ee04708f00ba0a9c40e3b21cf91da8859d0f7d99e0c50141042b409e1ebbb43875be5edde9c452c82c01e3903d38fa4fd89f3887a52cb8aea9dc8aec7e2c9d5b3609c03eb16259a2537135a1bf0f9c5fbbcbdbaf83ba402442ffffffff02206b1000000000001976a91420bb5c3bfaef0231dc05190e7f1c8e22e098991e88acf0ca0100000000001976a9149e3e2d23973a04ec1b02be97c30ab9f2f27c3b2c88ac00000000' 11 | let block = new Block().fromHex(blockhex) 12 | let blockHeader = block.blockHeader 13 | 14 | it('should exist', function () { 15 | should.exist(MsgHeaders) 16 | should.exist(new MsgHeaders()) 17 | }) 18 | 19 | describe('#fromBlockHeaders', function () { 20 | it('should make a msg from blockHeaders', function () { 21 | let msgheaders = new MsgHeaders().fromBlockHeaders([blockHeader]) 22 | msgheaders.dataBuf.length.should.greaterThan(0) 23 | }) 24 | }) 25 | 26 | describe('@fromBlockHeaders', function () { 27 | it('should make a msg from blockHeaders', function () { 28 | let msgheaders = new MsgHeaders().fromBlockHeaders([blockHeader]) 29 | msgheaders.dataBuf.length.should.greaterThan(0) 30 | }) 31 | }) 32 | 33 | describe('#asyncFromBlockHeaders', function () { 34 | it('should make a msg from blockHeaders', function () { 35 | return asink(function * () { 36 | let msgheaders = yield new MsgHeaders().asyncFromBlockHeaders([blockHeader]) 37 | msgheaders.dataBuf.length.should.greaterThan(0) 38 | }, this) 39 | }) 40 | }) 41 | 42 | describe('#toBlockHeaders', function () { 43 | it('should make a msg from blockHeaders', function () { 44 | let msgheaders = new MsgHeaders().fromBlockHeaders([blockHeader, blockHeader, blockHeader]) 45 | let blockHeaders = msgheaders.toBlockHeaders() 46 | blockHeaders.length.should.equal(3) 47 | ;(blockHeaders[0] instanceof BlockHeader).should.equal(true) 48 | }) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /test/msg-inv.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Inv = require('../lib/inv') 4 | let MsgInv = require('../lib/msg-inv') 5 | let asink = require('asink') 6 | let should = require('chai').should() 7 | 8 | describe('MsgInv', function () { 9 | it('should exist', function () { 10 | should.exist(MsgInv) 11 | should.exist(new MsgInv()) 12 | }) 13 | 14 | describe('#fromInvs', function () { 15 | it('should convert from invs', function () { 16 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 17 | let msginv = new MsgInv().fromInvs([inv]) 18 | msginv.getCmd().should.equal('inv') 19 | msginv.dataBuf.length.should.equal(1 + 4 + 32) 20 | }) 21 | }) 22 | 23 | describe('@fromInvs', function () { 24 | it('should convert from invs', function () { 25 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 26 | let msginv = MsgInv.fromInvs([inv]) 27 | msginv.getCmd().should.equal('inv') 28 | msginv.dataBuf.length.should.equal(1 + 4 + 32) 29 | }) 30 | }) 31 | 32 | describe('#asyncFromInvs', function () { 33 | it('should convert from invs', function () { 34 | return asink(function * () { 35 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 36 | let msginv = yield new MsgInv().asyncFromInvs([inv]) 37 | msginv.getCmd().should.equal('inv') 38 | msginv.dataBuf.length.should.equal(1 + 4 + 32) 39 | }, this) 40 | }) 41 | }) 42 | 43 | describe('@asyncFromInvs', function () { 44 | it('should convert from invs', function () { 45 | return asink(function * () { 46 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 47 | let msginv = yield MsgInv.asyncFromInvs([inv]) 48 | msginv.getCmd().should.equal('inv') 49 | msginv.dataBuf.length.should.equal(1 + 4 + 32) 50 | }, this) 51 | }) 52 | }) 53 | 54 | describe('#toInvs', function () { 55 | it('should convert to invs', function () { 56 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 57 | let msginv = new MsgInv().fromInvs([inv]) 58 | let invs2 = msginv.toInvs() 59 | invs2.length.should.equal(1) 60 | ;(invs2[0] instanceof Inv).should.equal(true) 61 | }) 62 | }) 63 | 64 | describe('#isValid', function () { 65 | it('should know this is a valid msg invs', function () { 66 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 67 | let msginv = new MsgInv().fromInvs([inv]) 68 | msginv.isValid().should.equal(true) 69 | }) 70 | }) 71 | }) 72 | -------------------------------------------------------------------------------- /test/msg-mem-pool.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let MsgMemPool = require('../lib/msg-mem-pool') 4 | let should = require('chai').should() 5 | 6 | describe('MsgMemPool', function () { 7 | it('should exist', function () { 8 | should.exist(MsgMemPool) 9 | should.exist(new MsgMemPool()) 10 | }) 11 | 12 | describe('#isValid', function () { 13 | it('should know this is a valid mempool msg', function () { 14 | new MsgMemPool().isValid().should.equal(true) 15 | }) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /test/msg-not-found.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Inv = require('../lib/inv') 4 | let MsgNotFound = require('../lib/msg-not-found') 5 | let should = require('chai').should() 6 | 7 | describe('MsgNotFound', function () { 8 | it('should exist', function () { 9 | should.exist(MsgNotFound) 10 | should.exist(new MsgNotFound()) 11 | }) 12 | 13 | describe('#fromInvs', function () { 14 | it('should convert from invs', function () { 15 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 16 | let msginv = new MsgNotFound().fromInvs([inv]) 17 | msginv.getCmd().should.equal('notfound') 18 | msginv.dataBuf.length.should.equal(1 + 4 + 32) 19 | }) 20 | }) 21 | 22 | describe('#toInvs', function () { 23 | it('should convert to invs', function () { 24 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 25 | let msginv = new MsgNotFound().fromInvs([inv]) 26 | let invs2 = msginv.toInvs() 27 | invs2.length.should.equal(1) 28 | ;(invs2[0] instanceof Inv).should.equal(true) 29 | }) 30 | }) 31 | 32 | describe('#isValid', function () { 33 | it('should know this is a valid msg invs', function () { 34 | let inv = new Inv().fromBuffer(new Buffer('01000000' + '0'.repeat(64), 'hex')) 35 | let msginv = new MsgNotFound().fromInvs([inv]) 36 | msginv.isValid().should.equal(true) 37 | }) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /test/msg-ping.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let MsgPing = require('../lib/msg-ping') 4 | let Random = require('../lib/random') 5 | let asink = require('asink') 6 | let should = require('chai').should() 7 | 8 | describe('MsgPing', function () { 9 | it('should satisfy this basic API', function () { 10 | let msgping = new MsgPing() 11 | should.exist(msgping) 12 | msgping = new MsgPing() 13 | should.exist(msgping) 14 | should.exist(MsgPing.Mainnet) 15 | should.exist(MsgPing.Testnet) 16 | }) 17 | 18 | describe('#fromRandom', function () { 19 | it('should find a msgping from random', function () { 20 | let msgping = new MsgPing().fromRandom() 21 | msgping.getCmd().should.equal('ping') 22 | msgping.dataBuf.length.should.equal(8) 23 | }) 24 | }) 25 | 26 | describe('@fromRandom', function () { 27 | it('should find a msgping from random', function () { 28 | let msgping = MsgPing.fromRandom() 29 | msgping.getCmd().should.equal('ping') 30 | msgping.dataBuf.length.should.equal(8) 31 | }) 32 | }) 33 | 34 | describe('#asyncFromRandom', function () { 35 | it('should find a msgping from random', function () { 36 | return asink(function * () { 37 | let msgping = yield new MsgPing().asyncFromRandom() 38 | msgping.getCmd().should.equal('ping') 39 | msgping.dataBuf.length.should.equal(8) 40 | }, this) 41 | }) 42 | }) 43 | 44 | describe('@asyncFromRandom', function () { 45 | it('should find a msgping from random', function () { 46 | return asink(function * () { 47 | let msgping = yield MsgPing.asyncFromRandom() 48 | msgping.getCmd().should.equal('ping') 49 | msgping.dataBuf.length.should.equal(8) 50 | }, this) 51 | }) 52 | }) 53 | 54 | describe('#isValid', function () { 55 | it('should know this is a valid ping', function () { 56 | let msgping = new MsgPing().fromRandom() 57 | msgping.isValid().should.equal(true) 58 | }) 59 | 60 | it('should know this is an invalid ping', function () { 61 | let msgping = new MsgPing().fromRandom() 62 | msgping.setCmd('pingo') 63 | msgping.isValid().should.equal(false) 64 | }) 65 | 66 | it('should know this is an invalid ping', function () { 67 | let msgping = new MsgPing().fromRandom() 68 | msgping.setData(Random.getRandomBuffer(9)) 69 | msgping.isValid().should.equal(false) 70 | }) 71 | }) 72 | }) 73 | -------------------------------------------------------------------------------- /test/msg-pong.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let MsgPing = require('../lib/msg-ping') 4 | let MsgPong = require('../lib/msg-pong') 5 | let Random = require('../lib/random') 6 | let should = require('chai').should() 7 | 8 | describe('MsgPong', function () { 9 | it('should satisfy this basic API', function () { 10 | let msgping = new MsgPong() 11 | should.exist(msgping) 12 | msgping = new MsgPong() 13 | should.exist(msgping) 14 | should.exist(MsgPong.Mainnet) 15 | should.exist(MsgPong.Testnet) 16 | }) 17 | 18 | describe('#fromMsgPing', function () { 19 | it('should find a msgpong from a msgping', function () { 20 | let msgping = new MsgPing().fromRandom() 21 | let msgpong = new MsgPong().fromMsgPing(msgping) 22 | Buffer.compare(msgping.dataBuf, msgpong.dataBuf).should.equal(0) 23 | msgpong.getCmd().should.equal('pong') 24 | }) 25 | }) 26 | 27 | describe('@fromMsgPing', function () { 28 | it('should find a msgpong from a msgping', function () { 29 | let msgping = MsgPing.fromRandom() 30 | let msgpong = MsgPong.fromMsgPing(msgping) 31 | Buffer.compare(msgping.dataBuf, msgpong.dataBuf).should.equal(0) 32 | msgpong.getCmd().should.equal('pong') 33 | }) 34 | }) 35 | 36 | describe('#isValid', function () { 37 | it('should know this is a valid pong', function () { 38 | let msgping = new MsgPing().fromRandom() 39 | let msgpong = new MsgPong().fromMsgPing(msgping) 40 | msgpong.isValid().should.equal(true) 41 | }) 42 | 43 | it('should know this is an invalid ping', function () { 44 | let msgping = new MsgPing().fromRandom() 45 | let msgpong = new MsgPong().fromMsgPing(msgping) 46 | msgpong.setCmd('pongo') 47 | msgpong.isValid().should.equal(false) 48 | }) 49 | 50 | it('should know this is an invalid ping', function () { 51 | let msgping = new MsgPing().fromRandom() 52 | let msgpong = new MsgPong().fromMsgPing(msgping) 53 | msgpong.setData(Random.getRandomBuffer(9)) 54 | msgpong.isValid().should.equal(false) 55 | }) 56 | }) 57 | }) 58 | -------------------------------------------------------------------------------- /test/msg-reject.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Reject = require('../lib/reject') 4 | let MsgReject = require('../lib/msg-reject') 5 | let VarInt = require('../lib/var-int') 6 | let asink = require('asink') 7 | let should = require('chai').should() 8 | 9 | describe('MsgReject', function () { 10 | it('should exist', function () { 11 | should.exist(MsgReject) 12 | should.exist(new MsgReject()) 13 | }) 14 | 15 | describe('#fromReject', function () { 16 | it('should convert from a reject', function () { 17 | let reject = new Reject().fromObject({ 18 | typeVi: new VarInt().fromNumber(2), 19 | typeStr: 'tx', 20 | codeNum: 1, 21 | reasonVi: new VarInt().fromNumber(2), 22 | reasonStr: 'hi', 23 | extraBuf: new Buffer(0) 24 | }) 25 | let msgreject = new MsgReject().fromReject(reject) 26 | Buffer.compare(msgreject.dataBuf, reject.toBuffer()).should.equal(0) 27 | }) 28 | }) 29 | 30 | describe('@fromReject', function () { 31 | it('should convert from a reject', function () { 32 | let reject = new Reject().fromObject({ 33 | typeVi: new VarInt().fromNumber(2), 34 | typeStr: 'tx', 35 | codeNum: 1, 36 | reasonVi: new VarInt().fromNumber(2), 37 | reasonStr: 'hi', 38 | extraBuf: new Buffer(0) 39 | }) 40 | let msgreject = MsgReject.fromReject(reject) 41 | Buffer.compare(msgreject.dataBuf, reject.toBuffer()).should.equal(0) 42 | }) 43 | }) 44 | 45 | describe('#asyncFromReject', function () { 46 | it('should convert from a reject', function () { 47 | return asink(function * () { 48 | let reject = new Reject().fromObject({ 49 | typeVi: new VarInt().fromNumber(2), 50 | typeStr: 'tx', 51 | codeNum: 1, 52 | reasonVi: new VarInt().fromNumber(2), 53 | reasonStr: 'hi', 54 | extraBuf: new Buffer(0) 55 | }) 56 | let msgreject = yield new MsgReject().asyncFromReject(reject) 57 | Buffer.compare(msgreject.dataBuf, reject.toBuffer()).should.equal(0) 58 | }, this) 59 | }) 60 | }) 61 | 62 | describe('@asyncFromReject', function () { 63 | it('should convert from a reject', function () { 64 | return asink(function * () { 65 | let reject = new Reject().fromObject({ 66 | typeVi: new VarInt().fromNumber(2), 67 | typeStr: 'tx', 68 | codeNum: 1, 69 | reasonVi: new VarInt().fromNumber(2), 70 | reasonStr: 'hi', 71 | extraBuf: new Buffer(0) 72 | }) 73 | let msgreject = yield MsgReject.asyncFromReject(reject) 74 | Buffer.compare(msgreject.dataBuf, reject.toBuffer()).should.equal(0) 75 | }, this) 76 | }) 77 | }) 78 | 79 | describe('#toReject', function () { 80 | it('should convert to a reject', function () { 81 | return asink(function * () { 82 | let reject = new Reject().fromObject({ 83 | typeVi: new VarInt().fromNumber(2), 84 | typeStr: 'tx', 85 | codeNum: 1, 86 | reasonVi: new VarInt().fromNumber(2), 87 | reasonStr: 'hi', 88 | extraBuf: new Buffer(0) 89 | }) 90 | let reject2 = new MsgReject().fromReject(reject).toReject() 91 | Buffer.compare(reject2.toBuffer(), reject.toBuffer()).should.equal(0) 92 | }, this) 93 | }) 94 | }) 95 | 96 | describe('#isValid', function () { 97 | it('should know this is a valid msgreject', function () { 98 | let reject = new Reject().fromObject({ 99 | typeVi: new VarInt().fromNumber(2), 100 | typeStr: 'tx', 101 | codeNum: 1, 102 | reasonVi: new VarInt().fromNumber(2), 103 | reasonStr: 'hi', 104 | extraBuf: new Buffer(0) 105 | }) 106 | let msgreject = new MsgReject().fromReject(reject) 107 | msgreject.isValid().should.equal(true) 108 | }) 109 | }) 110 | }) 111 | -------------------------------------------------------------------------------- /test/msg-send-header.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let MsgSendHeaders = require('../lib/msg-send-headers') 4 | let should = require('chai').should() 5 | 6 | describe('MsgSendHeaders', function () { 7 | it('should exist', function () { 8 | should.exist(MsgSendHeaders) 9 | should.exist(new MsgSendHeaders()) 10 | }) 11 | 12 | describe('#isValid', function () { 13 | it('should know this is a valid sendheaders msg', function () { 14 | new MsgSendHeaders().isValid().should.equal(true) 15 | }) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /test/msg-tx.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Tx = require('../lib/tx') 4 | let MsgTx = require('../lib/msg-tx') 5 | let asink = require('asink') 6 | let should = require('chai').should() 7 | 8 | describe('MsgTx', function () { 9 | let txhex = '01000000029e8d016a7b0dc49a325922d05da1f916d1e4d4f0cb840c9727f3d22ce8d1363f000000008c493046022100e9318720bee5425378b4763b0427158b1051eec8b08442ce3fbfbf7b30202a44022100d4172239ebd701dae2fbaaccd9f038e7ca166707333427e3fb2a2865b19a7f27014104510c67f46d2cbb29476d1f0b794be4cb549ea59ab9cc1e731969a7bf5be95f7ad5e7f904e5ccf50a9dc1714df00fbeb794aa27aaff33260c1032d931a75c56f2ffffffffa3195e7a1ab665473ff717814f6881485dc8759bebe97e31c301ffe7933a656f020000008b48304502201c282f35f3e02a1f32d2089265ad4b561f07ea3c288169dedcf2f785e6065efa022100e8db18aadacb382eed13ee04708f00ba0a9c40e3b21cf91da8859d0f7d99e0c50141042b409e1ebbb43875be5edde9c452c82c01e3903d38fa4fd89f3887a52cb8aea9dc8aec7e2c9d5b3609c03eb16259a2537135a1bf0f9c5fbbcbdbaf83ba402442ffffffff02206b1000000000001976a91420bb5c3bfaef0231dc05190e7f1c8e22e098991e88acf0ca0100000000001976a9149e3e2d23973a04ec1b02be97c30ab9f2f27c3b2c88ac00000000' 10 | 11 | it('should exist', function () { 12 | let msgtx = new MsgTx() 13 | should.exist(MsgTx) 14 | should.exist(msgtx) 15 | }) 16 | 17 | describe('#fromTx', function () { 18 | it('should convert a tx into a msgtx', function () { 19 | let tx = new Tx().fromHex(txhex) 20 | let msgtx = new MsgTx().fromTx(tx) 21 | msgtx.isValid().should.equal(true) 22 | }) 23 | }) 24 | 25 | describe('@fromTx', function () { 26 | it('should convert a tx into a msgtx', function () { 27 | let tx = new Tx().fromHex(txhex) 28 | let msgtx = MsgTx.fromTx(tx) 29 | msgtx.isValid().should.equal(true) 30 | }) 31 | }) 32 | 33 | describe('#asyncFromTx', function () { 34 | it('should convert a tx into a msgtx', function () { 35 | return asink(function * () { 36 | let tx = new Tx().fromHex(txhex) 37 | let msgtx = yield new MsgTx().asyncFromTx(tx) 38 | msgtx.isValid().should.equal(true) 39 | }, this) 40 | }) 41 | }) 42 | 43 | describe('@asyncFromTx', function () { 44 | it('should convert a tx into a msgtx', function () { 45 | return asink(function * () { 46 | let tx = new Tx().fromHex(txhex) 47 | let msgtx = yield MsgTx.asyncFromTx(tx) 48 | msgtx.isValid().should.equal(true) 49 | }, this) 50 | }) 51 | }) 52 | 53 | describe('#toTx', function () { 54 | it('should convert a msgtx into a tx', function () { 55 | let tx = new Tx().fromHex(txhex) 56 | let msgtx = new MsgTx().fromTx(tx) 57 | let tx2 = msgtx.toTx() 58 | tx.toHex().should.equal(tx2.toHex()) 59 | }) 60 | }) 61 | 62 | describe('#isValid', function () { 63 | it('should know this msgtx is or is not valid', function () { 64 | let tx = new Tx().fromHex(txhex) 65 | let msgtx = new MsgTx().fromTx(tx) 66 | msgtx.isValid().should.equal(true) 67 | msgtx.setCmd('txo') 68 | msgtx.isValid().should.equal(false) 69 | }) 70 | }) 71 | }) 72 | -------------------------------------------------------------------------------- /test/msg-ver-ack.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let MsgVerAck = require('../lib/msg-ver-ack') 4 | let should = require('chai').should() 5 | 6 | describe('MsgVerAck', function () { 7 | it('should exist', function () { 8 | should.exist(MsgVerAck) 9 | should.exist(new MsgVerAck()) 10 | }) 11 | 12 | describe('#isValid', function () { 13 | it('should know this is a valid verack msg', function () { 14 | new MsgVerAck().isValid().should.equal(true) 15 | }) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /test/msg-version.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Bn = require('../lib/bn') 4 | let MsgVersion = require('../lib/msg-version') 5 | let VarInt = require('../lib/var-int') 6 | let Version = require('../lib/version') 7 | let asink = require('asink') 8 | let should = require('chai').should() 9 | 10 | describe('Version', function () { 11 | let version = Version.fromObject({ 12 | versionBytesNum: 0, 13 | servicesBuf: Buffer.alloc(8), 14 | timeBn: new Bn(0), 15 | addrRecvServicesBuf: Buffer.alloc(8), 16 | addrRecvIpAddrBuf: Buffer.alloc(16), 17 | addrRecvPort: 0, 18 | addrTransServicesBuf: Buffer.alloc(8), 19 | addrTransIpAddrBuf: Buffer.alloc(16), 20 | addrTransPort: 0, 21 | nonceBuf: Buffer.alloc(8), 22 | userAgentVi: VarInt.fromNumber('test'.length), 23 | userAgentBuf: new Buffer('test'), 24 | startHeightNum: 100, 25 | relay: true 26 | }) 27 | 28 | it('should exist', function () { 29 | should.exist(Version) 30 | should.exist(new Version()) 31 | }) 32 | 33 | describe('#fromVersion', function () { 34 | it('should convert from a version', function () { 35 | let msgVersion = new MsgVersion().fromVersion(version) 36 | ;(msgVersion instanceof MsgVersion).should.equal(true) 37 | }) 38 | }) 39 | 40 | describe('@fromVersion', function () { 41 | it('should convert from a version', function () { 42 | let msgVersion = MsgVersion.fromVersion(version) 43 | ;(msgVersion instanceof MsgVersion).should.equal(true) 44 | }) 45 | }) 46 | 47 | describe('#asyncFromVersion', function () { 48 | it('should convert from a version', function () { 49 | return asink(function * () { 50 | let msgVersion = yield new MsgVersion().asyncFromVersion(version) 51 | ;(msgVersion instanceof MsgVersion).should.equal(true) 52 | }, this) 53 | }) 54 | }) 55 | 56 | describe('@asyncFromVersion', function () { 57 | it('should convert from a version', function () { 58 | return asink(function * () { 59 | let msgVersion = yield MsgVersion.asyncFromVersion(version) 60 | ;(msgVersion instanceof MsgVersion).should.equal(true) 61 | }, this) 62 | }) 63 | }) 64 | 65 | describe('#toVersion', function () { 66 | it('should get a version', function () { 67 | let msgVersion = MsgVersion.fromVersion(version) 68 | let version2 = msgVersion.toVersion() 69 | version2.toHex().should.equal(version.toHex()) 70 | ;(version2 instanceof Version).should.equal(true) 71 | }) 72 | }) 73 | 74 | describe('#isValid', function () { 75 | it('should know this is a valid MsgVersion', function () { 76 | let msgVersion = MsgVersion.fromVersion(version) 77 | msgVersion.isValid().should.equal(true) 78 | }) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /test/op-code.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let should = require('chai').should() 4 | let OpCode = require('../lib/op-code') 5 | 6 | describe('OpCode', function () { 7 | it('should create a new OpCode', function () { 8 | let opCode = new OpCode(5) 9 | should.exist(opCode) 10 | }) 11 | 12 | it('should have 121 opCodes', function () { 13 | let i = 0 14 | for (let key in OpCode) { 15 | if (key.indexOf('OP_') !== -1) { 16 | i++ 17 | } 18 | } 19 | i.should.equal(121) 20 | }) 21 | 22 | it('should convert to a string with this handy syntax', function () { 23 | new OpCode(0).toString().should.equal('OP_0') 24 | new OpCode(96).toString().should.equal('OP_16') 25 | new OpCode(97).toString().should.equal('OP_NOP') 26 | }) 27 | 28 | it('should convert to a number with this handy syntax', function () { 29 | new OpCode().fromString('OP_0').toNumber().should.equal(0) 30 | new OpCode().fromString('OP_16').toNumber().should.equal(96) 31 | new OpCode().fromString('OP_NOP').toNumber().should.equal(97) 32 | }) 33 | 34 | describe('#fromNumber', function () { 35 | it('should work for 0', function () { 36 | new OpCode().fromNumber(0).num.should.equal(0) 37 | }) 38 | }) 39 | 40 | describe('#toNumber', function () { 41 | it('should work for 0', function () { 42 | new OpCode().fromNumber(0).toNumber().should.equal(0) 43 | }) 44 | }) 45 | 46 | describe('#fromString', function () { 47 | it('should work for OP_0', function () { 48 | new OpCode().fromString('OP_0').num.should.equal(0) 49 | }) 50 | }) 51 | 52 | describe('#toString', function () { 53 | it('should work for OP_0', function () { 54 | new OpCode().fromString('OP_0').toString().should.equal('OP_0') 55 | }) 56 | }) 57 | 58 | describe('@str', function () { 59 | it('should exist and have op 185', function () { 60 | should.exist(OpCode.str) 61 | OpCode.str[185].should.equal('OP_NOP10') 62 | }) 63 | }) 64 | }) 65 | -------------------------------------------------------------------------------- /test/random.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | require('chai').should() 4 | let Random = require('../lib/random') 5 | 6 | describe('Random', function () { 7 | describe('@getRandomBuffer', function () { 8 | it('should return a buffer', function () { 9 | let bytes = Random.getRandomBuffer(8) 10 | bytes.length.should.equal(8) 11 | Buffer.isBuffer(bytes).should.equal(true) 12 | }) 13 | 14 | it('should not equate two 256 bit random buffers', function () { 15 | let bytes1 = Random.getRandomBuffer(32) 16 | let bytes2 = Random.getRandomBuffer(32) 17 | bytes1.toString('hex').should.not.equal(bytes2.toString('hex')) 18 | }) 19 | 20 | it('should generate 100 8 byte buffers in a row that are not equal', function () { 21 | let hexs = [] 22 | for (let i = 0; i < 100; i++) { 23 | hexs[i] = Random.getRandomBuffer(8).toString('hex') 24 | } 25 | for (let i = 0; i < 100; i++) { 26 | for (let j = i + 1; j < 100; j++) { 27 | hexs[i].should.not.equal(hexs[j]) 28 | } 29 | } 30 | }) 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /test/reject.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Reject = require('../lib/reject') 4 | let VarInt = require('../lib/var-int') 5 | let should = require('chai').should() 6 | 7 | describe('Reject', function () { 8 | it('should exist', function () { 9 | should.exist(Reject) 10 | should.exist(new Reject()) 11 | }) 12 | 13 | describe('#toBuffer', function () { 14 | it('should convert to a buffer', function () { 15 | let reject = new Reject().fromObject({ 16 | typeVi: new VarInt().fromNumber(2), 17 | typeStr: 'tx', 18 | codeNum: 1, 19 | reasonVi: new VarInt().fromNumber(2), 20 | reasonStr: 'hi', 21 | extraBuf: new Buffer(0) 22 | }) 23 | Buffer.isBuffer(reject.toBuffer()).should.equal(true) 24 | }) 25 | }) 26 | 27 | describe('#fromBuffer', function () { 28 | it('should convert from a buffer', function () { 29 | let reject = new Reject().fromObject({ 30 | typeVi: new VarInt().fromNumber(2), 31 | typeStr: 'tx', 32 | codeNum: 1, 33 | reasonVi: new VarInt().fromNumber(2), 34 | reasonStr: 'hi', 35 | extraBuf: new Buffer(0) 36 | }) 37 | let reject2 = new Reject().fromBuffer(reject.toBuffer()) 38 | reject.typeStr.should.equal(reject2.typeStr) 39 | reject.codeNum.should.equal(reject2.codeNum) 40 | reject.reasonStr.should.equal(reject2.reasonStr) 41 | Buffer.compare(reject.extraBuf, reject2.extraBuf).should.equal(0) 42 | }) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /test/tx-out-map.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let should = require('chai').should() 4 | let TxOutMap = require('../lib/tx-out-map') 5 | let Tx = require('../lib/tx') 6 | let TxOut = require('../lib/tx-out') 7 | let Script = require('../lib/script') 8 | let Bn = require('../lib/bn') 9 | 10 | describe('TxOutMap', function () { 11 | let txHashBuf = new Buffer(32) 12 | txHashBuf.fill(0) 13 | let label = txHashBuf.toString('hex') + ':' + '0' 14 | let txOut = TxOut.fromProperties(new Bn(0), new Script('OP_RETURN')) 15 | let map = new Map() 16 | map.set(label, txOut) 17 | let tx = new Tx().fromHex('0100000001795b88d47a74e3be0948fc9d1b4737f96097474d57151afa6f77c787961e47cc120000006a47304402202289f9e1ae2ed981cd0bf62f822f6ae4aea40c65c7339d90643cea90de93ad1502205c8a08b3265f9ba7e99057d030d5b91c889a1b99f94a3a5b79d7daaada2409b6012103798b51f980e7a3690af6b43ce3467db75bede190385702c4d9d48c0a735ff4a9ffffffff01c0a83200000000001976a91447b8e62e008f82d95d1f565055a8243cc243d32388ac00000000') 18 | 19 | it('should make a new txOutMap', function () { 20 | let txOutMap = new TxOutMap() 21 | txOutMap = new TxOutMap({map: map}) 22 | should.exist(txOutMap) 23 | should.exist(txOutMap.map) 24 | }) 25 | 26 | describe('#fromObject', function () { 27 | it('should set a map', function () { 28 | let txOutMap = new TxOutMap().fromObject({map: map}) 29 | txOutMap.map.get(label).toHex().should.equal(txOut.toHex()) 30 | txOutMap.fromObject({}) 31 | txOutMap.map.get(label).toHex().should.equal(txOut.toHex()) 32 | }) 33 | }) 34 | 35 | describe('#toJSON', function () { 36 | it('convert to json', function () { 37 | let txOutMap = new TxOutMap().add(txHashBuf, 0, txOut) 38 | .add(txHashBuf, 1, txOut) 39 | .add(txHashBuf, 2, txOut) 40 | let json = txOutMap.toJSON() 41 | Object.keys(json).length.should.equal(3) 42 | }) 43 | }) 44 | 45 | describe('#fromJSON', function () { 46 | it('convert to/from json roundtrip', function () { 47 | let txOutMap = new TxOutMap().add(txHashBuf, 0, txOut) 48 | .add(txHashBuf, 1, txOut) 49 | .add(txHashBuf, 2, txOut) 50 | let txOutMap2 = new TxOutMap().fromJSON(txOutMap.toJSON()) 51 | txOutMap2.get(txHashBuf, 0).toHex().should.equal(txOutMap.get(txHashBuf, 0).toHex()) 52 | txOutMap2.get(txHashBuf, 1).toHex().should.equal(txOutMap.get(txHashBuf, 1).toHex()) 53 | txOutMap2.get(txHashBuf, 2).toHex().should.equal(txOutMap.get(txHashBuf, 2).toHex()) 54 | }) 55 | }) 56 | 57 | describe('#add', function () { 58 | it('should add a txOut to the txOutMap', function () { 59 | let txOutMap = new TxOutMap().add(txHashBuf, 0, txOut) 60 | should.exist(txOutMap.map.get(label)) 61 | }) 62 | }) 63 | 64 | describe('#get', function () { 65 | it('should get a txOut', function () { 66 | let txOutMap = new TxOutMap().fromObject({map: map}) 67 | txOutMap.get(txHashBuf, 0).toHex().should.equal(txOut.toHex()) 68 | }) 69 | }) 70 | 71 | describe('#addTx', function () { 72 | it('should add all outputs from a tx', function () { 73 | let txOutMap = new TxOutMap().addTx(tx) 74 | let txHashBuf = tx.hash() 75 | let txOut = tx.txOuts[0] 76 | txOutMap.get(txHashBuf, 0).toHex().should.equal(txOut.toHex()) 77 | }) 78 | }) 79 | }) 80 | -------------------------------------------------------------------------------- /test/tx-verifier-vectors-1.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let txInvalid = require('./vectors/bitcoind/tx_invalid') 4 | let txValid = require('./vectors/bitcoind/tx_valid') 5 | let testTxVerifierPartial = require('./helpers/tx-verifier').testTxVerifierPartial 6 | 7 | describe('TxVerifier Vectors 1/4', function () { 8 | testTxVerifierPartial(it, txValid, txInvalid, 0) 9 | }) 10 | -------------------------------------------------------------------------------- /test/tx-verifier-vectors-2.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let txInvalid = require('./vectors/bitcoind/tx_invalid') 4 | let txValid = require('./vectors/bitcoind/tx_valid') 5 | let testTxVerifierPartial = require('./helpers/tx-verifier').testTxVerifierPartial 6 | 7 | describe('TxVerifier Vectors 2/4', function () { 8 | testTxVerifierPartial(it, txValid, txInvalid, 1) 9 | }) 10 | -------------------------------------------------------------------------------- /test/tx-verifier-vectors-3.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let txInvalid = require('./vectors/bitcoind/tx_invalid') 4 | let txValid = require('./vectors/bitcoind/tx_valid') 5 | let testTxVerifierPartial = require('./helpers/tx-verifier').testTxVerifierPartial 6 | 7 | describe('TxVerifier Vectors 3/4', function () { 8 | testTxVerifierPartial(it, txValid, txInvalid, 2) 9 | }) 10 | -------------------------------------------------------------------------------- /test/tx-verifier-vectors-4.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let txInvalid = require('./vectors/bitcoind/tx_invalid') 4 | let txValid = require('./vectors/bitcoind/tx_valid') 5 | let testTxVerifierPartial = require('./helpers/tx-verifier').testTxVerifierPartial 6 | 7 | describe('TxVerifier Vectors 4/4', function () { 8 | testTxVerifierPartial(it, txValid, txInvalid, 3) 9 | }) 10 | -------------------------------------------------------------------------------- /test/var-int.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Bn = require('../lib/bn') 4 | let should = require('chai').should() 5 | let Br = require('../lib/br') 6 | let Bw = require('../lib/bw') 7 | let VarInt = require('../lib/var-int') 8 | 9 | describe('VarInt', function () { 10 | it('should make a new varInt', function () { 11 | let buf = new Buffer('00', 'hex') 12 | let varInt = new VarInt(buf) 13 | should.exist(varInt) 14 | varInt.buf.toString('hex').should.equal('00') 15 | varInt = new VarInt(buf) 16 | should.exist(varInt) 17 | varInt.buf.toString('hex').should.equal('00') 18 | 19 | // varInts can have multiple buffer representations 20 | VarInt.fromNumber(0).toNumber().should.equal(new VarInt(new Buffer([0xFD, 0, 0])).toNumber()) 21 | VarInt.fromNumber(0).toBuffer().toString('hex').should.not.equal(new VarInt().fromBuffer(new Buffer([0xFD, 0, 0])).toBuffer().toString('hex')) 22 | }) 23 | 24 | describe('#fromObject', function () { 25 | it('should set a buffer', function () { 26 | let buf = new Buffer('00', 'hex') 27 | let varInt = new VarInt().fromObject({buf: buf}) 28 | varInt.buf.toString('hex').should.equal('00') 29 | varInt.fromObject({}) 30 | varInt.buf.toString('hex').should.equal('00') 31 | }) 32 | }) 33 | 34 | describe('#fromJSON', function () { 35 | it('should set a buffer', function () { 36 | let buf = new Bw().writeVarIntNum(5).toBuffer() 37 | let varInt = new VarInt().fromJSON(buf.toString('hex')) 38 | varInt.toNumber().should.equal(5) 39 | }) 40 | }) 41 | 42 | describe('#toJSON', function () { 43 | it('should return a buffer', function () { 44 | let buf = new Bw().writeVarIntNum(5).toBuffer() 45 | let varInt = new VarInt().fromJSON(buf.toString('hex')) 46 | varInt.toJSON().should.equal('05') 47 | }) 48 | }) 49 | 50 | describe('#fromBuffer', function () { 51 | it('should set a buffer', function () { 52 | let buf = new Bw().writeVarIntNum(5).toBuffer() 53 | let varInt = new VarInt().fromBuffer(buf) 54 | varInt.toNumber().should.equal(5) 55 | }) 56 | }) 57 | 58 | describe('#fromBr', function () { 59 | it('should set a buffer reader', function () { 60 | let buf = new Bw().writeVarIntNum(5).toBuffer() 61 | let br = new Br(buf) 62 | let varInt = new VarInt().fromBr(br) 63 | varInt.toNumber().should.equal(5) 64 | }) 65 | }) 66 | 67 | describe('#fromBn', function () { 68 | it('should set a number', function () { 69 | let varInt = new VarInt().fromBn(new Bn(5)) 70 | varInt.toNumber().should.equal(5) 71 | }) 72 | }) 73 | 74 | describe('@fromBn', function () { 75 | it('should set a number', function () { 76 | let varInt = VarInt.fromBn(new Bn(5)) 77 | varInt.toNumber().should.equal(5) 78 | }) 79 | }) 80 | 81 | describe('#fromNumber', function () { 82 | it('should set a number', function () { 83 | let varInt = new VarInt().fromNumber(5) 84 | varInt.toNumber().should.equal(5) 85 | }) 86 | }) 87 | 88 | describe('@fromNumber', function () { 89 | it('should set a number', function () { 90 | let varInt = VarInt.fromNumber(5) 91 | varInt.toNumber().should.equal(5) 92 | }) 93 | }) 94 | 95 | describe('#toBuffer', function () { 96 | it('should return a buffer', function () { 97 | let buf = new Bw().writeVarIntNum(5).toBuffer() 98 | let varInt = new VarInt(buf) 99 | varInt.toBuffer().toString('hex').should.equal(buf.toString('hex')) 100 | }) 101 | }) 102 | 103 | describe('#toBn', function () { 104 | it('should return a buffer', function () { 105 | let varInt = VarInt.fromNumber(5) 106 | varInt.toBn().toString().should.equal(new Bn(5).toString()) 107 | }) 108 | }) 109 | 110 | describe('#toNumber', function () { 111 | it('should return a buffer', function () { 112 | let varInt = VarInt.fromNumber(5) 113 | varInt.toNumber().should.equal(5) 114 | }) 115 | }) 116 | }) 117 | -------------------------------------------------------------------------------- /test/vectors/coolest-tx-ever-sent.json: -------------------------------------------------------------------------------- 1 | { 2 | "tx": "0100000002bab3b61c5a7facd63a090addb0a4ea1863ccb0f8d6d8d5c1d7b747b5aa9b17bc01000000fdfe000048304502210089666e61b0486a71f2103414315aa4c418dc65815f8b8bfcfab1037c3c2a66210220428b8162874cfc97e05dee6f901dae03820d11011fa7828ecb8fbca45be2188d01493046022100c6c19d75b6d5c911813b2b64cee07c6338f54bca0395264e53c3b3d8ca8e4f8e022100bbcb8d32960e62f26e3e5bdeca605a8b49f1a42cedd20bad507a1bc23c565faf01ab522103c86390eb5230237f31de1f02e70ce61e77f6dbfefa7d0e4ed4f6b3f78f85d8ec2103193f28067b502b34cac9eae39f74dba4815e1278bab31516efb29bd8de2c1bea21032462c60ebc21f4d38b3c4ccb33be77b57ae72762be12887252db18fd6225befb53aeffffffffb1678d9af66c4b8cde45d0d445749322746ab900e546d3900cf30f436e73428a01000000fd470100483045022100a7af036203a1e6b2e833b0d6b402958d58f9ffaaff4969539f213634f17600ee0220192594a5c60f70e5a97dc48fec06df0d3b17c44850162d3d552c7d8653d159a001483045022072020e687ce937828827e85bc916716a9099a510e7fbd96a2836617afa370108022100ce737ad7b46c249cda2b09cb065ea16078b9a3a31f6fc6b63385f645abfdafdf01493046022100c30c5f6e943a78d502216e019821545b940b940784e83051945d89c92ec245f0022100b5c76266878ee8f29f65401fb0af6ba3941641740d846cb551059c0ad25b798c01ab532103c86390eb5230237f31de1f02e70ce61e77f6dbfefa7d0e4ed4f6b3f78f85d8ec2103193f28067b502b34cac9eae39f74dba4815e1278bab31516efb29bd8de2c1bea21032462c60ebc21f4d38b3c4ccb33be77b57ae72762be12887252db18fd6225befb53aeffffffff0150c300000000000017142c68bb496b123d39920fcfdc206daa08bbe58506b17500000000", 3 | "intx0": "010000000290c5e425bfba62bd5b294af0414d8fa3ed580c5ca6f351ccc23e360b14ff7f470100000091004730440220739d9ab2c3e7089e7bd311f267a65dc0ea00f49619cb61ec016a5038016ed71202201b88257809b623d471e429787c36e0a9bcd2a058fc0c75fd9c25f905657e3b9e01ab512103c86390eb5230237f31de1f02e70ce61e77f6dbfefa7d0e4ed4f6b3f78f85d8ec2103193f28067b502b34cac9eae39f74dba4815e1278bab31516efb29bd8de2c1bea52aeffffffffdd7f3ce640a2fb04dbe24630aa06e4299fbb1d3fe585fe4f80be4a96b5ff0a0d01000000b400483045022100a28d2ace2f1cb4b2a58d26a5f1a2cc15cdd4cf1c65cee8e4521971c7dc60021c0220476a5ad62bfa7c18f9174d9e5e29bc0062df543e2c336ae2c77507e462bbf95701ab512103c86390eb5230237f31de1f02e70ce61e77f6dbfefa7d0e4ed4f6b3f78f85d8ec2103193f28067b502b34cac9eae39f74dba4815e1278bab31516efb29bd8de2c1bea21032462c60ebc21f4d38b3c4ccb33be77b57ae72762be12887252db18fd6225befb53aeffffffff02e0fd1c00000000001976a9148501106ab5492387998252403d70857acfa1586488ac50c3000000000000171499050637f553f03cc0f82bbfe98dc99f10526311b17500000000", 4 | "intx1": "0100000001bab3b61c5a7facd63a090addb0a4ea1863ccb0f8d6d8d5c1d7b747b5aa9b17bc000000006b483045022056eaab9d21789a762c7aefdf84d90daf35f7d98bc917c83a1ae6fa24d44f2b94022100a8e1d45d4bc51ad3a192b1b9d582a4711971b0e957012a303950b83eda3d306c01210375228faaa97a02433f4f126ba8d5a295b92466608acf8d13740130d5bbf9cdb4ffffffff0240771b00000000001976a914bb05d829af3b31730e69b7eeb83c1c0d21d362eb88ac50c3000000000000171452cf84e83d1dc919ef4ada30c44cf4349ee55af9b17500000000" 5 | } 6 | -------------------------------------------------------------------------------- /test/vectors/kdf.json: -------------------------------------------------------------------------------- 1 | { 2 | "PBKDF2": { 3 | "valid": [ 4 | { 5 | "p": "70617373776f7264", 6 | "s": "73616c74", 7 | "c": 1, 8 | "dkLen": 20, 9 | "hmacf": "sha1", 10 | "key": "0c60c80f961f0e71f3a9b524af6012062fe037a6" 11 | }, 12 | { 13 | "p": "70617373776f7264", 14 | "s": "73616c74", 15 | "c": 2, 16 | "dkLen": 20, 17 | "hmacf": "sha1", 18 | "key": "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957" 19 | }, 20 | { 21 | "p": "70617373776f7264", 22 | "s": "73616c74", 23 | "c": 4096, 24 | "dkLen": 20, 25 | "hmacf": "sha1", 26 | "key": "4b007901b765489abead49d926f721d065a429c1" 27 | }, 28 | { 29 | "p": "70617373776f726450415353574f524470617373776f7264", 30 | "s": "73616c7453414c5473616c7453414c5473616c7453414c5473616c7453414c5473616c74", 31 | "c": 4096, 32 | "dkLen": 25, 33 | "hmacf": "sha1", 34 | "key": "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038" 35 | }, 36 | { 37 | "p": "7061737300776f7264", 38 | "s": "7361006c74", 39 | "c": 4096, 40 | "dkLen": 16, 41 | "hmacf": "sha1", 42 | "key": "56fa6aa75548099dcc37d7f03425e0c3" 43 | } 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/vectors/sig.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": [ 3 | { 4 | "compact": { 5 | "hex": "1f33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262", 6 | "compressed": true, 7 | "i": 0 8 | } 9 | }, 10 | { 11 | "compact": { 12 | "hex": "1b54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5", 13 | "compressed": false, 14 | "i": 0 15 | } 16 | }, 17 | { 18 | "compact": { 19 | "hex": "1fff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd06fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283", 20 | "compressed": true, 21 | "i": 0 22 | } 23 | }, 24 | { 25 | "compact": { 26 | "hex": "1cc0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d375afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3", 27 | "compressed": false, 28 | "i": 1 29 | } 30 | }, 31 | { 32 | "compact": { 33 | "hex": "1f7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6", 34 | "compressed": true, 35 | "i": 0 36 | } 37 | }, 38 | { 39 | "compact": { 40 | "hex": "1cfbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda4870e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37", 41 | "compressed": false, 42 | "i": 1 43 | } 44 | }, 45 | { 46 | "compact": { 47 | "hex": "20cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf906ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef", 48 | "compressed": true, 49 | "i": 1 50 | } 51 | } 52 | ], 53 | "invalid": { 54 | "compact": [ 55 | { 56 | "exception": "Invalid signature parameter", 57 | "hex": "23987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62" 58 | }, 59 | { 60 | "exception": "Invalid signature length", 61 | "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62000000" 62 | }, 63 | { 64 | "exception": "Invalid signature length", 65 | "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e9379" 66 | } 67 | ] 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /test/vectors/sighash-single-bug.json: -------------------------------------------------------------------------------- 1 | { 2 | "tx": "01000000022f196cf1e5bd426a04f07b882c893b5b5edebad67da6eb50f066c372ed736d5f000000006a47304402201f81ac31b52cb4b1ceb83f97d18476f7339b74f4eecd1a32c251d4c3cccfffa402203c9143c18810ce072969e4132fdab91408816c96b423b2be38eec8a3582ade36012102aa5a2b334bd8f135f11bc5c477bf6307ff98ed52d3ed10f857d5c89adf5b02beffffffffff8755f073f1170c0d519457ffc4acaa7cb2988148163b5dc457fae0fe42aa19000000009200483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a530347304402206da827fb26e569eb740641f9c1a7121ee59141703cbe0f903a22cc7d9a7ec7ac02204729f989b5348b3669ab020b8c4af01acc4deaba7c0d9f8fa9e06b2106cbbfeb01ffffffff010000000000000000016a00000000", 3 | "intx0": "010000000143d4b858145e44fbd121dbc592ae931b459f9ec99418a83e8cb6d94330a80c24010000006b483045022100f85c9fceb6d4d38c82a9121acbf68ffffe784017b05554b586464fdbe473340d0220077780b2022c2d97752961c2cb03ed9202cbe57647510746c6bd31276c8a3c5201210314ffdda8717bc586284c05f37192990f774c391e2088516d2983094d3a33e7c3ffffffff02a0860100000000001976a91419660c27383b347112e92caba64fb1d07e9f63bf88ac40c33800000000001976a914825537afe6d73324f862027690651a64c688dfb788ac00000000", 4 | "intx1": "01000000017a2133643a513a004ff4d09bbcc7a05d7ee7d3a1d28889f0c06d06f9db1d1d8000000000fd4d0200473044022011cb94542051b8be5563b39da022d7531673ed4b53b6b3f8536794150f7d75e802205a6774c0630964457c2d4a087e5a23167155f661082746dc711ba348ca4d4187014d01025121033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b5faeffffffff01a08601000000000091483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53037552210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7152ae00000000" 5 | } 6 | -------------------------------------------------------------------------------- /test/version.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Version = require('../lib/version') 4 | let Bn = require('../lib/bn') 5 | let should = require('chai').should() 6 | let VarInt = require('../lib/var-int') 7 | 8 | describe('Version', function () { 9 | it('should exist', function () { 10 | should.exist(Version) 11 | should.exist(new Version()) 12 | }) 13 | 14 | describe('#toBuffer', function () { 15 | it('should convert to buffer', function () { 16 | let version = Version.fromObject({ 17 | versionBytesNum: 0, 18 | servicesBuf: Buffer.alloc(8), 19 | timeBn: new Bn(0), 20 | addrRecvServicesBuf: Buffer.alloc(8), 21 | addrRecvIpAddrBuf: Buffer.alloc(16), 22 | addrRecvPort: 0, 23 | addrTransServicesBuf: Buffer.alloc(8), 24 | addrTransIpAddrBuf: Buffer.alloc(16), 25 | addrTransPort: 0, 26 | nonceBuf: Buffer.alloc(8), 27 | userAgentVi: VarInt.fromNumber('test'.length), 28 | userAgentBuf: new Buffer('test'), 29 | startHeightNum: 100, 30 | relay: true 31 | }) 32 | Buffer.isBuffer(version.toBuffer()).should.equal(true) 33 | }) 34 | }) 35 | 36 | describe('#fromBuffer', function () { 37 | it('should convert from buffer', function () { 38 | let version = Version.fromObject({ 39 | versionBytesNum: 0, 40 | servicesBuf: Buffer.alloc(8), 41 | timeBn: new Bn(0), 42 | addrRecvServicesBuf: Buffer.alloc(8), 43 | addrRecvIpAddrBuf: Buffer.alloc(16), 44 | addrRecvPort: 0, 45 | addrTransServicesBuf: Buffer.alloc(8), 46 | addrTransIpAddrBuf: Buffer.alloc(16), 47 | addrTransPort: 0, 48 | nonceBuf: Buffer.alloc(8), 49 | userAgentVi: VarInt.fromNumber('test'.length), 50 | userAgentBuf: new Buffer('test'), 51 | startHeightNum: 100, 52 | relay: true 53 | }) 54 | version = new Version().fromBuffer(version.toBuffer()) 55 | ;(version instanceof Version).should.equal(true) 56 | }) 57 | }) 58 | 59 | describe('@fromBuffer', function () { 60 | it('should convert from buffer', function () { 61 | let version = Version.fromObject({ 62 | versionBytesNum: 0, 63 | servicesBuf: Buffer.alloc(8), 64 | timeBn: new Bn(0), 65 | addrRecvServicesBuf: Buffer.alloc(8), 66 | addrRecvIpAddrBuf: Buffer.alloc(16), 67 | addrRecvPort: 0, 68 | addrTransServicesBuf: Buffer.alloc(8), 69 | addrTransIpAddrBuf: Buffer.alloc(16), 70 | addrTransPort: 0, 71 | nonceBuf: Buffer.alloc(8), 72 | userAgentVi: VarInt.fromNumber('test'.length), 73 | userAgentBuf: new Buffer('test'), 74 | startHeightNum: 100, 75 | relay: true 76 | }) 77 | version = Version.fromBuffer(version.toBuffer()) 78 | ;(version instanceof Version).should.equal(true) 79 | }) 80 | }) 81 | }) 82 | -------------------------------------------------------------------------------- /test/workers-result.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let WorkersResult = require('../lib/workers-result') 4 | let cmp = require('../lib/cmp') 5 | let should = require('chai').should() 6 | 7 | describe('WorkersResult', function () { 8 | it('should satisfy this basic API', function () { 9 | let workersResult = new WorkersResult() 10 | should.exist(workersResult) 11 | }) 12 | 13 | describe('#fromResult', function () { 14 | it('should make a workersResult from a string', function () { 15 | let result = 'test result' 16 | let workersResult = new WorkersResult().fromResult(result, 0) 17 | cmp(workersResult.resbuf, new Buffer(JSON.stringify(result))).should.equal(true) 18 | workersResult.isError.should.equal(false) 19 | workersResult.id.should.equal(0) 20 | }) 21 | }) 22 | 23 | describe('@fromResult', function () { 24 | it('should make a workersResult from a string', function () { 25 | let result = 'test result' 26 | let workersResult = WorkersResult.fromResult(result, 0) 27 | cmp(workersResult.resbuf, new Buffer(JSON.stringify(result))).should.equal(true) 28 | workersResult.isError.should.equal(false) 29 | workersResult.id.should.equal(0) 30 | }) 31 | }) 32 | 33 | describe('#fromError', function () { 34 | it('should make a workersResult from an error', function () { 35 | let error = new Error('oh noes, error') 36 | let workersResult = new WorkersResult().fromError(error, 0) 37 | cmp(workersResult.resbuf, new Buffer(JSON.stringify(error.message))).should.equal(true) 38 | workersResult.isError.should.equal(true) 39 | workersResult.id.should.equal(0) 40 | }) 41 | }) 42 | 43 | describe('#toBuffer', function () { 44 | it('should make a buffer from a workersResult', function () { 45 | let result = 'test result' 46 | let workersResult = new WorkersResult().fromResult(result, 0) 47 | workersResult.toBuffer().length.should.greaterThan(0) 48 | }) 49 | 50 | it('should make a buffer from a workersResult error', function () { 51 | let error = new Error('oh noes, error') 52 | let workersResult = new WorkersResult().fromError(error, 0) 53 | workersResult.toBuffer().length.should.greaterThan(0) 54 | }) 55 | }) 56 | 57 | describe('#fromBuffer', function () { 58 | it('should make a workersResult from a workersResult buffer', function () { 59 | let result = 'test result' 60 | let workersResult = new WorkersResult().fromResult(result, 0) 61 | let buf = workersResult.toBuffer() 62 | workersResult = new WorkersResult().fromBuffer(buf) 63 | cmp(workersResult.resbuf, new Buffer(JSON.stringify(result))).should.equal(true) 64 | }) 65 | 66 | it('should make a workersResult error from a workersResult buffer', function () { 67 | let error = new Error('oh noes, error') 68 | let workersResult = new WorkersResult().fromError(error, 0) 69 | let buf = workersResult.toBuffer() 70 | workersResult = new WorkersResult().fromBuffer(buf) 71 | cmp(workersResult.resbuf, new Buffer(JSON.stringify(error.message))).should.equal(true) 72 | }) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/workers.js: -------------------------------------------------------------------------------- 1 | /* global describe,it */ 2 | 'use strict' 3 | let Bip32 = require('../lib/bip-32') 4 | let Hash = require('../lib/hash') 5 | let PrivKey = require('../lib/priv-key') 6 | let PubKey = require('../lib/pub-key') 7 | let Workers = require('../lib/workers') 8 | let asink = require('asink') 9 | let should = require('chai').should() 10 | 11 | describe('Workers', function () { 12 | it('should satisfy this basic API', function () { 13 | let workers = new Workers() 14 | should.exist(workers.nativeWorkers) 15 | should.exist(workers) 16 | }) 17 | 18 | describe('#asyncObjectMethod', function () { 19 | it('should compute this method in the workers', function () { 20 | return asink(function * () { 21 | let bip32 = new Bip32().fromRandom() 22 | let workersResult = yield Workers.asyncObjectMethod(bip32, 'toString', []) 23 | let str = JSON.parse(workersResult.resbuf.toString()) 24 | str[0].should.equal('x') 25 | }, this) 26 | }) 27 | 28 | it('should compute this method with Yours Bitcoin object in args in the workers', function () { 29 | return asink(function * () { 30 | let privKey = new PrivKey().fromRandom() 31 | let pubKey1 = new PubKey().fromPrivKey(privKey) 32 | let workersResult = yield Workers.asyncObjectMethod(new PubKey(), 'fromPrivKey', [privKey]) 33 | let pubKey2 = new PubKey().fromFastBuffer(workersResult.resbuf) 34 | pubKey1.toString().should.equal(pubKey2.toString()) 35 | }, this) 36 | }) 37 | }) 38 | 39 | describe('#asyncClassMethod', function () { 40 | it('should compute this method in the workers', function () { 41 | return asink(function * () { 42 | let buf = new Buffer([0, 1, 2, 3, 4]) 43 | let args = [buf] 44 | let workersResult = yield Workers.asyncClassMethod('Hash', 'sha1', args) 45 | let hashBuf1 = workersResult.resbuf 46 | let hashBuf2 = Hash.sha1(buf) 47 | Buffer.compare(hashBuf1, hashBuf2).should.equal(0) 48 | }, this) 49 | }) 50 | }) 51 | }) 52 | --------------------------------------------------------------------------------