From 0631148705ce1f049bb034affa6d7fcac4004bbc Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 19 Nov 2016 05:29:16 -0800 Subject: [PATCH] modules: more refactoring. --- browser/transform.js | 17 - lib/chain/chain.js | 10 +- lib/chain/chaindb.js | 3 +- lib/chain/chainentry.js | 3 +- lib/crypto/aes.js | 2 + lib/crypto/crypto.js | 294 ++++------- lib/env.js | 10 +- lib/hd/common.js | 103 ++++ lib/hd/hd.js | 57 -- lib/hd/mnemonic.js | 15 - lib/hd/private.js | 39 +- lib/hd/public.js | 19 +- lib/http/server.js | 3 +- lib/mempool/mempool.js | 5 +- lib/mempool/mempoolentry.js | 4 +- lib/miner/minerblock.js | 7 +- lib/net/bip150.js | 3 +- lib/net/bip152.js | 5 +- lib/net/pool.js | 5 +- lib/primitives/abstractblock.js | 20 +- lib/primitives/address.js | 5 +- lib/primitives/block.js | 46 +- lib/primitives/headers.js | 13 + lib/primitives/keyring.js | 7 +- lib/primitives/memblock.js | 5 +- lib/primitives/merkleblock.js | 7 +- lib/primitives/mtx.js | 16 +- lib/primitives/tx.js | 142 +---- lib/script/script.js | 12 +- lib/utils/base58.js | 8 +- lib/utils/btcutils.js | 403 ++++++++++++++ lib/utils/encoding.js | 653 +++++++++++++++++++++++ lib/utils/errors.js | 11 + lib/utils/lazy-browser.js | 11 + lib/utils/reader.js | 22 +- lib/utils/utils.js | 902 +------------------------------- lib/utils/writer.js | 24 +- lib/wallet/account.js | 5 +- lib/wallet/common.js | 26 + lib/wallet/txdb.js | 3 +- lib/wallet/wallet.js | 14 +- lib/wallet/walletdb.js | 11 +- test/block-test.js | 3 +- test/hd-test.js | 3 +- test/utils-test.js | 122 ++--- test/wallet-test.js | 5 +- 46 files changed, 1582 insertions(+), 1521 deletions(-) create mode 100644 lib/hd/common.js create mode 100644 lib/utils/btcutils.js create mode 100644 lib/utils/encoding.js create mode 100644 lib/utils/lazy-browser.js create mode 100644 lib/wallet/common.js diff --git a/browser/transform.js b/browser/transform.js index fcc4266a..bda143f6 100644 --- a/browser/transform.js +++ b/browser/transform.js @@ -24,17 +24,6 @@ function processEnv(str) { '$1this.$2 = require(\'$3\')'); } -function processLazy(str) { - str.replace( - /^( *)lazy\('(\w+)', '([^']+)'\)/gm, - function(_, sp, w1, w2) { - str += sp + 'if (0) require(\'' + w2 + '\');\n'; - return ''; - } - ); - return str; -} - function transformer(file, process) { var stream = new Transform(); var decoder = new StringDecoder('utf8'); @@ -62,12 +51,6 @@ function end(file, offset) { } module.exports = function(file) { - if (end(file, 3) === 'lib/utils/utils.js') - return transformer(file, processLazy); - - if (end(file, 3) === 'lib/crypto/crypto.js') - return transformer(file, processLazy); - if (end(file, 2) === 'lib/env.js') return transformer(file, processEnv); diff --git a/lib/chain/chain.js b/lib/chain/chain.js index 5ece74e7..c57fd991 100644 --- a/lib/chain/chain.js +++ b/lib/chain/chain.js @@ -13,12 +13,14 @@ var Logger = require('../node/logger'); var ChainDB = require('./chaindb'); var constants = require('../protocol/constants'); var utils = require('../utils/utils'); +var btcutils = require('../utils/btcutils'); var Locker = require('../utils/locker'); var ChainEntry = require('./chainentry'); var CoinView = require('./coinview'); var assert = require('assert'); -var VerifyError = require('../utils/errors').VerifyError; -var VerifyResult = utils.VerifyResult; +var errors = require('../utils/errors'); +var VerifyError = errors.VerifyError; +var VerifyResult = errors.VerifyResult; var time = require('../net/timedata'); var co = require('../utils/co'); @@ -1859,7 +1861,7 @@ Chain.prototype.retarget = function retarget(prev, first) { return prev.bits; actualTimespan = prev.ts - first.ts; - target = utils.fromCompact(prev.bits); + target = btcutils.fromCompact(prev.bits); if (actualTimespan < targetTimespan / 4 | 0) actualTimespan = targetTimespan / 4 | 0; @@ -1873,7 +1875,7 @@ Chain.prototype.retarget = function retarget(prev, first) { if (target.cmp(pow.limit) > 0) return pow.bits; - return utils.toCompact(target); + return btcutils.toCompact(target); }; /** diff --git a/lib/chain/chaindb.js b/lib/chain/chaindb.js index 8e5f8f17..08886c95 100644 --- a/lib/chain/chaindb.js +++ b/lib/chain/chaindb.js @@ -13,6 +13,7 @@ var utils = require('../utils/utils'); var assert = require('assert'); var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); +var encoding = require('../utils/encoding'); var co = require('../utils/co'); var Network = require('../protocol/network'); var CoinView = require('./coinview'); @@ -26,7 +27,7 @@ var Outpoint = require('../primitives/outpoint'); var TX = require('../primitives/tx'); var Address = require('../primitives/address'); var ChainEntry = require('./chainentry'); -var U32 = utils.U32; +var U32 = encoding.U32; var DUMMY = new Buffer([0]); /** diff --git a/lib/chain/chainentry.js b/lib/chain/chainentry.js index 864217bc..0f881c25 100644 --- a/lib/chain/chainentry.js +++ b/lib/chain/chainentry.js @@ -11,6 +11,7 @@ var BN = require('bn.js'); var Network = require('../protocol/network'); var constants = require('../protocol/constants'); var utils = require('../utils/utils'); +var btcutils = require('../utils/btcutils'); var crypto = require('../crypto/crypto'); var assert = require('assert'); var BufferWriter = require('../utils/writer'); @@ -124,7 +125,7 @@ ChainEntry.MAX_CHAINWORK = new BN(1).ushln(256); */ ChainEntry.prototype.getProof = function getProof() { - var target = utils.fromCompact(this.bits); + var target = btcutils.fromCompact(this.bits); if (target.isNeg() || target.cmpn(0) === 0) return new BN(0); return ChainEntry.MAX_CHAINWORK.div(target.iaddn(1)); diff --git a/lib/crypto/aes.js b/lib/crypto/aes.js index f7ac9523..7243efbb 100644 --- a/lib/crypto/aes.js +++ b/lib/crypto/aes.js @@ -739,6 +739,8 @@ AES.cbc.decrypt = function decrypt(data, key, iv) { AES.Key = AESKey; AES.Cipher = AESCipher; AES.Decipher = AESDecipher; +AES.encipher = AES.cbc.encrypt; +AES.decipher = AES.cbc.decrypt; /* * Helpers diff --git a/lib/crypto/crypto.js b/lib/crypto/crypto.js index aac0cef5..820eb95a 100644 --- a/lib/crypto/crypto.js +++ b/lib/crypto/crypto.js @@ -10,16 +10,9 @@ var assert = require('assert'); var scrypt = require('./scrypt'); var scryptAsync = require('./scrypt-async'); -var utils = require('../utils/utils'); var co = require('../utils/co'); var native = require('../utils/native').binding; var backend = require('./backend'); -var lazy = utils.lazy(require, exports); - -/** - * @exports crypto - */ - var crypto = exports; /** @@ -221,109 +214,6 @@ crypto.scryptAsync = function _scrypt(passwd, salt, N, r, p, len) { }); }; -/** - * Derive a key using pbkdf2 with 50,000 iterations. - * @param {Buffer|String} passphrase - * @returns {Promise} - */ - -crypto.derive = function derive(passphrase) { - return crypto.pbkdf2Async(passphrase, 'bcoin', 50000, 32, 'sha256'); -}; - -/** - * Encrypt with aes-256-cbc. Derives key with {@link crypto.derive}. - * @param {Buffer} data - * @param {Buffer|String} passphrase - * @param {Buffer} iv - 128 bit initialization vector. - * @returns {Promise} - */ - -crypto.encrypt = co(function* encrypt(data, passphrase, iv) { - var key; - - assert(Buffer.isBuffer(data)); - assert(passphrase, 'No passphrase.'); - assert(Buffer.isBuffer(iv)); - - key = yield crypto.derive(passphrase); - - try { - data = crypto.encipher(data, key, iv); - } catch (e) { - crypto.cleanse(key); - throw e; - } - - crypto.cleanse(key); - - return data; -}); - -/** - * Encrypt with aes-256-cbc. - * @param {Buffer} data - * @param {Buffer} key - 256 bit key. - * @param {Buffer} iv - 128 bit initialization vector. - * @returns {Buffer} - */ - -crypto.encipher = function encipher(data, key, iv) { - assert(Buffer.isBuffer(data)); - assert(Buffer.isBuffer(key)); - assert(Buffer.isBuffer(iv)); - assert(key.length === 32); - assert(iv.length === 16); - - return backend.encipher(data, key, iv); -}; - -/** - * Decrypt with aes-256-cbc. Derives key with {@link crypto.derive}. - * @param {Buffer} data - * @param {Buffer|String} passphrase - * @param {Buffer} iv - 128 bit initialization vector. - * @returns {Promise} - */ - -crypto.decrypt = co(function* decrypt(data, passphrase, iv) { - var key; - - assert(Buffer.isBuffer(data)); - assert(passphrase, 'No passphrase.'); - assert(Buffer.isBuffer(iv)); - - key = yield crypto.derive(passphrase); - - try { - data = crypto.decipher(data, key, iv); - } catch (e) { - crypto.cleanse(key); - throw e; - } - - crypto.cleanse(key); - - return data; -}); - -/** - * Decrypt with aes-256-cbc. - * @param {Buffer} data - * @param {Buffer} key - 256 bit key. - * @param {Buffer} iv - 128 bit initialization vector. - * @returns {Buffer} - */ - -crypto.decipher = function decipher(data, key, iv) { - assert(Buffer.isBuffer(data)); - assert(Buffer.isBuffer(key)); - assert(Buffer.isBuffer(iv)); - assert(key.length === 32); - assert(iv.length === 16); - return backend.decipher(data, key, iv); -}; - /** * Perform key derivation using PBKDF2. * @private @@ -414,74 +304,6 @@ crypto.hkdfExpand = function hkdfExpand(prk, info, len, alg) { return okm; }; -/** - * memcmp in constant time (can only return true or false). - * This protects us against timing attacks when - * comparing an input against a secret string. - * @see https://cryptocoding.net/index.php/Coding_rules - * @see `$ man 3 memcmp` (NetBSD's consttime_memequal) - * @param {Buffer} a - * @param {Buffer} b - * @returns {Boolean} - */ - -crypto.ccmp = function ccmp(a, b) { - var i, res; - - if (!Buffer.isBuffer(a)) - return false; - - if (!Buffer.isBuffer(b)) - return false; - - if (b.length === 0) - return a.length === 0; - - res = a.length ^ b.length; - - for (i = 0; i < a.length; i++) - res |= a[i] ^ b[i % b.length]; - - return res === 0; -}; - -/** - * Compare two bytes in constant time. - * @param {Number} a - * @param {Number} b - * @returns {Boolean} - */ - -crypto.ceq = function ceq(a, b) { - var r = ~(a ^ b) & 0xff; - r &= r >>> 4; - r &= r >>> 2; - r &= r >>> 1; - return r === 1; -}; - -/** - * A maybe-secure memzero. - * @param {Buffer} data - */ - -crypto.cleanse = function cleanse(data) { - var ctr = crypto._counter; - var i; - - for (i = 0; i < data.length; i++) { - data[i] = ctr & 0xff; - ctr += i; - } - - crypto._counter = ctr >>> 0; -}; - -crypto._counter = 0; - -if (native) - crypto.cleanse = native.cleanse; - /** * Build a merkle tree from leaves. * @param {Buffer[]} leaves @@ -503,7 +325,7 @@ crypto.buildMerkleTree = function buildMerkleTree(leaves) { right = tree[j + i2]; if (i2 === i + 1 && i2 + 1 === size - && utils.cmp(left, right) === 0) { + && left.compare(right) === 0) { return; } @@ -600,6 +422,109 @@ crypto.checkMerkleBranch = function checkMerkleBranch(hash, branch, index) { if (native) crypto.checkMerkleBranch = native.checkMerkleBranch; +/** + * Encrypt with aes-256-cbc. + * @param {Buffer} data + * @param {Buffer} key - 256 bit key. + * @param {Buffer} iv - 128 bit initialization vector. + * @returns {Buffer} + */ + +crypto.encipher = function encipher(data, key, iv) { + assert(Buffer.isBuffer(data)); + assert(Buffer.isBuffer(key)); + assert(Buffer.isBuffer(iv)); + assert(key.length === 32); + assert(iv.length === 16); + + return backend.encipher(data, key, iv); +}; + +/** + * Decrypt with aes-256-cbc. + * @param {Buffer} data + * @param {Buffer} key - 256 bit key. + * @param {Buffer} iv - 128 bit initialization vector. + * @returns {Buffer} + */ + +crypto.decipher = function decipher(data, key, iv) { + assert(Buffer.isBuffer(data)); + assert(Buffer.isBuffer(key)); + assert(Buffer.isBuffer(iv)); + assert(key.length === 32); + assert(iv.length === 16); + return backend.decipher(data, key, iv); +}; + +/** + * memcmp in constant time (can only return true or false). + * This protects us against timing attacks when + * comparing an input against a secret string. + * @see https://cryptocoding.net/index.php/Coding_rules + * @see `$ man 3 memcmp` (NetBSD's consttime_memequal) + * @param {Buffer} a + * @param {Buffer} b + * @returns {Boolean} + */ + +crypto.ccmp = function ccmp(a, b) { + var i, res; + + if (!Buffer.isBuffer(a)) + return false; + + if (!Buffer.isBuffer(b)) + return false; + + if (b.length === 0) + return a.length === 0; + + res = a.length ^ b.length; + + for (i = 0; i < a.length; i++) + res |= a[i] ^ b[i % b.length]; + + return res === 0; +}; + +/** + * Compare two bytes in constant time. + * @param {Number} a + * @param {Number} b + * @returns {Boolean} + */ + +crypto.ceq = function ceq(a, b) { + var r = ~(a ^ b) & 0xff; + r &= r >>> 4; + r &= r >>> 2; + r &= r >>> 1; + return r === 1; +}; + +/** + * A maybe-secure memzero. + * @param {Buffer} data + */ + +crypto.cleanse = function cleanse(data) { + var ctr = crypto._counter; + var i; + + for (i = 0; i < data.length; i++) { + data[i] = ctr & 0xff; + ctr += i; + } + + crypto._counter = ctr >>> 0; +}; + +crypto._counter = 0; + +if (native) + crypto.cleanse = native.cleanse; + /** * Generate some random bytes. * @function @@ -635,14 +560,3 @@ crypto.randomRange = function randomRange(min, max) { var num = crypto.randomInt(); return Math.floor((num / 0x100000000) * (max - min) + min); }; - -/* - * Expose other objects. - */ - -lazy('aes', './aes'); -lazy('chachapoly', './chachapoly'); -lazy('ec', './ec'); // ec-secp256k1 - circular -lazy('schnorr', './schnorr'); // circular -lazy('siphash', './siphash'); -lazy('pk', './pk'); // circular diff --git a/lib/env.js b/lib/env.js index f86cd5ea..53c2865a 100644 --- a/lib/env.js +++ b/lib/env.js @@ -119,6 +119,7 @@ function Environment() { // Utils this.require('utils', './utils/utils'); + this.require('btcutils', './utils/btcutils'); this.require('locker', './utils/locker'); this.require('reader', './utils/reader'); this.require('writer', './utils/writer'); @@ -127,10 +128,15 @@ function Environment() { this.require('uri', './utils/uri'); this.require('errors', './utils/errors'); this.require('co', './utils/co'); + this.require('base58', './utils/base58'); + this.require('asn1', './utils/asn1'); + this.require('pem', './utils/pem'); + this.require('protobuf', './utils/protobuf'); // Crypto - this.require('ec', './crypto/ec'); this.require('crypto', './crypto/crypto'); + this.require('ec', './crypto/ec'); + this.require('schnorr', './crypto/schnorr'); // DB this.require('lowlevelup', './db/lowlevelup'); @@ -251,7 +257,7 @@ Environment.prototype.cache = function cache() { this.fullnode; this.spvnode; this.http; - this.crypto.schnorr; + this.schnorr; this.uri; this.bip70; }; diff --git a/lib/hd/common.js b/lib/hd/common.js new file mode 100644 index 00000000..0414b3c5 --- /dev/null +++ b/lib/hd/common.js @@ -0,0 +1,103 @@ +/*! + * common.js - common functions for hd + * Copyright (c) 2015-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var LRU = require('../utils/lru'); +var constants = require('../protocol/constants'); +var common = exports; + +/** + * LRU cache to avoid deriving keys twice. + * @type {LRU} + */ + +common.cache = new LRU(500); + +/** + * Parse a derivation path and return an array of indexes. + * @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki + * @param {String} path + * @param {Number?} max - Max index. + * @returns {Number[]} + */ + +common.parsePath = function parsePath(path, max) { + var parts = path.split('/'); + var root = parts.shift(); + var result = []; + var i, hardened, index; + + if (max == null) + max = constants.hd.MAX_INDEX; + + if (root !== 'm' + && root !== 'M' + && root !== 'm\'' + && root !== 'M\'') { + throw new Error('Bad path root.'); + } + + for (i = 0; i < parts.length; i++) { + index = parts[i]; + hardened = index[index.length - 1] === '\''; + + if (hardened) + index = index.slice(0, -1); + + if (!/^\d+$/.test(index)) + throw new Error('Non-number path index.'); + + index = parseInt(index, 10); + + if (hardened) + index += constants.hd.HARDENED; + + if (!(index >= 0 && index < max)) + throw new Error('Index out of range.'); + + result.push(index); + } + + return result; +}; + +/** + * Test whether the key is a master key. + * @param {HDPrivateKey|HDPublicKey} key + * @returns {Boolean} + */ + +common.isMaster = function isMaster(key) { + return key.depth === 0 + && key.childIndex === 0 + && key.parentFingerPrint.readUInt32LE(0, true) === 0; +}; + +/** + * Test whether the key is (most likely) a BIP44 account key. + * @param {HDPrivateKey|HDPublicKey} key + * @param {Number?} accountIndex + * @returns {Boolean} + */ + +common.isAccount44 = function isAccount44(key, accountIndex) { + if (accountIndex != null) { + if (key.childIndex !== constants.hd.HARDENED + accountIndex) + return false; + } + return key.depth === 3 && key.childIndex >= constants.hd.HARDENED; +}; + +/** + * Test whether the key is a BIP45 purpose key. + * @param {HDPrivateKey|HDPublicKey} key + * @returns {Boolean} + */ + +common.isPurpose45 = function isPurpose45(key) { + return key.depth === 1 && key.childIndex === constants.hd.HARDENED + 45; +}; diff --git a/lib/hd/hd.js b/lib/hd/hd.js index e340f6eb..4f51d33b 100644 --- a/lib/hd/hd.js +++ b/lib/hd/hd.js @@ -7,8 +7,6 @@ 'use strict'; var assert = require('assert'); -var constants = require('../protocol/constants'); -var LRU = require('../utils/lru'); var Mnemonic = require('./mnemonic'); var HDPrivateKey = require('./private'); var HDPublicKey = require('./public'); @@ -151,61 +149,6 @@ HD.isRaw = function isRaw(data) { || HDPublicKey.isRaw(data); }; -/** - * Parse a derivation path and return an array of indexes. - * @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki - * @param {String} path - * @param {Number?} max - Max index. - * @returns {Number[]} - */ - -HD.parsePath = function parsePath(path, max) { - var parts = path.split('/'); - var root = parts.shift(); - var result = []; - var i, hardened, index; - - if (max == null) - max = constants.hd.MAX_INDEX; - - if (root !== 'm' - && root !== 'M' - && root !== 'm\'' - && root !== 'M\'') { - throw new Error('Bad path root.'); - } - - for (i = 0; i < parts.length; i++) { - index = parts[i]; - hardened = index[index.length - 1] === '\''; - - if (hardened) - index = index.slice(0, -1); - - if (!/^\d+$/.test(index)) - throw new Error('Non-number path index.'); - - index = parseInt(index, 10); - - if (hardened) - index += constants.hd.HARDENED; - - if (!(index >= 0 && index < max)) - throw new Error('Index out of range.'); - - result.push(index); - } - - return result; -}; - -/** - * LRU cache to avoid deriving keys twice. - * @type {LRU} - */ - -HD.cache = new LRU(500); - /** * Test whether an object is an HD key. * @param {Object} obj diff --git a/lib/hd/mnemonic.js b/lib/hd/mnemonic.js index 66d011d7..bfbbeb58 100644 --- a/lib/hd/mnemonic.js +++ b/lib/hd/mnemonic.js @@ -12,7 +12,6 @@ var assert = require('assert'); var constants = require('../protocol/constants'); var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); -var HD = require('./hd'); var wordlist = require('./wordlist'); var nfkd = require('../utils/nfkd'); @@ -147,20 +146,6 @@ Mnemonic.prototype.toSeed = function toSeed(passphrase) { 2048, 64, 'sha512'); }; -/** - * Generate seed and create an hd private key. - * @param {String?} passphrase - * @param {(Network|NetworkType)?} network - * @returns {HDPrivateKey} - */ - -Mnemonic.prototype.toKey = function toKey(passphrase, network) { - var seed = this.toSeed(passphrase); - var key = HD.PrivateKey.fromSeed(seed, network); - key.mnemonic = this; - return key; -}; - /** * Get or generate entropy. * @returns {Buffer} diff --git a/lib/hd/private.js b/lib/hd/private.js index d95a525a..b777e280 100644 --- a/lib/hd/private.js +++ b/lib/hd/private.js @@ -15,7 +15,10 @@ var networks = require('../protocol/networks'); var Network = require('../protocol/network'); var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); -var HD = require('./hd'); +var base58 = require('../utils/base58'); +var Mnemonic = require('./mnemonic'); +var HDPublicKey = require('./public'); +var common = require('./common'); /* * Constants @@ -99,7 +102,7 @@ HDPrivateKey.prototype.fromOptions = function fromOptions(options) { this.publicKey = ec.publicKeyCreate(options.privateKey, true); if (options.mnemonic) { - assert(options.mnemonic instanceof HD.Mnemonic); + assert(options.mnemonic instanceof Mnemonic); this.mnemonic = options.mnemonic; } @@ -125,7 +128,7 @@ HDPrivateKey.prototype.__defineGetter__('hdPublicKey', function() { var key = this._hdPublicKey; if (!key) { - key = new HD.PublicKey(); + key = new HDPublicKey(); key.network = this.network; key.depth = this.depth; key.parentFingerPrint = this.parentFingerPrint; @@ -197,7 +200,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened, cache) { } if (!cache) - cache = HD.cache; + cache = common.cache; if (typeof index === 'string') return this.derivePath(index, cache); @@ -306,9 +309,7 @@ HDPrivateKey.prototype.derivePurpose45 = function derivePurpose45(cache) { */ HDPrivateKey.prototype.isMaster = function isMaster() { - return this.depth === 0 - && this.childIndex === 0 - && this.parentFingerPrint.readUInt32LE(0, true) === 0; + return common.isMaster(this); }; /** @@ -318,11 +319,7 @@ HDPrivateKey.prototype.isMaster = function isMaster() { */ HDPrivateKey.prototype.isAccount44 = function isAccount44(accountIndex) { - if (accountIndex != null) { - if (this.childIndex !== constants.hd.HARDENED + accountIndex) - return false; - } - return this.depth === 3 && this.childIndex >= constants.hd.HARDENED; + return common.isAccount44(this, accountIndex); }; /** @@ -331,7 +328,7 @@ HDPrivateKey.prototype.isAccount44 = function isAccount44(accountIndex) { */ HDPrivateKey.prototype.isPurpose45 = function isPurpose45() { - return this.depth === 1 && this.childIndex === constants.hd.HARDENED + 45; + return common.isPurpose45(this); }; /** @@ -395,7 +392,7 @@ HDPrivateKey.isValidPath = function isValidPath(path) { return false; try { - HD.parsePath(path, constants.hd.MAX_INDEX); + common.parsePath(path, constants.hd.MAX_INDEX); return true; } catch (e) { return false; @@ -410,7 +407,7 @@ HDPrivateKey.isValidPath = function isValidPath(path) { */ HDPrivateKey.prototype.derivePath = function derivePath(path, cache) { - var indexes = HD.parsePath(path, constants.hd.MAX_INDEX); + var indexes = common.parsePath(path, constants.hd.MAX_INDEX); var key = this; var i; @@ -534,8 +531,8 @@ HDPrivateKey.fromSeed = function fromSeed(seed, network) { */ HDPrivateKey.prototype.fromMnemonic = function fromMnemonic(mnemonic, network) { - if (!(mnemonic instanceof HD.Mnemonic)) - mnemonic = new HD.Mnemonic(mnemonic); + if (!(mnemonic instanceof Mnemonic)) + mnemonic = new Mnemonic(mnemonic); this.fromSeed(mnemonic.toSeed(), network); this.mnemonic = mnemonic; return this; @@ -604,7 +601,7 @@ HDPrivateKey.generate = function generate(network) { */ HDPrivateKey.prototype.fromBase58 = function fromBase58(xkey) { - this.fromRaw(utils.fromBase58(xkey)); + this.fromRaw(base58.decode(xkey)); this._xprivkey = xkey; return this; }; @@ -650,7 +647,7 @@ HDPrivateKey.prototype.fromRaw = function fromRaw(raw) { */ HDPrivateKey.prototype.toBase58 = function toBase58(network) { - return utils.toBase58(this.toRaw(network)); + return base58.encode(this.toRaw(network)); }; /** @@ -717,7 +714,7 @@ HDPrivateKey.prototype.fromExtended = function fromExtended(data) { var p = new BufferReader(data); this.fromRaw(p); if (p.readU8() === 1) - this.mnemonic = HD.Mnemonic.fromRaw(p); + this.mnemonic = Mnemonic.fromRaw(p); return this; }; @@ -775,7 +772,7 @@ HDPrivateKey.prototype.fromJSON = function fromJSON(json) { this.fromBase58(json.xprivkey); if (json.mnemonic) - this.mnemonic = HD.Mnemonic.fromJSON(json.mnemonic); + this.mnemonic = Mnemonic.fromJSON(json.mnemonic); return this; }; diff --git a/lib/hd/public.js b/lib/hd/public.js index ac5ef742..35ace54a 100644 --- a/lib/hd/public.js +++ b/lib/hd/public.js @@ -15,7 +15,8 @@ var networks = require('../protocol/networks'); var Network = require('../protocol/network'); var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); -var HD = require('./hd'); +var base58 = require('../utils/base58'); +var common = require('./common'); /* * Constants @@ -150,7 +151,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened, cache) { } if (!cache) - cache = HD.cache; + cache = common.cache; if (typeof index === 'string') return this.derivePath(index, cache); @@ -248,7 +249,7 @@ HDPublicKey.prototype.derivePurpose45 = function derivePurpose45() { */ HDPublicKey.prototype.isMaster = function() { - return HD.PrivateKey.prototype.isMaster.call(this); + return common.isMaster(this); }; /** @@ -259,7 +260,7 @@ HDPublicKey.prototype.isMaster = function() { */ HDPublicKey.prototype.isAccount44 = function(accountIndex) { - return HD.PrivateKey.prototype.isAccount44.call(this, accountIndex); + return common.isAccount44(this, accountIndex); }; /** @@ -269,7 +270,7 @@ HDPublicKey.prototype.isAccount44 = function(accountIndex) { */ HDPublicKey.prototype.isPurpose45 = function() { - return HD.PrivateKey.prototype.isPurpose45.call(this); + return common.isPurpose45(this); }; /** @@ -284,7 +285,7 @@ HDPublicKey.isValidPath = function isValidPath(path) { return false; try { - HD.parsePath(path, constants.hd.HARDENED); + common.parsePath(path, constants.hd.HARDENED); return true; } catch (e) { return false; @@ -300,7 +301,7 @@ HDPublicKey.isValidPath = function isValidPath(path) { */ HDPublicKey.prototype.derivePath = function derivePath(path, cache) { - var indexes = HD.parsePath(path, constants.hd.HARDENED); + var indexes = common.parsePath(path, constants.hd.HARDENED); var key = this; var i; @@ -454,7 +455,7 @@ HDPublicKey.isRaw = function isRaw(data) { */ HDPublicKey.prototype.fromBase58 = function fromBase58(xkey) { - this.fromRaw(utils.fromBase58(xkey)); + this.fromRaw(base58.decode(xkey)); this._xpubkey = xkey; return this; }; @@ -498,7 +499,7 @@ HDPublicKey.prototype.fromRaw = function fromRaw(raw) { */ HDPublicKey.prototype.toBase58 = function toBase58(network) { - return utils.toBase58(this.toRaw(network)); + return base58.encode(this.toRaw(network)); }; /** diff --git a/lib/http/server.js b/lib/http/server.js index fcfe6f2d..29d79dbe 100644 --- a/lib/http/server.js +++ b/lib/http/server.js @@ -16,6 +16,7 @@ var constants = require('../protocol/constants'); var HTTPBase = require('./base'); var utils = require('../utils/utils'); var co = require('../utils/co'); +var base58 = require('../utils/base58'); var Address = require('../primitives/address'); var Bloom = require('../utils/bloom'); var TX = require('../primitives/tx'); @@ -69,7 +70,7 @@ function HTTPServer(options) { this.rpc = null; if (!this.apiKey) - this.apiKey = utils.toBase58(crypto.randomBytes(20)); + this.apiKey = base58.encode(crypto.randomBytes(20)); if (!this.serviceKey) this.serviceKey = this.apiKey; diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 336265d1..bb1c7e84 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -12,8 +12,9 @@ var utils = require('../utils/utils'); var co = require('../utils/co'); var assert = require('assert'); var crypto = require('../crypto/crypto'); -var VerifyError = require('../utils/errors').VerifyError; -var VerifyResult = utils.VerifyResult; +var errors = require('../utils/errors'); +var VerifyError = errors.VerifyError; +var VerifyResult = errors.VerifyResult; var flags = constants.flags; var Bloom = require('../utils/bloom'); var Address = require('../primitives/address'); diff --git a/lib/mempool/mempoolentry.js b/lib/mempool/mempoolentry.js index 78b8d6b9..bf1bcf66 100644 --- a/lib/mempool/mempoolentry.js +++ b/lib/mempool/mempoolentry.js @@ -8,7 +8,7 @@ var constants = require('../protocol/constants'); var utils = require('../utils/utils'); -var TX = require('../primitives/tx'); +var btcutils = require('../utils/btcutils'); /** * Represents a mempool entry. @@ -151,7 +151,7 @@ MempoolEntry.prototype.getFee = function getFee() { */ MempoolEntry.prototype.getRate = function getRate() { - return TX.getRate(this.size, this.fee); + return btcutils.getRate(this.size, this.fee); }; /** diff --git a/lib/miner/minerblock.js b/lib/miner/minerblock.js index 53395305..2ac7722e 100644 --- a/lib/miner/minerblock.js +++ b/lib/miner/minerblock.js @@ -7,10 +7,11 @@ 'use strict'; +var assert = require('assert'); var utils = require('../utils/utils'); +var btcutils = require('../utils/btcutils'); var co = require('../utils/co'); var crypto = require('../crypto/crypto'); -var assert = require('assert'); var constants = require('../protocol/constants'); var Network = require('../protocol/network'); var BN = require('bn.js'); @@ -52,7 +53,7 @@ function MinerBlock(options) { this.version = options.version; this.height = options.tip.height + 1; this.bits = options.bits; - this.target = utils.fromCompact(this.bits).toArrayLike(Buffer, 'le', 32); + this.target = btcutils.fromCompact(this.bits).toArrayLike(Buffer, 'le', 32); this.locktime = options.locktime; this.flags = options.flags; this.extraNonce = new BN(0); @@ -62,7 +63,7 @@ function MinerBlock(options) { this.address = options.address; this.network = Network.get(options.network); this.destroyed = false; - this.reward = Block.reward(this.height, this.network); + this.reward = btcutils.getReward(this.height, this.network.halvingInterval); this.sigops = 0; this.weight = 0; diff --git a/lib/net/bip150.js b/lib/net/bip150.js index 20d664f5..daa51dbc 100644 --- a/lib/net/bip150.js +++ b/lib/net/bip150.js @@ -17,6 +17,7 @@ var assert = require('assert'); var constants = require('../protocol/constants'); var ec = require('../crypto/ec'); var BufferWriter = require('../utils/writer'); +var base58 = require('../utils/base58'); /** * Represents a BIP150 input and output stream. @@ -286,7 +287,7 @@ BIP150.address = function address(key) { p.writeU16BE(0xff01); p.writeBytes(crypto.hash160(key)); p.writeChecksum(); - return utils.toBase58(p.render()); + return base58.encode(p.render()); }; /** diff --git a/lib/net/bip152.js b/lib/net/bip152.js index 22d35e62..855775e0 100644 --- a/lib/net/bip152.js +++ b/lib/net/bip152.js @@ -405,10 +405,7 @@ CompactBlock.prototype.destroy = function destroy() { }; CompactBlock.prototype.toHeaders = function toHeaders() { - var headers = new Headers(this); - headers._hash = this._hash; - headers._valid = true; - return headers; + return Headers.fromBlock(this); }; /** diff --git a/lib/net/pool.js b/lib/net/pool.js index e6d2ad33..c0ca02c4 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -14,9 +14,10 @@ var utils = require('../utils/utils'); var IP = require('../utils/ip'); var co = require('../utils/co'); var constants = require('../protocol/constants'); -var VerifyError = require('../utils/errors').VerifyError; +var errors = require('../utils/errors'); +var VerifyError = errors.VerifyError; +var VerifyResult = errors.VerifyResult; var NetworkAddress = require('../primitives/netaddress'); -var VerifyResult = utils.VerifyResult; var Address = require('../primitives/address'); var BIP150 = require('./bip150'); var Bloom = require('../utils/bloom'); diff --git a/lib/primitives/abstractblock.js b/lib/primitives/abstractblock.js index 3dd1e67d..42805a21 100644 --- a/lib/primitives/abstractblock.js +++ b/lib/primitives/abstractblock.js @@ -7,11 +7,12 @@ 'use strict'; +var assert = require('assert'); var constants = require('../protocol/constants'); var utils = require('../utils/utils'); var crypto = require('../crypto/crypto'); -var assert = require('assert'); -var VerifyResult = utils.VerifyResult; +var btcutils = require('../utils/btcutils'); +var VerifyResult = require('../utils/errors').VerifyResult; var BufferWriter = require('../utils/writer'); var time = require('../net/timedata'); var InvItem = require('./invitem'); @@ -211,14 +212,14 @@ AbstractBlock.prototype.verifyHeaders = function verifyHeaders(ret) { if (!ret) ret = new VerifyResult(); - // Check proof of work - if (!utils.testTarget(this.hash(), this.bits)) { + // Check proof of work. + if (!this.verifyPOW()) { ret.reason = 'high-hash'; ret.score = 50; return false; } - // Check timestamp against now + 2 hours + // Check timestamp against adjusted-time + 2 hours. if (this.ts > time.now() + 2 * 60 * 60) { ret.reason = 'time-too-new'; ret.score = 0; @@ -228,6 +229,15 @@ AbstractBlock.prototype.verifyHeaders = function verifyHeaders(ret) { return true; }; +/** + * Verify proof-of-work. + * @returns {Boolean} + */ + +AbstractBlock.prototype.verifyPOW = function verifyPOW() { + return btcutils.verifyPOW(this.hash(), this.bits); +}; + /** * Set the `height` property and the `height` * property of all transactions within the block. diff --git a/lib/primitives/address.js b/lib/primitives/address.js index c2516881..37325c5a 100644 --- a/lib/primitives/address.js +++ b/lib/primitives/address.js @@ -15,6 +15,7 @@ var crypto = require('../crypto/crypto'); var assert = require('assert'); var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); +var base58 = require('../utils/base58'); var scriptTypes = constants.scriptTypes; /** @@ -136,7 +137,7 @@ Address.prototype.toRaw = function toRaw(network) { */ Address.prototype.toBase58 = function toBase58(network) { - return utils.toBase58(this.toRaw(network)); + return base58.encode(this.toRaw(network)); }; /** @@ -225,7 +226,7 @@ Address.fromRaw = function fromRaw(data) { Address.prototype.fromBase58 = function fromBase58(data) { assert(typeof data === 'string'); - return this.fromRaw(utils.fromBase58(data)); + return this.fromRaw(base58.decode(data)); }; /** diff --git a/lib/primitives/block.js b/lib/primitives/block.js index 2be9a15b..f9be7521 100644 --- a/lib/primitives/block.js +++ b/lib/primitives/block.js @@ -7,12 +7,13 @@ 'use strict'; +var assert = require('assert'); var utils = require('../utils/utils'); var crypto = require('../crypto/crypto'); -var assert = require('assert'); +var btcutils = require('../utils/btcutils'); var constants = require('../protocol/constants'); var AbstractBlock = require('./abstractblock'); -var VerifyResult = utils.VerifyResult; +var VerifyResult = require('../utils/errors').VerifyResult; var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); var TX = require('./tx'); @@ -492,8 +493,10 @@ Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() { */ Block.prototype.getReward = function getReward(network) { - var reward = Block.reward(this.height, network); - var i, fee; + var i, reward, fee; + + network = Network.get(network); + reward = btcutils.getReward(this.height, network.halvingInterval); for (i = 1; i < this.txs.length; i++) { fee = this.txs[i].getFee(); @@ -528,36 +531,6 @@ Block.prototype.getClaimed = function getClaimed() { return this.txs[0].getOutputValue(); }; -/** - * Calculate block subsidy. - * @param {Number} height - Reward era by height. - * @returns {Amount} - */ - -Block.reward = function reward(height, network) { - var halvings; - - assert(height >= 0, 'Bad height for reward.'); - - network = Network.get(network); - halvings = height / network.halvingInterval | 0; - - // BIP 42 (well, our own version of it, - // since we can only handle 32 bit shifts). - // https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki - if (halvings >= 33) - return 0; - - // We need to shift right by `halvings`, - // but 50 btc is a 33 bit number, so we - // cheat. We only start halving once the - // halvings are at least 1. - if (halvings === 0) - return 5000000000; - - return 2500000000 >>> (halvings - 1); -}; - /** * Get all unique outpoint hashes in the * block. Coinbases are ignored. @@ -795,10 +768,7 @@ Block.prototype.frameWitness = function frameWitness(writer) { */ Block.prototype.toHeaders = function toHeaders() { - var headers = new Headers(this); - headers._hash = this._hash; - headers._valid = true; - return headers; + return Headers.fromBlock(this); }; /** diff --git a/lib/primitives/headers.js b/lib/primitives/headers.js index 23ef030a..01b3db11 100644 --- a/lib/primitives/headers.js +++ b/lib/primitives/headers.js @@ -184,6 +184,19 @@ Headers.prototype.toHeaders = function toHeaders() { return this; }; +/** + * Convert the block to a headers object. + * @param {Block|MerkleBlock} block + * @returns {Headers} + */ + +Headers.fromBlock = function fromBlock(block) { + var headers = new Headers(block); + headers._hash = block._hash; + headers._valid = true; + return headers; +}; + /** * Test an object to see if it is a Headers object. * @param {Object} obj diff --git a/lib/primitives/keyring.js b/lib/primitives/keyring.js index 8174e12b..83acf9bb 100644 --- a/lib/primitives/keyring.js +++ b/lib/primitives/keyring.js @@ -15,6 +15,7 @@ var networks = require('../protocol/networks'); var Network = require('../protocol/network'); var BufferReader = require('../utils/reader'); var BufferWriter = require('../utils/writer'); +var base58 = require('../utils/base58'); var Script = require('../script/script'); var Address = require('./address'); var Input = require('./input'); @@ -281,7 +282,7 @@ KeyRing.prototype.toSecret = function toSecret() { p.writeChecksum(); - return utils.toBase58(p.render()); + return base58.encode(p.render()); }; /** @@ -291,7 +292,7 @@ KeyRing.prototype.toSecret = function toSecret() { */ KeyRing.prototype.fromSecret = function fromSecret(data) { - var p = new BufferReader(utils.fromBase58(data), true); + var p = new BufferReader(base58.decode(data), true); var i, prefix, version, type, key, compressed; version = p.readU8(); @@ -356,7 +357,7 @@ KeyRing.prototype.getPrivateKey = function getPrivateKey(enc) { KeyRing.prototype.getPublicKey = function getPublicKey(enc) { if (enc === 'base58') - return utils.toBase58(this.publicKey); + return base58.encode(this.publicKey); if (enc === 'hex') return this.publicKey.toString('hex'); diff --git a/lib/primitives/memblock.js b/lib/primitives/memblock.js index 9c352437..d8dc1c76 100644 --- a/lib/primitives/memblock.js +++ b/lib/primitives/memblock.js @@ -199,10 +199,7 @@ MemBlock.prototype.toBlock = function toBlock() { */ MemBlock.prototype.toHeaders = function toHeaders() { - var headers = new Headers(this); - headers._hash = this._hash; - headers._valid = true; - return headers; + return Headers.fromBlock(this); }; /** diff --git a/lib/primitives/merkleblock.js b/lib/primitives/merkleblock.js index 3a29e0db..d46ef721 100644 --- a/lib/primitives/merkleblock.js +++ b/lib/primitives/merkleblock.js @@ -13,7 +13,7 @@ var assert = require('assert'); var constants = require('../protocol/constants'); var DUMMY = new Buffer([0]); var AbstractBlock = require('./abstractblock'); -var VerifyResult = utils.VerifyResult; +var VerifyResult = require('../utils/errors').VerifyResult; var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); var Headers = require('./headers'); @@ -644,10 +644,7 @@ MerkleBlock.isMerkleBlock = function isMerkleBlock(obj) { */ MerkleBlock.prototype.toHeaders = function toHeaders() { - var headers = new Headers(this); - headers._hash = this._hash; - headers._valid = true; - return headers; + return Headers.fromBlock(this); }; /* diff --git a/lib/primitives/mtx.js b/lib/primitives/mtx.js index cef6c223..8edb634d 100644 --- a/lib/primitives/mtx.js +++ b/lib/primitives/mtx.js @@ -7,8 +7,9 @@ 'use strict'; -var utils = require('../utils/utils'); var assert = require('assert'); +var utils = require('../utils/utils'); +var btcutils = require('../utils/btcutils'); var constants = require('../protocol/constants'); var Script = require('../script/script'); var opcodes = Script.opcodes; @@ -20,6 +21,7 @@ var Coin = require('./coin'); var KeyRing = require('./keyring'); var Address = require('./address'); var workers = require('../workers/workers'); +var encoding = require('../utils/encoding'); /** * A mutable transaction object. @@ -973,7 +975,7 @@ MTX.prototype.maxSize = function maxSize(options) { for (i = 0; i < this.inputs.length; i++) { input = this.inputs[i]; size = input.script.getSize(); - total -= utils.sizeVarint(size) + size; + total -= encoding.sizeVarint(size) + size; } // Add size for signatures and public keys @@ -1016,7 +1018,7 @@ MTX.prototype.maxSize = function maxSize(options) { if (redeem) { // The regular redeem script // is now worth 4 points. - size += utils.sizeVarint(size); + size += encoding.sizeVarint(size); size *= 4; } else { // Add one varint byte back @@ -1035,7 +1037,7 @@ MTX.prototype.maxSize = function maxSize(options) { if (redeem) { prev = redeem; sz = prev.getSize(); - size += utils.sizeVarint(sz); + size += encoding.sizeVarint(sz); size += sz; } } else if (prev.isWitnessPubkeyhash()) { @@ -1104,7 +1106,7 @@ MTX.prototype.maxSize = function maxSize(options) { } else { // Byte for varint // size of input script. - size += utils.sizeVarint(size); + size += encoding.sizeVarint(size); } total += size; @@ -1658,9 +1660,9 @@ CoinSelector.prototype.getFee = function getFee(size) { var fee; if (this.round) - fee = TX.getRoundFee(size, this.rate); + fee = btcutils.getRoundFee(size, this.rate); else - fee = TX.getMinFee(size, this.rate); + fee = btcutils.getMinFee(size, this.rate); if (fee > constants.tx.MAX_FEE) fee = constants.tx.MAX_FEE; diff --git a/lib/primitives/tx.js b/lib/primitives/tx.js index 6a00d710..ec6228a2 100644 --- a/lib/primitives/tx.js +++ b/lib/primitives/tx.js @@ -7,15 +7,16 @@ 'use strict'; +var assert = require('assert'); var utils = require('../utils/utils'); var crypto = require('../crypto/crypto'); -var assert = require('assert'); +var btcutils = require('../utils/btcutils'); var constants = require('../protocol/constants'); var Network = require('../protocol/network'); var Script = require('../script/script'); var Stack = require('../script/stack'); var BufferWriter = require('../utils/writer'); -var VerifyResult = utils.VerifyResult; +var VerifyResult = require('../utils/errors').VerifyResult; var Input = require('./input'); var Output = require('./output'); var Outpoint = require('./outpoint'); @@ -1850,7 +1851,7 @@ TX.prototype.getMinFee = function getMinFee(size, rate) { if (size == null) size = this.maxSize(); - return TX.getMinFee(size, rate); + return btcutils.getMinFee(size, rate); }; /** @@ -1867,7 +1868,7 @@ TX.prototype.getRoundFee = function getRoundFee(size, rate) { if (size == null) size = this.maxSize(); - return TX.getRoundFee(size, rate); + return btcutils.getRoundFee(size, rate); }; /** @@ -1881,7 +1882,7 @@ TX.prototype.getRate = function getRate(size) { if (size == null) size = this.maxSize(); - return TX.getRate(size, this.getFee()); + return btcutils.getRate(size, this.getFee()); }; /** @@ -2021,137 +2022,6 @@ TX.prototype.toInv = function toInv() { return new InvItem(constants.inv.TX, this.hash('hex')); }; -/** - * Calculate minimum fee based on rate and size. - * @param {Number?} size - * @param {Rate?} rate - Rate of satoshi per kB. - * @returns {Amount} fee - */ - -TX.getMinFee = function getMinFee(size, rate) { - var fee; - - if (rate == null) - rate = constants.tx.MIN_RELAY; - - fee = Math.floor(rate * size / 1000); - - if (fee === 0 && rate > 0) - fee = rate; - - return fee; -}; - -/** - * Calculate the minimum fee in order for the transaction - * to be relayable, but _round to the nearest kilobyte - * when taking into account size. - * @param {Number?} size - * @param {Rate?} rate - Rate of satoshi per kB. - * @returns {Amount} fee - */ - -TX.getRoundFee = function getRoundFee(size, rate) { - var fee; - - if (rate == null) - rate = constants.tx.MIN_RELAY; - - fee = rate * Math.ceil(size / 1000); - - if (fee === 0 && rate > 0) - fee = rate; - - return fee; -}; - -/** - * Calculate a fee rate based on size and fees. - * @param {Number} size - * @param {Amount} fee - * @returns {Rate} - */ - -TX.getRate = function getRate(size, fee) { - return Math.floor(fee * 1000 / size); -}; - -/** - * Sort an array of transactions in dependency order. - * @param {TX[]} txs - * @returns {TX[]} - */ - -TX.sort = function sort(txs) { - var depMap = {}; - var count = {}; - var result = []; - var top = []; - var map = txs; - var i, j, tx, hash, input; - var prev, hasDeps, deps; - - if (Array.isArray(txs)) { - map = {}; - for (i = 0; i < txs.length; i++) { - tx = txs[i]; - hash = tx.hash('hex'); - map[hash] = tx; - } - } - - for (i = 0; i < txs.length; i++) { - tx = txs[i]; - hash = tx.hash('hex'); - hasDeps = false; - - count[hash] = 0; - - for (j = 0; j < tx.inputs.length; j++) { - input = tx.inputs[j]; - prev = input.prevout.hash; - - if (!map[prev]) - continue; - - count[hash] += 1; - hasDeps = true; - - if (!depMap[prev]) - depMap[prev] = []; - - depMap[prev].push(tx); - } - - if (hasDeps) - continue; - - top.push(tx); - } - - for (i = 0; i < top.length; i++) { - tx = top[i]; - hash = tx.hash('hex'); - - result.push(tx); - - deps = depMap[hash]; - - if (!deps) - continue; - - for (j = 0; j < deps.length; j++) { - tx = deps[j]; - hash = tx.hash('hex'); - - if (--count[hash] === 0) - top.push(tx); - } - } - - return result; -}; - /** * Inspect the transaction and return a more * user-friendly representation of the data. diff --git a/lib/script/script.js b/lib/script/script.js index adb82111..eaa93d72 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -1579,7 +1579,7 @@ Script.prototype.fromMultisig = function fromMultisig(m, n, keys) { assert(m >= 1 && m <= n); assert(n >= 1 && n <= 15); - keys = utils.sortKeys(keys); + keys = sortKeys(keys); this.push(Opcode.fromSmall(m)); @@ -3644,6 +3644,16 @@ Script.isScript = function isScript(obj) { && typeof obj.getSubscript === 'function'; }; +/* + * Helpers + */ + +function sortKeys(keys) { + return keys.slice().sort(function(a, b) { + return utils.cmp(a, b); + }); +} + /* * Expose */ diff --git a/lib/utils/base58.js b/lib/utils/base58.js index a762e901..5c7df188 100644 --- a/lib/utils/base58.js +++ b/lib/utils/base58.js @@ -31,7 +31,7 @@ for (var i = 0; i < base58.length; i++) * @returns {Base58String} */ -exports.toBase58 = function toBase58(data) { +exports.encode = function encode(data) { var zeroes = 0; var length = 0; var str = ''; @@ -76,7 +76,7 @@ exports.toBase58 = function toBase58(data) { }; if (native) - exports.toBase58 = native.toBase58; + exports.encode = native.toBase58; /** * Decode a base58 string. @@ -86,7 +86,7 @@ if (native) * @throws on non-base58 character. */ -exports.fromBase58 = function fromBase58(str) { +exports.decode = function decode(str) { var zeroes = 0; var length = 0; var i = 0; @@ -137,4 +137,4 @@ exports.fromBase58 = function fromBase58(str) { }; if (native) - exports.fromBase58 = native.fromBase58; + exports.decode = native.fromBase58; diff --git a/lib/utils/btcutils.js b/lib/utils/btcutils.js new file mode 100644 index 00000000..dab5711e --- /dev/null +++ b/lib/utils/btcutils.js @@ -0,0 +1,403 @@ +/*! + * btcutils.js - bitcoin-related utils for bcoin + * Copyright (c) 2014-2015, Fedor Indutny (MIT License) + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var assert = require('assert'); +var BN = require('bn.js'); +var constants = require('../protocol/constants'); +var utils = require('./utils'); +var btcutils = exports; + +/** + * Convert a compact number to a big number. + * Used for `block.bits` -> `target` conversion. + * @param {Number} compact + * @returns {BN} + */ + +btcutils.fromCompact = function fromCompact(compact) { + var exponent = compact >>> 24; + var negative = (compact >>> 23) & 1; + var mantissa = compact & 0x7fffff; + var num; + + if (compact === 0) + return new BN(0); + + // Logic ported from btcd since + // the bitcoind code is a nightmare. + if (exponent <= 3) { + mantissa >>>= 8 * (3 - exponent); + num = new BN(mantissa); + } else { + num = new BN(mantissa); + num.iushln(8 * (exponent - 3)); + } + + if (negative) + num.ineg(); + + return num; +}; + +/** + * Convert a big number to a compact number. + * Used for `target` -> `block.bits` conversion. + * @param {BN} num + * @returns {Number} + */ + +btcutils.toCompact = function toCompact(num) { + var mantissa, exponent, compact; + + if (num.cmpn(0) === 0) + return 0; + + exponent = num.byteLength(); + + // Logic ported from btcd since + // the bitcoind code is a nightmare. + if (exponent <= 3) { + mantissa = num.toNumber(); + mantissa <<= 8 * (3 - exponent); + } else { + mantissa = num.ushrn(8 * (exponent - 3)).toNumber(); + } + + if (mantissa & 0x800000) { + mantissa >>= 8; + exponent++; + } + + compact = (exponent << 24) | mantissa; + + if (num.isNeg()) + compact |= 0x800000; + + compact >>>= 0; + + return compact; +}; + +/** + * Verify proof-of-work. + * @returns {Boolean} + */ + +btcutils.verifyPOW = function verifyPOW(hash, bits) { + var target = btcutils.fromCompact(bits); + + if (target.isNeg() || target.cmpn(0) === 0) + return false; + + hash = new BN(hash, 'le'); + + if (hash.cmp(target) > 0) + return false; + + return true; +}; + +/** + * Calculate block subsidy. + * @param {Number} height - Reward era by height. + * @returns {Amount} + */ + +btcutils.getReward = function getReward(height, interval) { + var halvings = height / interval | 0; + + assert(height >= 0, 'Bad height for reward.'); + + // BIP 42 (well, our own version of it, + // since we can only handle 32 bit shifts). + // https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki + if (halvings >= 33) + return 0; + + // We need to shift right by `halvings`, + // but 50 btc is a 33 bit number, so we + // cheat. We only start halving once the + // halvings are at least 1. + if (halvings === 0) + return 5000000000; + + return 2500000000 >>> (halvings - 1); +}; + +/** + * Calculate minimum fee based on rate and size. + * @param {Number?} size + * @param {Rate?} rate - Rate of satoshi per kB. + * @returns {Amount} fee + */ + +btcutils.getMinFee = function getMinFee(size, rate) { + var fee; + + if (rate == null) + rate = constants.tx.MIN_RELAY; + + fee = Math.floor(rate * size / 1000); + + if (fee === 0 && rate > 0) + fee = rate; + + return fee; +}; + +/** + * Calculate the minimum fee in order for the transaction + * to be relayable, but _round to the nearest kilobyte + * when taking into account size. + * @param {Number?} size + * @param {Rate?} rate - Rate of satoshi per kB. + * @returns {Amount} fee + */ + +btcutils.getRoundFee = function getRoundFee(size, rate) { + var fee; + + if (rate == null) + rate = constants.tx.MIN_RELAY; + + fee = rate * Math.ceil(size / 1000); + + if (fee === 0 && rate > 0) + fee = rate; + + return fee; +}; + +/** + * Calculate a fee rate based on size and fees. + * @param {Number} size + * @param {Amount} fee + * @returns {Rate} + */ + +btcutils.getRate = function getRate(size, fee) { + return Math.floor(fee * 1000 / size); +}; + +/** + * Safely convert satoshis to a BTC string. + * This function explicitly avoids any + * floating point arithmetic. + * @param {Amount} value - Satoshis. + * @returns {String} BTC string. + */ + +btcutils.btc = function btc(value) { + var negative = false; + var hi, lo, result; + + if (utils.isFloat(value)) + return value; + + assert(utils.isInt(value), 'Non-satoshi value for conversion.'); + + if (value < 0) { + value = -value; + negative = true; + } + + assert(value <= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1.'); + + value = value.toString(10); + + assert(value.length <= 16, 'Number exceeds 2^53-1.'); + + while (value.length < 9) + value = '0' + value; + + hi = value.slice(0, -8); + lo = value.slice(-8); + + lo = lo.replace(/0+$/, ''); + + if (lo.length === 0) + lo += '0'; + + result = hi + '.' + lo; + + if (negative) + result = '-' + result; + + return result; +}; + +/** + * Safely convert a BTC string to satoshis. + * This function explicitly avoids any + * floating point arithmetic. It also does + * extra validation to ensure the resulting + * Number will be 53 bits or less. + * @param {String} value - BTC + * @returns {Amount} Satoshis. + * @throws on parse error + */ + +btcutils.satoshi = function satoshi(value) { + var negative = false; + var parts, hi, lo, result; + + if (utils.isInt(value)) + return value; + + assert(utils.isFloat(value), 'Non-BTC value for conversion.'); + + if (value[0] === '-') { + negative = true; + value = value.substring(1); + } + + parts = value.split('.'); + + assert(parts.length <= 2, 'Bad decimal point.'); + + hi = parts[0] || '0'; + lo = parts[1] || '0'; + + hi = hi.replace(/^0+/, ''); + lo = lo.replace(/0+$/, ''); + + assert(hi.length <= 8, 'Number exceeds 2^53-1.'); + assert(lo.length <= 8, 'Too many decimal places.'); + + if (hi.length === 0) + hi = '0'; + + while (lo.length < 8) + lo += '0'; + + hi = parseInt(hi, 10); + lo = parseInt(lo, 10); + + assert(hi < 90071992 || (hi === 90071992 && lo <= 54740991), + 'Number exceeds 2^53-1.'); + + result = hi * 100000000 + lo; + + if (negative) + result = -result; + + return result; +}; + +/** + * Test and validate a satoshi value (Number). + * @param {Number?} value + * @returns {Boolean} + */ + +btcutils.isSatoshi = function isSatoshi(value) { + if (typeof value !== 'number') + return false; + + try { + utils.satoshi(value); + return true; + } catch (e) { + return false; + } +}; + +/** + * Test and validate a BTC string. + * @param {String?} value + * @returns {Boolean} + */ + +btcutils.isBTC = function isBTC(value) { + if (typeof value !== 'string') + return false; + + try { + utils.btc(value); + return true; + } catch (e) { + return false; + } +}; + +/** + * Sort an array of transactions in dependency order. + * @param {TX[]} txs + * @returns {TX[]} + */ + +btcutils.sortTX = function sortTX(txs) { + var depMap = {}; + var count = {}; + var result = []; + var top = []; + var map = txs; + var i, j, tx, hash, input; + var prev, hasDeps, deps; + + if (Array.isArray(txs)) { + map = {}; + for (i = 0; i < txs.length; i++) { + tx = txs[i]; + hash = tx.hash('hex'); + map[hash] = tx; + } + } + + for (i = 0; i < txs.length; i++) { + tx = txs[i]; + hash = tx.hash('hex'); + hasDeps = false; + + count[hash] = 0; + + for (j = 0; j < tx.inputs.length; j++) { + input = tx.inputs[j]; + prev = input.prevout.hash; + + if (!map[prev]) + continue; + + count[hash] += 1; + hasDeps = true; + + if (!depMap[prev]) + depMap[prev] = []; + + depMap[prev].push(tx); + } + + if (hasDeps) + continue; + + top.push(tx); + } + + for (i = 0; i < top.length; i++) { + tx = top[i]; + hash = tx.hash('hex'); + + result.push(tx); + + deps = depMap[hash]; + + if (!deps) + continue; + + for (j = 0; j < deps.length; j++) { + tx = deps[j]; + hash = tx.hash('hex'); + + if (--count[hash] === 0) + top.push(tx); + } + } + + return result; +}; diff --git a/lib/utils/encoding.js b/lib/utils/encoding.js new file mode 100644 index 00000000..30b2f227 --- /dev/null +++ b/lib/utils/encoding.js @@ -0,0 +1,653 @@ +/*! + * encoding.js - encoding utils for bcoin + * Copyright (c) 2014-2015, Fedor Indutny (MIT License) + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var assert = require('assert'); +var BN = require('bn.js'); +var encoding = exports; + +/** + * UINT32_MAX + * @const {BN} + */ + +encoding.U32_MAX = new BN(0xffffffff); + +/** + * UINT64_MAX + * @const {BN} + */ + +encoding.U64_MAX = new BN('ffffffffffffffff', 'hex'); + +/** + * Read uint64le. + * @param {Buffer} data + * @param {Number} off + * @returns {BN} + */ + +encoding.readU64 = function readU64(data, off) { + var num; + off = off >>> 0; + num = data.slice(off, off + 8); + return new BN(num, 'le'); +}; + +/** + * Read uint64be. + * @param {Buffer} data + * @param {Number} off + * @returns {BN} + */ + +encoding.readU64BE = function readU64BE(data, off) { + var num; + off = off >>> 0; + num = data.slice(off, off + 8); + return new BN(num, 'be'); +}; + +/** + * Read int64le. + * @param {Buffer} data + * @param {Number} off + * @returns {BN} + */ + +encoding.read64 = function read64(data, off) { + var num; + + off = off >>> 0; + + num = data.slice(off, off + 8); + + if (num[num.length - 1] & 0x80) + return new BN(num, 'le').notn(64).addn(1).neg(); + + return new BN(num, 'le'); +}; + +/** + * Read int64be. + * @param {Buffer} data + * @param {Number} off + * @returns {BN} + */ + +encoding.read64BE = function read64BE(data, off) { + var num; + + off = off >>> 0; + + num = data.slice(off, off + 8); + + if (num[0] & 0x80) + return new BN(num, 'be').notn(64).addn(1).neg(); + + return new BN(num, 'be'); +}; + +/** + * Write uint64le. + * @param {BN|Number} value + */ + +encoding.writeU64 = function writeU64(dst, num, off) { + return encoding.write64(dst, num, off); +}; + +/** + * Write uint64be. + * @param {BN|Number} value + */ + +encoding.writeU64BE = function writeU64BE(dst, num, off) { + return encoding.write64BE(dst, num, off); +}; + +/** + * Write a javascript number as a uint64le (faster than big numbers). + * @param {Number} value + * @throws on num > MAX_SAFE_INTEGER + */ + +encoding.writeU64N = function writeU64N(dst, num, off) { + return encoding.write64N(dst, num, off); +}; + +/** + * Write a javascript number as a uint64be (faster than big numbers). + * @param {Number} value + * @throws on num > MAX_SAFE_INTEGER + */ + +encoding.writeU64NBE = function writeU64NBE(dst, num, off) { + return encoding.write64NBE(dst, num, off); +}; + +/** + * Max safe integer (53 bits). + * @const {Number} + * @default + */ + +encoding.MAX_SAFE_INTEGER = 0x1fffffffffffff; + +/** + * Max 52 bit integer (safe for additions). + * `(MAX_SAFE_INTEGER - 1) / 2` + * @const {Number} + * @default + */ + +encoding.MAX_SAFE_ADDITION = 0xfffffffffffff; + +/** + * Write a javascript number as an int64le (faster than big numbers). + * @param {Number} value + * @throws on num > MAX_SAFE_INTEGER + */ + +encoding.write64N = function write64N(dst, num, off, be) { + var negative, hi, lo; + + assert(typeof num === 'number'); + + off = off >>> 0; + + negative = num < 0; + + if (negative) { + num = -num; + num -= 1; + } + + assert(num <= encoding.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1'); + + lo = num % 0x100000000; + hi = (num - lo) / 0x100000000; + + if (negative) { + hi = ~hi >>> 0; + lo = ~lo >>> 0; + } + + if (be) { + dst[off + 0] = (hi >>> 24) & 0xff; + dst[off + 1] = (hi >>> 16) & 0xff; + dst[off + 2] = (hi >>> 8) & 0xff; + dst[off + 3] = (hi >>> 0) & 0xff; + dst[off + 4] = (lo >>> 24) & 0xff; + dst[off + 5] = (lo >>> 16) & 0xff; + dst[off + 6] = (lo >>> 8) & 0xff; + dst[off + 7] = (lo >>> 0) & 0xff; + } else { + dst[off + 0] = (lo >>> 0) & 0xff; + dst[off + 1] = (lo >>> 8) & 0xff; + dst[off + 2] = (lo >>> 16) & 0xff; + dst[off + 3] = (lo >>> 24) & 0xff; + dst[off + 4] = (hi >>> 0) & 0xff; + dst[off + 5] = (hi >>> 8) & 0xff; + dst[off + 6] = (hi >>> 16) & 0xff; + dst[off + 7] = (hi >>> 24) & 0xff; + } + + return off + 8; +}; + +/** + * Write a javascript number as an int64be (faster than big numbers). + * @param {Number} value + * @throws on num > MAX_SAFE_INTEGER + */ + +encoding.write64NBE = function write64NBE(dst, num, off) { + return encoding.write64N(dst, num, off, true); +}; + +/** + * Read uint64le as a js number. + * @param {Buffer} data + * @param {Number} off + * @param {Boolean} force53 - Read only 53 bits, but maintain the sign. + * @returns {Number} + * @throws on num > MAX_SAFE_INTEGER + */ + +encoding.readU64N = function readU64N(data, off, force53, be) { + var hi, lo; + + off = off >>> 0; + + if (be) { + hi = data.readUInt32BE(off, true); + lo = data.readUInt32BE(off + 4, true); + } else { + hi = data.readUInt32LE(off + 4, true); + lo = data.readUInt32LE(off, true); + } + + if (force53) + hi &= 0x1fffff; + + assert((hi & 0xffe00000) === 0, 'Number exceeds 2^53-1'); + + return (hi * 0x100000000) + lo; +}; + +/** + * Read uint64be as a js number. + * @param {Buffer} data + * @param {Number} off + * @param {Boolean} force53 - Read only 53 bits, but maintain the sign. + * @returns {Number} + * @throws on num > MAX_SAFE_INTEGER + */ + +encoding.readU64NBE = function readU64NBE(data, off, force53) { + return encoding.readU64N(data, off, force53, true); +}; + +/** + * Read int64le as a js number. + * @param {Buffer} data + * @param {Number} off + * @param {Boolean} force53 - Read only 53 bits, but maintain the sign. + * @returns {Number} + * @throws on num > MAX_SAFE_INTEGER + */ + +encoding.read64N = function read64N(data, off, force53, be) { + var hi, lo; + + off = off >>> 0; + + if (be) { + hi = data.readUInt32BE(off, true); + lo = data.readUInt32BE(off + 4, true); + } else { + hi = data.readUInt32LE(off + 4, true); + lo = data.readUInt32LE(off, true); + } + + if (hi & 0x80000000) { + hi = ~hi >>> 0; + lo = ~lo >>> 0; + + if (force53) + hi &= 0x1fffff; + + assert((hi & 0xffe00000) === 0, 'Number exceeds 2^53-1'); + + return -(hi * 0x100000000 + lo + 1); + } + + if (force53) + hi &= 0x1fffff; + + assert((hi & 0xffe00000) === 0, 'Number exceeds 2^53-1'); + + return hi * 0x100000000 + lo; +}; + +/** + * Read int64be as a js number. + * @param {Buffer} data + * @param {Number} off + * @param {Boolean} force53 - Read only 53 bits, but maintain the sign. + * @returns {Number} + * @throws on num > MAX_SAFE_INTEGER + */ + +encoding.read64NBE = function read64NBE(data, off, force53) { + return encoding.read64N(data, off, force53, true); +}; + +/** + * Write int64le. + * @param {Buffer} dst + * @param {BN|Number} num + * @param {Number} off + * @returns {Number} Number of bytes written. + */ + +encoding.write64 = function write64(dst, num, off) { + var i; + + if (typeof num === 'number') + return encoding.write64N(dst, num, off); + + off = off >>> 0; + + if (num.isNeg()) + num = num.neg().inotn(64).iaddn(1); + + if (num.bitLength() > 64) + num = num.uand(encoding.U64_MAX); + + num = num.toArray('le', 8); + + for (i = 0; i < num.length; i++) + dst[off++] = num[i]; + + return off; +}; + +/** + * Write int64be. + * @param {Buffer} dst + * @param {BN|Number} num + * @param {Number} off + * @returns {Number} Number of bytes written. + */ + +encoding.write64BE = function write64BE(dst, num, off) { + var i; + + if (typeof num === 'number') + return encoding.write64NBE(dst, num, off); + + off = off >>> 0; + + if (num.isNeg()) + num = num.neg().inotn(64).iaddn(1); + + if (num.bitLength() > 64) + num = num.uand(encoding.U64_MAX); + + num = num.toArray('be', 8); + + for (i = 0; i < num.length; i++) + dst[off++] = num[i]; + + return off; +}; + +/** + * Read a varint. + * @param {Buffer} data + * @param {Number} off + * @param {Boolean?} big - Whether to read as a big number. + * @returns {Object} + */ + +encoding.readVarint = function readVarint(data, off, big) { + var value, size; + + off = off >>> 0; + + assert(off < data.length); + + switch (data[off]) { + case 0xff: + size = 9; + assert(off + size <= data.length); + if (big) { + value = encoding.readU64(data, off + 1); + assert(value.bitLength() > 32); + } else { + value = encoding.readU64N(data, off + 1); + assert(value > 0xffffffff); + } + break; + case 0xfe: + size = 5; + assert(off + size <= data.length); + value = data.readUInt32LE(off + 1, true); + assert(value > 0xffff); + if (big) + value = new BN(value); + break; + case 0xfd: + size = 3; + assert(off + size <= data.length); + value = data[off + 1] | (data[off + 2] << 8); + assert(value >= 0xfd); + if (big) + value = new BN(value); + break; + default: + size = 1; + value = data[off]; + if (big) + value = new BN(value); + break; + } + + return { size: size, value: value }; +}; + +/** + * Write a varint. + * @param {Buffer} dst + * @param {BN|Number} num + * @param {Number} off + * @returns {Number} Number of bytes written. + */ + +encoding.writeVarint = function writeVarint(dst, num, off) { + off = off >>> 0; + + if (BN.isBN(num)) { + if (num.bitLength() > 32) { + dst[off] = 0xff; + encoding.writeU64(dst, num, off + 1); + return off + 9; + } + num = num.toNumber(); + } + + num = +num; + + if (num < 0xfd) { + dst[off] = num & 0xff; + return off + 1; + } + + if (num <= 0xffff) { + dst[off] = 0xfd; + dst[off + 1] = num & 0xff; + dst[off + 2] = (num >>> 8) & 0xff; + return off + 3; + } + + if (num <= 0xffffffff) { + dst[off] = 0xfe; + dst[off + 1] = num & 0xff; + dst[off + 2] = (num >>> 8) & 0xff; + dst[off + 3] = (num >>> 16) & 0xff; + dst[off + 4] = (num >>> 24) & 0xff; + return off + 5; + } + + dst[off] = 0xff; + encoding.writeU64N(dst, num, off + 1); + + return off + 9; +}; + +/** + * Calculate size of varint. + * @param {BN|Number} num + * @returns {Number} size + */ + +encoding.sizeVarint = function sizeVarint(num) { + if (BN.isBN(num)) { + if (num.bitLength() > 32) + return 9; + num = num.toNumber(); + } + + if (num < 0xfd) + return 1; + + if (num <= 0xffff) + return 3; + + if (num <= 0xffffffff) + return 5; + + return 9; +}; + +/** + * Read a varint (type 2). + * @param {Buffer} data + * @param {Number} off + * @param {Boolean?} big - Whether to read as a big number. + * @returns {Object} + */ + +encoding.readVarint2 = function readVarint2(data, off, big) { + var num = 0; + var size = 0; + var bnum, ch; + + off = off >>> 0; + + for (;;) { + assert(off < data.length); + + ch = data[off++]; + size++; + + if (num >= 0x3fffffffffff) { + assert(big, 'Number exceeds 2^53-1.'); + bnum = new BN(num); + num = 0; + } + + if (bnum) { + assert(bnum.bitLength() <= 256); + bnum.iushln(7).iaddn(ch & 0x7f); + if ((ch & 0x80) === 0) + break; + bnum.iaddn(1); + continue; + } + + num = (num * 0x80) + (ch & 0x7f); + if ((ch & 0x80) === 0) + break; + num++; + } + + if (bnum) + return { size: size, value: bnum }; + + if (big) + num = new BN(num); + + return { size: size, value: num }; +}; + +/** + * Write a varint (type 2). + * @param {Buffer} dst + * @param {BN|Number} num + * @param {Number} off + * @returns {Number} Number of bytes written. + */ + +encoding.writeVarint2 = function writeVarint2(dst, num, off) { + var tmp = []; + var len = 0; + + if (BN.isBN(num)) { + if (num.bitLength() > 53) { + for (;;) { + tmp[len] = (num.words[0] & 0x7f) | (len ? 0x80 : 0x00); + if (num.cmpn(0x7f) <= 0) + break; + num.iushrn(7).isubn(1); + len++; + } + + assert(off + len <= dst.length); + + do { + dst[off++] = tmp[len]; + } while (len--); + + return off; + } + + num = num.toNumber(); + } + + off = off >>> 0; + num = +num; + + for (;;) { + tmp[len] = (num & 0x7f) | (len ? 0x80 : 0x00); + if (num <= 0x7f) + break; + num = ((num - (num % 0x80)) / 0x80) - 1; + len++; + } + + assert(off + len <= dst.length); + + do { + dst[off++] = tmp[len]; + } while (len--); + + return off; +}; + +/** + * Calculate size of varint (type 2). + * @param {BN|Number} num + * @returns {Number} size + */ + +encoding.sizeVarint2 = function sizeVarint2(num) { + var size = 0; + + if (BN.isBN(num)) { + if (num.bitLength() > 53) { + num = num.clone(); + + for (;;) { + size++; + if (num.cmpn(0x7f) <= 0) + break; + num.iushrn(7).isubn(1); + } + + return size; + } + + num = num.toNumber(); + } + + num = +num; + + for (;;) { + size++; + if (num <= 0x7f) + break; + num = ((num - (num % 0x80)) / 0x80) - 1; + } + + return size; +}; + +/** + * Serialize number as a u32le. + * @param {Number} num + * @returns {Buffer} + */ + +encoding.U32 = function U32(num) { + var data = new Buffer(4); + data.writeUInt32LE(num, 0, true); + return data; +}; diff --git a/lib/utils/errors.js b/lib/utils/errors.js index fcaaa41b..1e5c01cb 100644 --- a/lib/utils/errors.js +++ b/lib/utils/errors.js @@ -61,6 +61,16 @@ function VerifyError(msg, code, reason, score) { utils.inherits(VerifyError, Error); +/** + * Verication result. + * @constructor + */ + +function VerifyResult() { + this.reason = 'unknown'; + this.score = 0; +} + /** * An error thrown from the scripting system, * potentially pertaining to Script execution. @@ -146,5 +156,6 @@ utils.inherits(FundingError, Error); */ exports.VerifyError = VerifyError; +exports.VerifyResult = VerifyResult; exports.ScriptError = ScriptError; exports.FundingError = FundingError; diff --git a/lib/utils/lazy-browser.js b/lib/utils/lazy-browser.js new file mode 100644 index 00000000..fe132709 --- /dev/null +++ b/lib/utils/lazy-browser.js @@ -0,0 +1,11 @@ +/*! + * lazy-browser.js - lazy loading for bcoin + * Copyright (c) 2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +module.exports = function lazy(require, exports) { + return function() {}; +}; diff --git a/lib/utils/reader.js b/lib/utils/reader.js index 52ded3d7..90faa1e8 100644 --- a/lib/utils/reader.js +++ b/lib/utils/reader.js @@ -7,7 +7,7 @@ 'use strict'; -var utils = require('../utils/utils'); +var encoding = require('./encoding'); var crypto = require('../crypto/crypto'); var assert = require('assert'); @@ -207,7 +207,7 @@ BufferReader.prototype.readU32BE = function readU32BE() { BufferReader.prototype.readU64 = function readU64() { var ret; assert(this.offset + 8 <= this.data.length); - ret = utils.readU64(this.data, this.offset); + ret = encoding.readU64(this.data, this.offset); this.offset += 8; return ret; }; @@ -220,7 +220,7 @@ BufferReader.prototype.readU64 = function readU64() { BufferReader.prototype.readU64BE = function readU64BE() { var ret; assert(this.offset + 8 <= this.data.length); - ret = utils.readU64BE(this.data, this.offset); + ret = encoding.readU64BE(this.data, this.offset); this.offset += 8; return ret; }; @@ -234,7 +234,7 @@ BufferReader.prototype.readU64BE = function readU64BE() { BufferReader.prototype.readU64N = function readU64N(force53) { var ret; assert(this.offset + 8 <= this.data.length); - ret = utils.readU64N(this.data, this.offset, force53); + ret = encoding.readU64N(this.data, this.offset, force53); this.offset += 8; return ret; }; @@ -248,7 +248,7 @@ BufferReader.prototype.readU64N = function readU64N(force53) { BufferReader.prototype.readU64NBE = function readU64NBE(force53) { var ret; assert(this.offset + 8 <= this.data.length); - ret = utils.readU64NBE(this.data, this.offset, force53); + ret = encoding.readU64NBE(this.data, this.offset, force53); this.offset += 8; return ret; }; @@ -346,7 +346,7 @@ BufferReader.prototype.read32BE = function read32BE() { BufferReader.prototype.read64 = function read64() { var ret; assert(this.offset + 8 <= this.data.length); - ret = utils.read64(this.data, this.offset); + ret = encoding.read64(this.data, this.offset); this.offset += 8; return ret; }; @@ -359,7 +359,7 @@ BufferReader.prototype.read64 = function read64() { BufferReader.prototype.read64BE = function read64BE() { var ret; assert(this.offset + 8 <= this.data.length); - ret = utils.read64BE(this.data, this.offset); + ret = encoding.read64BE(this.data, this.offset); this.offset += 8; return ret; }; @@ -373,7 +373,7 @@ BufferReader.prototype.read64BE = function read64BE() { BufferReader.prototype.read64N = function read64N(force53) { var ret; assert(this.offset + 8 <= this.data.length); - ret = utils.read64N(this.data, this.offset, force53); + ret = encoding.read64N(this.data, this.offset, force53); this.offset += 8; return ret; }; @@ -387,7 +387,7 @@ BufferReader.prototype.read64N = function read64N(force53) { BufferReader.prototype.read64NBE = function read64NBE(force53) { var ret; assert(this.offset + 8 <= this.data.length); - ret = utils.read64NBE(this.data, this.offset, force53); + ret = encoding.read64NBE(this.data, this.offset, force53); this.offset += 8; return ret; }; @@ -471,7 +471,7 @@ BufferReader.prototype.readDoubleBE = function readDoubleBE() { */ BufferReader.prototype.readVarint = function readVarint(big) { - var result = utils.readVarint(this.data, this.offset, big); + var result = encoding.readVarint(this.data, this.offset, big); this.offset += result.size; return result.value; }; @@ -483,7 +483,7 @@ BufferReader.prototype.readVarint = function readVarint(big) { */ BufferReader.prototype.readVarint2 = function readVarint2(big) { - var result = utils.readVarint2(this.data, this.offset, big); + var result = encoding.readVarint2(this.data, this.offset, big); this.offset += result.size; return result.value; }; diff --git a/lib/utils/utils.js b/lib/utils/utils.js index 94d1d14a..b83c7995 100644 --- a/lib/utils/utils.js +++ b/lib/utils/utils.js @@ -118,27 +118,6 @@ utils.concat = function concat(a, b) { return data; }; -/** - * Encode a base58 string. - * @see https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp - * @function - * @param {Buffer} data - * @returns {Base58String} - */ - -utils.toBase58 = base58.toBase58; - -/** - * Decode a base58 string. - * @see https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp - * @function - * @param {Base58String} str - * @returns {Buffer} - * @throws on non-base58 character. - */ - -utils.fromBase58 = base58.fromBase58; - /** * Test whether a string is base58 (note that you * may get a false positive on a hex string). @@ -390,6 +369,23 @@ utils.satoshi = function satoshi(value) { return result; }; +/** + * Max safe integer (53 bits). + * @const {Number} + * @default + */ + +utils.MAX_SAFE_INTEGER = 0x1fffffffffffff; + +/** + * Max 52 bit integer (safe for additions). + * `(MAX_SAFE_INTEGER - 1) / 2` + * @const {Number} + * @default + */ + +utils.MAX_SAFE_ADDITION = 0xfffffffffffff; + /** * Test whether a number is below MAX_SAFE_INTEGER. * @param {Number} value @@ -478,36 +474,6 @@ utils.isFloat = function isFloat(value) { && value !== '-'; }; -/** - * Test and validate a satoshi value (Number). - * @param {Number?} value - * @returns {Boolean} - */ - -utils.isSatoshi = function isSatoshi(value) { - try { - utils.satoshi(value); - return true; - } catch (e) { - return false; - } -}; - -/** - * Test and validate a BTC string. - * @param {String?} value - * @returns {Boolean} - */ - -utils.isBTC = function isBTC(value) { - try { - utils.btc(value); - return true; - } catch (e) { - return false; - } -}; - /** * util.inspect() with 20 levels of depth. * @param {Object|String} obj @@ -595,18 +561,6 @@ utils.error = function error() { process.stderr.write(msg + '\n'); }; -/** - * Sort public keys lexicographically. - * @param {Buffer[]} keys - * @returns {Buffer[]} Sorted keys. - */ - -utils.sortKeys = function sortKeys(keys) { - return keys.slice().sort(function(a, b) { - return utils.cmp(a, b); - }); -}; - /** * Unique-ify an array of strings. * @param {String[]} obj @@ -628,102 +582,6 @@ utils.uniq = function uniq(obj) { return out; }; -/** - * Convert a compact number to a big number. - * Used for `block.bits` -> `target` conversion. - * @param {Number} compact - * @returns {BN} - */ - -utils.fromCompact = function fromCompact(compact) { - var exponent = compact >>> 24; - var negative = (compact >>> 23) & 1; - var mantissa = compact & 0x7fffff; - var num; - - if (compact === 0) - return new BN(0); - - // Logic ported from btcd since - // the bitcoind code is a nightmare. - if (exponent <= 3) { - mantissa >>>= 8 * (3 - exponent); - num = new BN(mantissa); - } else { - num = new BN(mantissa); - num.iushln(8 * (exponent - 3)); - } - - if (negative) - num.ineg(); - - return num; -}; - -/** - * Convert a big number to a compact number. - * Used for `target` -> `block.bits` conversion. - * @param {BN} num - * @returns {Number} - */ - -utils.toCompact = function toCompact(num) { - var mantissa, exponent, compact; - - if (num.cmpn(0) === 0) - return 0; - - exponent = num.byteLength(); - - // Logic ported from btcd since - // the bitcoind code is a nightmare. - if (exponent <= 3) { - mantissa = num.toNumber(); - mantissa <<= 8 * (3 - exponent); - } else { - mantissa = num.ushrn(8 * (exponent - 3)).toNumber(); - } - - if (mantissa & 0x800000) { - mantissa >>= 8; - exponent++; - } - - compact = (exponent << 24) | mantissa; - - if (num.isNeg()) - compact |= 0x800000; - - compact >>>= 0; - - return compact; -}; - -/** - * Test hash against a target. - * @param {Buffer|Hash} hash - * @param {BN|Number} target - Compact number or big number. - * @returns {Boolean} True if hash is less than target. - */ - -utils.testTarget = function testTarget(hash, target) { - if (typeof hash === 'string') - hash = new Buffer(hash, 'hex'); - - if (typeof target === 'number') - target = utils.fromCompact(target); - - if (target.isNeg() || target.cmpn(0) === 0) - return false; - - hash = new BN(hash, 'le'); - - if (hash.cmp(target) > 0) - return false; - - return true; -}; - /** * Get current time in unix time (seconds). * @returns {Number} @@ -770,20 +628,6 @@ utils.time = function time(date) { return new Date(date) / 1000 | 0; }; -/** - * UINT32_MAX - * @const {BN} - */ - -utils.U32 = new BN(0xffffffff); - -/** - * UINT64_MAX - * @const {BN} - */ - -utils.U64 = new BN('ffffffffffffffff', 'hex'); - /** * Create a 64 bit nonce. * @returns {BN} @@ -801,621 +645,6 @@ utils.nonce = function _nonce(buffer) { return new BN(nonce); }; -/** - * Read uint64le. - * @param {Buffer} data - * @param {Number} off - * @returns {BN} - */ - -utils.readU64 = function readU64(data, off) { - var num; - off = off >>> 0; - num = data.slice(off, off + 8); - return new BN(num, 'le'); -}; - -/** - * Read uint64be. - * @param {Buffer} data - * @param {Number} off - * @returns {BN} - */ - -utils.readU64BE = function readU64BE(data, off) { - var num; - off = off >>> 0; - num = data.slice(off, off + 8); - return new BN(num, 'be'); -}; - -/** - * Read int64le. - * @param {Buffer} data - * @param {Number} off - * @returns {BN} - */ - -utils.read64 = function read64(data, off) { - var num; - - off = off >>> 0; - - num = data.slice(off, off + 8); - - if (num[num.length - 1] & 0x80) - return new BN(num, 'le').notn(64).addn(1).neg(); - - return new BN(num, 'le'); -}; - -/** - * Read int64be. - * @param {Buffer} data - * @param {Number} off - * @returns {BN} - */ - -utils.read64BE = function read64BE(data, off) { - var num; - - off = off >>> 0; - - num = data.slice(off, off + 8); - - if (num[0] & 0x80) - return new BN(num, 'be').notn(64).addn(1).neg(); - - return new BN(num, 'be'); -}; - -/** - * Write uint64le. - * @param {BN|Number} value - */ - -utils.writeU64 = function writeU64(dst, num, off) { - return utils.write64(dst, num, off); -}; - -/** - * Write uint64be. - * @param {BN|Number} value - */ - -utils.writeU64BE = function writeU64BE(dst, num, off) { - return utils.write64BE(dst, num, off); -}; - -/** - * Write a javascript number as a uint64le (faster than big numbers). - * @param {Number} value - * @throws on num > MAX_SAFE_INTEGER - */ - -utils.writeU64N = function writeU64N(dst, num, off) { - return utils.write64N(dst, num, off); -}; - -/** - * Write a javascript number as a uint64be (faster than big numbers). - * @param {Number} value - * @throws on num > MAX_SAFE_INTEGER - */ - -utils.writeU64NBE = function writeU64NBE(dst, num, off) { - return utils.write64NBE(dst, num, off); -}; - -/** - * Max safe integer (53 bits). - * @const {Number} - * @default - */ - -utils.MAX_SAFE_INTEGER = 0x1fffffffffffff; - -/** - * Max 52 bit integer (safe for additions). - * `(MAX_SAFE_INTEGER - 1) / 2` - * @const {Number} - * @default - */ - -utils.MAX_SAFE_ADDITION = 0xfffffffffffff; - -/** - * Write a javascript number as an int64le (faster than big numbers). - * @param {Number} value - * @throws on num > MAX_SAFE_INTEGER - */ - -utils.write64N = function write64N(dst, num, off, be) { - var negative, hi, lo; - - assert(typeof num === 'number'); - - off = off >>> 0; - - negative = num < 0; - - if (negative) { - num = -num; - num -= 1; - } - - assert(num <= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1'); - - lo = num % 0x100000000; - hi = (num - lo) / 0x100000000; - - if (negative) { - hi = ~hi >>> 0; - lo = ~lo >>> 0; - } - - if (be) { - dst[off + 0] = (hi >>> 24) & 0xff; - dst[off + 1] = (hi >>> 16) & 0xff; - dst[off + 2] = (hi >>> 8) & 0xff; - dst[off + 3] = (hi >>> 0) & 0xff; - dst[off + 4] = (lo >>> 24) & 0xff; - dst[off + 5] = (lo >>> 16) & 0xff; - dst[off + 6] = (lo >>> 8) & 0xff; - dst[off + 7] = (lo >>> 0) & 0xff; - } else { - dst[off + 0] = (lo >>> 0) & 0xff; - dst[off + 1] = (lo >>> 8) & 0xff; - dst[off + 2] = (lo >>> 16) & 0xff; - dst[off + 3] = (lo >>> 24) & 0xff; - dst[off + 4] = (hi >>> 0) & 0xff; - dst[off + 5] = (hi >>> 8) & 0xff; - dst[off + 6] = (hi >>> 16) & 0xff; - dst[off + 7] = (hi >>> 24) & 0xff; - } - - return off + 8; -}; - -/** - * Write a javascript number as an int64be (faster than big numbers). - * @param {Number} value - * @throws on num > MAX_SAFE_INTEGER - */ - -utils.write64NBE = function write64NBE(dst, num, off) { - return utils.write64N(dst, num, off, true); -}; - -/** - * Read uint64le as a js number. - * @param {Buffer} data - * @param {Number} off - * @param {Boolean} force53 - Read only 53 bits, but maintain the sign. - * @returns {Number} - * @throws on num > MAX_SAFE_INTEGER - */ - -utils.readU64N = function readU64N(data, off, force53, be) { - var hi, lo; - - off = off >>> 0; - - if (be) { - hi = data.readUInt32BE(off, true); - lo = data.readUInt32BE(off + 4, true); - } else { - hi = data.readUInt32LE(off + 4, true); - lo = data.readUInt32LE(off, true); - } - - if (force53) - hi &= 0x1fffff; - - assert((hi & 0xffe00000) === 0, 'Number exceeds 2^53-1'); - - return (hi * 0x100000000) + lo; -}; - -/** - * Read uint64be as a js number. - * @param {Buffer} data - * @param {Number} off - * @param {Boolean} force53 - Read only 53 bits, but maintain the sign. - * @returns {Number} - * @throws on num > MAX_SAFE_INTEGER - */ - -utils.readU64NBE = function readU64NBE(data, off, force53) { - return utils.readU64N(data, off, force53, true); -}; - -/** - * Read int64le as a js number. - * @param {Buffer} data - * @param {Number} off - * @param {Boolean} force53 - Read only 53 bits, but maintain the sign. - * @returns {Number} - * @throws on num > MAX_SAFE_INTEGER - */ - -utils.read64N = function read64N(data, off, force53, be) { - var hi, lo; - - off = off >>> 0; - - if (be) { - hi = data.readUInt32BE(off, true); - lo = data.readUInt32BE(off + 4, true); - } else { - hi = data.readUInt32LE(off + 4, true); - lo = data.readUInt32LE(off, true); - } - - if (hi & 0x80000000) { - hi = ~hi >>> 0; - lo = ~lo >>> 0; - - if (force53) - hi &= 0x1fffff; - - assert((hi & 0xffe00000) === 0, 'Number exceeds 2^53-1'); - - return -(hi * 0x100000000 + lo + 1); - } - - if (force53) - hi &= 0x1fffff; - - assert((hi & 0xffe00000) === 0, 'Number exceeds 2^53-1'); - - return hi * 0x100000000 + lo; -}; - -/** - * Read int64be as a js number. - * @param {Buffer} data - * @param {Number} off - * @param {Boolean} force53 - Read only 53 bits, but maintain the sign. - * @returns {Number} - * @throws on num > MAX_SAFE_INTEGER - */ - -utils.read64NBE = function read64NBE(data, off, force53) { - return utils.read64N(data, off, force53, true); -}; - -/** - * Write int64le. - * @param {Buffer} dst - * @param {BN|Number} num - * @param {Number} off - * @returns {Number} Number of bytes written. - */ - -utils.write64 = function write64(dst, num, off) { - var i; - - if (typeof num === 'number') - return utils.write64N(dst, num, off); - - off = off >>> 0; - - if (num.isNeg()) - num = num.neg().inotn(64).iaddn(1); - - if (num.bitLength() > 64) - num = num.uand(utils.U64); - - num = num.toArray('le', 8); - - for (i = 0; i < num.length; i++) - dst[off++] = num[i]; - - return off; -}; - -/** - * Write int64be. - * @param {Buffer} dst - * @param {BN|Number} num - * @param {Number} off - * @returns {Number} Number of bytes written. - */ - -utils.write64BE = function write64BE(dst, num, off) { - var i; - - if (typeof num === 'number') - return utils.write64NBE(dst, num, off); - - off = off >>> 0; - - if (num.isNeg()) - num = num.neg().inotn(64).iaddn(1); - - if (num.bitLength() > 64) - num = num.uand(utils.U64); - - num = num.toArray('be', 8); - - for (i = 0; i < num.length; i++) - dst[off++] = num[i]; - - return off; -}; - -/** - * Read a varint. - * @param {Buffer} data - * @param {Number} off - * @param {Boolean?} big - Whether to read as a big number. - * @returns {Object} - */ - -utils.readVarint = function readVarint(data, off, big) { - var value, size; - - off = off >>> 0; - - assert(off < data.length); - - switch (data[off]) { - case 0xff: - size = 9; - assert(off + size <= data.length); - if (big) { - value = utils.readU64(data, off + 1); - assert(value.bitLength() > 32); - } else { - value = utils.readU64N(data, off + 1); - assert(value > 0xffffffff); - } - break; - case 0xfe: - size = 5; - assert(off + size <= data.length); - value = data.readUInt32LE(off + 1, true); - assert(value > 0xffff); - if (big) - value = new BN(value); - break; - case 0xfd: - size = 3; - assert(off + size <= data.length); - value = data[off + 1] | (data[off + 2] << 8); - assert(value >= 0xfd); - if (big) - value = new BN(value); - break; - default: - size = 1; - value = data[off]; - if (big) - value = new BN(value); - break; - } - - return { size: size, value: value }; -}; - -/** - * Write a varint. - * @param {Buffer} dst - * @param {BN|Number} num - * @param {Number} off - * @returns {Number} Number of bytes written. - */ - -utils.writeVarint = function writeVarint(dst, num, off) { - off = off >>> 0; - - if (BN.isBN(num)) { - if (num.bitLength() > 32) { - dst[off] = 0xff; - utils.writeU64(dst, num, off + 1); - return off + 9; - } - num = num.toNumber(); - } - - num = +num; - - if (num < 0xfd) { - dst[off] = num & 0xff; - return off + 1; - } - - if (num <= 0xffff) { - dst[off] = 0xfd; - dst[off + 1] = num & 0xff; - dst[off + 2] = (num >>> 8) & 0xff; - return off + 3; - } - - if (num <= 0xffffffff) { - dst[off] = 0xfe; - dst[off + 1] = num & 0xff; - dst[off + 2] = (num >>> 8) & 0xff; - dst[off + 3] = (num >>> 16) & 0xff; - dst[off + 4] = (num >>> 24) & 0xff; - return off + 5; - } - - dst[off] = 0xff; - utils.writeU64N(dst, num, off + 1); - - return off + 9; -}; - -/** - * Calculate size of varint. - * @param {BN|Number} num - * @returns {Number} size - */ - -utils.sizeVarint = function sizeVarint(num) { - if (BN.isBN(num)) { - if (num.bitLength() > 32) - return 9; - num = num.toNumber(); - } - - if (num < 0xfd) - return 1; - - if (num <= 0xffff) - return 3; - - if (num <= 0xffffffff) - return 5; - - return 9; -}; - -/** - * Read a varint (type 2). - * @param {Buffer} data - * @param {Number} off - * @param {Boolean?} big - Whether to read as a big number. - * @returns {Object} - */ - -utils.readVarint2 = function readVarint2(data, off, big) { - var num = 0; - var size = 0; - var bnum, ch; - - off = off >>> 0; - - for (;;) { - assert(off < data.length); - - ch = data[off++]; - size++; - - if (num >= 0x3fffffffffff) { - assert(big, 'Number exceeds 2^53-1.'); - bnum = new BN(num); - num = 0; - } - - if (bnum) { - assert(bnum.bitLength() <= 256); - bnum.iushln(7).iaddn(ch & 0x7f); - if ((ch & 0x80) === 0) - break; - bnum.iaddn(1); - continue; - } - - num = (num * 0x80) + (ch & 0x7f); - if ((ch & 0x80) === 0) - break; - num++; - } - - if (bnum) - return { size: size, value: bnum }; - - if (big) - num = new BN(num); - - return { size: size, value: num }; -}; - -/** - * Write a varint (type 2). - * @param {Buffer} dst - * @param {BN|Number} num - * @param {Number} off - * @returns {Number} Number of bytes written. - */ - -utils.writeVarint2 = function writeVarint2(dst, num, off) { - var tmp = []; - var len = 0; - - if (BN.isBN(num)) { - if (num.bitLength() > 53) { - for (;;) { - tmp[len] = (num.words[0] & 0x7f) | (len ? 0x80 : 0x00); - if (num.cmpn(0x7f) <= 0) - break; - num.iushrn(7).isubn(1); - len++; - } - - assert(off + len <= dst.length); - - do { - dst[off++] = tmp[len]; - } while (len--); - - return off; - } - - num = num.toNumber(); - } - - off = off >>> 0; - num = +num; - - for (;;) { - tmp[len] = (num & 0x7f) | (len ? 0x80 : 0x00); - if (num <= 0x7f) - break; - num = ((num - (num % 0x80)) / 0x80) - 1; - len++; - } - - assert(off + len <= dst.length); - - do { - dst[off++] = tmp[len]; - } while (len--); - - return off; -}; - -/** - * Calculate size of varint (type 2). - * @param {BN|Number} num - * @returns {Number} size - */ - -utils.sizeVarint2 = function sizeVarint2(num) { - var size = 0; - - if (BN.isBN(num)) { - if (num.bitLength() > 53) { - num = num.clone(); - - for (;;) { - size++; - if (num.cmpn(0x7f) <= 0) - break; - num.iushrn(7).isubn(1); - } - - return size; - } - - num = num.toNumber(); - } - - num = +num; - - for (;;) { - size++; - if (num <= 0x7f) - break; - num = ((num - (num % 0x80)) / 0x80) - 1; - } - - return size; -}; - /** * Test whether a buffer is all zeroes. * @param {Buffer} data @@ -1477,32 +706,6 @@ utils.cmp = function cmp(a, b) { if (!Buffer.prototype.compare) utils.cmp = utils.strcmp; -/** - * Memcmp for comparing a needle to a haystack. - * @param {Buffer} target - Haystack. - * @param {Buffer} data - Needle. - * @param {Number} start - Index in haystack to begin the comparison. - * @returns {Number} -1, 1, or 0. - */ - -utils.icmp = function icmp(target, data, start) { - var i, a, b; - - if (target.length - start < data.length) - return -1; - - for (i = 0; i < data.length; i++) { - a = target[i + start]; - b = data[i]; - if (a < b) - return -1; - if (a > b) - return 1; - } - - return 0; -}; - /** * Convert bytes to mb. * @param {Number} size @@ -1510,7 +713,7 @@ utils.icmp = function icmp(target, data, start) { */ utils.mb = function mb(size) { - return size / 1024 / 1024 | 0; + return Math.floor(size / 1024 / 1024); }; /** @@ -1892,23 +1095,6 @@ utils.mkdir = function mkdir(path, dirname) { utils._paths = {}; -/** - * Test whether a string is eligible - * to be used as a name or ID. - * @param {String} key - * @returns {Boolean} - */ - -utils.isName = function isName(key) { - if (typeof key !== 'string') - return false; - - if (!/^[\-\._0-9A-Za-z]+$/.test(key)) - return false; - - return key.length >= 1 && key.length <= 40; -}; - /** * Ensure hidden-class mode for object. * @param {Object} obj @@ -1917,55 +1103,3 @@ utils.isName = function isName(key) { utils.fastProp = function fastProp(obj) { ({ __proto__: obj }); }; - -/** - * Verication result. - * @constructor - */ - -utils.VerifyResult = function VerifyResult() { - this.reason = 'unknown'; - this.score = 0; -}; - -/** - * Serialize number as a u32le. - * @param {Number} num - * @returns {Buffer} - */ - -utils.U32 = function U32(num) { - var data = new Buffer(4); - data.writeUInt32LE(num, 0, true); - return data; -}; - -/** - * Create a lazy loader. - * @param {Function} require - * @param {Object} exports - */ - -utils.lazy = require('./lazy'); - -/* - * Expose other objects. - */ - -lazy = utils.lazy(require, exports); - -lazy('AsyncObject', './async'); // circular - inherits -lazy('bloom', './bloom'); -lazy('errors', './errors'); // circular - inherits/btc -lazy('ip', './ip'); -lazy('Locker', './locker'); // circular - inherits -lazy('LRU', './lru'); -lazy('murmur3', './murmur3'); -lazy('co', './co'); -lazy('uri', './uri'); // circular - satoshi/btc/isNumber -lazy('BufferReader', './reader'); // circular - serialization -lazy('BufferWriter', './writer'); // circular - serialization -lazy('protobuf', './protobuf'); // circular - inherits -lazy('pem', './pem'); -lazy('asn1', './asn1'); -lazy('nfkd', './nfkd'); diff --git a/lib/utils/writer.js b/lib/utils/writer.js index 250e6660..41f9d8b3 100644 --- a/lib/utils/writer.js +++ b/lib/utils/writer.js @@ -7,9 +7,9 @@ 'use strict'; -var utils = require('../utils/utils'); -var crypto = require('../crypto/crypto'); var assert = require('assert'); +var encoding = require('./encoding'); +var crypto = require('../crypto/crypto'); /* * Constants @@ -87,21 +87,21 @@ BufferWriter.prototype.render = function render(keep) { case UI16BE: off = data.writeUInt16BE(item[1], off, true); break; case UI32: off = data.writeUInt32LE(item[1], off, true); break; case UI32BE: off = data.writeUInt32BE(item[1], off, true); break; - case UI64: off = utils.writeU64(data, item[1], off); break; - case UI64BE: off = utils.writeU64BE(data, item[1], off); break; + case UI64: off = encoding.writeU64(data, item[1], off); break; + case UI64BE: off = encoding.writeU64BE(data, item[1], off); break; case I8: off = data.writeInt8(item[1], off, true); break; case I16: off = data.writeInt16LE(item[1], off, true); break; case I16BE: off = data.writeInt16BE(item[1], off, true); break; case I32: off = data.writeInt32LE(item[1], off, true); break; case I32BE: off = data.writeInt32BE(item[1], off, true); break; - case I64: off = utils.write64(data, item[1], off); break; - case I64BE: off = utils.write64BE(data, item[1], off); break; + case I64: off = encoding.write64(data, item[1], off); break; + case I64BE: off = encoding.write64BE(data, item[1], off); break; case FL: off = data.writeFloatLE(item[1], off, true); break; case FLBE: off = data.writeFloatBE(item[1], off, true); break; case DBL: off = data.writeDoubleLE(item[1], off, true); break; case DBLBE: off = data.writeDoubleBE(item[1], off, true); break; - case VARINT: off = utils.writeVarint(data, item[1], off); break; - case VARINT2: off = utils.writeVarint2(data, item[1], off); break; + case VARINT: off = encoding.writeVarint(data, item[1], off); break; + case VARINT2: off = encoding.writeVarint2(data, item[1], off); break; case BYTES: off += item[1].copy(data, off); break; case STR: off += data.write(item[1], off, item[2]); break; case CHECKSUM: @@ -344,7 +344,7 @@ BufferWriter.prototype.writeVarint = function writeVarint(value) { else assert(!value.isNeg()); - this.written += utils.sizeVarint(value); + this.written += encoding.sizeVarint(value); this.data.push([VARINT, value]); }; @@ -359,7 +359,7 @@ BufferWriter.prototype.writeVarint2 = function writeVarint2(value) { else assert(!value.isNeg()); - this.written += utils.sizeVarint2(value); + this.written += encoding.sizeVarint2(value); this.data.push([VARINT2, value]); }; @@ -379,7 +379,7 @@ BufferWriter.prototype.writeBytes = function writeBytes(value) { */ BufferWriter.prototype.writeVarBytes = function writeVarBytes(value) { - this.written += utils.sizeVarint(value.length); + this.written += encoding.sizeVarint(value.length); this.written += value.length; this.data.push([VARINT, value.length]); this.data.push([BYTES, value]); @@ -426,7 +426,7 @@ BufferWriter.prototype.writeVarString = function writeVarString(value, enc) { size = Buffer.byteLength(value, enc); - this.written += utils.sizeVarint(size); + this.written += encoding.sizeVarint(size); this.written += size; this.data.push([VARINT, size]); diff --git a/lib/wallet/account.js b/lib/wallet/account.js index 951e4836..7190904d 100644 --- a/lib/wallet/account.js +++ b/lib/wallet/account.js @@ -12,6 +12,7 @@ var assert = require('assert'); var BufferReader = require('../utils/reader'); var BufferWriter = require('../utils/writer'); var Path = require('./path'); +var common = require('./common'); var Script = require('../script/script'); var WalletKey = require('./walletkey'); var HD = require('../hd/hd'); @@ -107,7 +108,7 @@ Account.prototype.fromOptions = function fromOptions(options) { assert(options, 'Options are required.'); assert(utils.isNumber(options.wid)); - assert(utils.isName(options.id), 'Bad Wallet ID.'); + assert(common.isName(options.id), 'Bad Wallet ID.'); assert(HD.isHD(options.accountKey), 'Account key is required.'); assert(utils.isNumber(options.accountIndex), 'Account index is required.'); @@ -115,7 +116,7 @@ Account.prototype.fromOptions = function fromOptions(options) { this.id = options.id; if (options.name != null) { - assert(utils.isName(options.name), 'Bad account name.'); + assert(common.isName(options.name), 'Bad account name.'); this.name = options.name; } diff --git a/lib/wallet/common.js b/lib/wallet/common.js new file mode 100644 index 00000000..9b6acbed --- /dev/null +++ b/lib/wallet/common.js @@ -0,0 +1,26 @@ +/*! + * common.js - commonly required functions for wallet. + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var common = exports; + +/** + * Test whether a string is eligible + * to be used as a name or ID. + * @param {String} key + * @returns {Boolean} + */ + +common.isName = function isName(key) { + if (typeof key !== 'string') + return false; + + if (!/^[\-\._0-9A-Za-z]+$/.test(key)) + return false; + + return key.length >= 1 && key.length <= 40; +}; diff --git a/lib/wallet/txdb.js b/lib/wallet/txdb.js index b8f7fa10..93a229d8 100644 --- a/lib/wallet/txdb.js +++ b/lib/wallet/txdb.js @@ -14,6 +14,7 @@ var assert = require('assert'); var constants = require('../protocol/constants'); var BufferReader = require('../utils/reader'); var BufferWriter = require('../utils/writer'); +var btcutils = require('../utils/btcutils'); var TX = require('../primitives/tx'); var Coin = require('../primitives/coin'); var Outpoint = require('../primitives/outpoint'); @@ -3191,7 +3192,7 @@ Details.prototype.getFee = function getFee() { */ Details.prototype.getRate = function getRate(fee) { - return TX.getRate(this.vsize, fee); + return btcutils.getRate(this.vsize, fee); }; /** diff --git a/lib/wallet/wallet.js b/lib/wallet/wallet.js index 66e3a505..120b9f09 100644 --- a/lib/wallet/wallet.js +++ b/lib/wallet/wallet.js @@ -7,6 +7,7 @@ 'use strict'; +var assert = require('assert'); var EventEmitter = require('events').EventEmitter; var constants = require('../protocol/constants'); var Network = require('../protocol/network'); @@ -14,13 +15,14 @@ var utils = require('../utils/utils'); var Locker = require('../utils/locker'); var co = require('../utils/co'); var crypto = require('../crypto/crypto'); -var assert = require('assert'); +var btcutils = require('../utils/btcutils'); var BufferReader = require('../utils/reader'); var BufferWriter = require('../utils/writer'); +var base58 = require('../utils/base58'); var TXDB = require('./txdb'); var Path = require('./path'); +var common = require('./common'); var Address = require('../primitives/address'); -var TX = require('../primitives/tx'); var MTX = require('../primitives/mtx'); var WalletKey = require('./walletkey'); var HD = require('../hd/hd'); @@ -124,7 +126,7 @@ Wallet.prototype.fromOptions = function fromOptions(options) { } if (options.id) { - assert(utils.isName(options.id), 'Bad wallet ID.'); + assert(common.isName(options.id), 'Bad wallet ID.'); id = options.id; } @@ -538,7 +540,7 @@ Wallet.prototype.renameAccount = co(function* renameAccount(acct, name) { Wallet.prototype._renameAccount = co(function* _renameAccount(acct, name) { var i, account, old, paths, path; - if (!utils.isName(name)) + if (!common.isName(name)) throw new Error('Bad account name.'); account = yield this.getAccount(acct); @@ -628,7 +630,7 @@ Wallet.prototype.getID = function getID() { p.writeBytes(hash); p.writeChecksum(); - return utils.toBase58(p.render()); + return base58.encode(p.render()); }; /** @@ -1651,7 +1653,7 @@ Wallet.prototype.resend = co(function* resend() { if (txs.length > 0) this.logger.info('Rebroadcasting %d transactions.', txs.length); - txs = TX.sort(txs); + txs = btcutils.sortTX(txs); for (i = 0; i < txs.length; i++) yield this.db.send(txs[i]); diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index 82710abc..713fb708 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -7,16 +7,19 @@ 'use strict'; +var assert = require('assert'); var AsyncObject = require('../utils/async'); var utils = require('../utils/utils'); var co = require('../utils/co'); var Locker = require('../utils/locker'); var LRU = require('../utils/lru'); +var encoding = require('../utils/encoding'); var crypto = require('../crypto/crypto'); -var assert = require('assert'); +var btcutils = require('../utils/btcutils'); var constants = require('../protocol/constants'); var Network = require('../protocol/network'); var Path = require('./path'); +var common = require('./common'); var Wallet = require('./wallet'); var Account = require('./account'); var LDB = require('../db/ldb'); @@ -32,7 +35,7 @@ var BlockMapRecord = records.BlockMapRecord; var BlockMeta = records.BlockMeta; var PathMapRecord = records.PathMapRecord; var OutpointMapRecord = records.OutpointMapRecord; -var U32 = utils.U32; +var U32 = encoding.U32; var DUMMY = new Buffer([0]); /** @@ -694,7 +697,7 @@ WalletDB.prototype._rename = co(function* _rename(wallet, id) { var old = wallet.id; var i, paths, path, batch; - if (!utils.isName(id)) + if (!common.isName(id)) throw new Error('WDB: Bad wallet ID.'); if (yield this.has(id)) @@ -1300,7 +1303,7 @@ WalletDB.prototype.resend = co(function* resend() { txs.push(tx); } - txs = TX.sort(txs); + txs = btcutils.sortTX(txs); for (i = 0; i < txs.length; i++) yield this.send(txs[i]); diff --git a/test/block-test.js b/test/block-test.js index a3bc565e..de45de3d 100644 --- a/test/block-test.js +++ b/test/block-test.js @@ -3,6 +3,7 @@ var BN = require('bn.js'); var bcoin = require('../').set('main'); var utils = bcoin.utils; +var btcutils = require('../lib/utils/btcutils'); var crypto = require('../lib/crypto/crypto'); var constants = bcoin.constants; var network = bcoin.networks; @@ -106,7 +107,7 @@ describe('Block', function() { var reward; for (;;) { - reward = bcoin.block.reward(height); + reward = btcutils.getReward(height, 210000); assert(reward <= constants.COIN * 50); total += reward; if (reward === 0) diff --git a/test/hd-test.js b/test/hd-test.js index afbb10dc..5638f7e0 100644 --- a/test/hd-test.js +++ b/test/hd-test.js @@ -3,6 +3,7 @@ var BN = require('bn.js'); var bcoin = require('../').set('main'); var utils = bcoin.utils; +var base58 = require('../lib/utils/base58'); var crypto = require('../lib/crypto/crypto'); var assert = require('assert'); @@ -159,7 +160,7 @@ describe('HD', function() { }); function ub58(data) { - return utils.fromBase58(data).toString('hex'); + return base58.decode(data).toString('hex'); } function equal(a, b) { diff --git a/test/utils-test.js b/test/utils-test.js index 7061d9f1..26772fd3 100644 --- a/test/utils-test.js +++ b/test/utils-test.js @@ -1,9 +1,12 @@ 'use strict'; -var BN = require('bn.js'); -var bcoin = require('../').set('main'); var assert = require('assert'); -var utils = bcoin.utils; +var BN = require('bn.js'); +var utils = require('../lib/utils/utils'); +var ec = require('../lib/crypto/ec'); +var btcutils = require('../lib/utils/btcutils'); +var base58 = require('../lib/utils/base58'); +var encoding = require('../lib/utils/encoding'); var crypto = require('../lib/crypto/crypto'); var schnorr = require('../lib/crypto/schnorr'); @@ -25,64 +28,63 @@ describe('Utils', function() { it('should encode/decode base58', function() { var arr = new Buffer([ 0, 0, 0, 0xde, 0xad, 0xbe, 0xef ]); - var b = utils.toBase58(arr); + var b = base58.encode(arr); assert.equal(b, '1116h8cQN'); - assert.deepEqual(utils.fromBase58(b), arr); + assert.deepEqual(base58.decode(b), arr); for (var i = 0; i < vectors.length; i++) { var r = new Buffer(vectors[i][0], 'hex'); var b = vectors[i][1]; - assert.equal(utils.toBase58(r), b); - assert.deepEqual(utils.fromBase58(b), r); + assert.equal(base58.encode(r), b); + assert.deepEqual(base58.decode(b), r); } }); - it('should translate bits to target', function() { - var bits = 0x1900896c; + it('should verify proof-of-work', function() { var hash = new Buffer( '672b3f1bb11a994267ea4171069ba0aa4448a840f38e8f340000000000000000', 'hex' ); - var target = utils.fromCompact(bits); - assert(utils.testTarget(hash, target)); + var bits = 0x1900896c; + assert(btcutils.verifyPOW(hash, bits)); }); it('should convert satoshi to btc', function() { - var btc = utils.btc(5460); + var btc = btcutils.btc(5460); assert.equal(btc, '0.0000546'); - btc = utils.btc(54678 * 1000000); + btc = btcutils.btc(54678 * 1000000); assert.equal(btc, '546.78'); - btc = utils.btc(5460 * 10000000); + btc = btcutils.btc(5460 * 10000000); assert.equal(btc, '546.0'); }); it('should convert btc to satoshi', function() { - var btc = utils.satoshi('0.0000546'); + var btc = btcutils.satoshi('0.0000546'); assert(btc === 5460); - btc = utils.satoshi('546.78'); + btc = btcutils.satoshi('546.78'); assert(btc === 54678 * 1000000); - btc = utils.satoshi('546'); + btc = btcutils.satoshi('546'); assert(btc === 5460 * 10000000); - btc = utils.satoshi('546.0'); + btc = btcutils.satoshi('546.0'); assert(btc === 5460 * 10000000); - btc = utils.satoshi('546.0000'); + btc = btcutils.satoshi('546.0000'); assert(btc === 5460 * 10000000); assert.doesNotThrow(function() { - utils.satoshi('546.00000000000000000'); + btcutils.satoshi('546.00000000000000000'); }); assert.throws(function() { - utils.satoshi('546.00000000000000001'); + btcutils.satoshi('546.00000000000000001'); }); assert.doesNotThrow(function() { - utils.satoshi('90071992.54740991'); + btcutils.satoshi('90071992.54740991'); }); assert.doesNotThrow(function() { - utils.satoshi('090071992.547409910'); + btcutils.satoshi('090071992.547409910'); }); assert.throws(function() { - utils.satoshi('90071992.54740992'); + btcutils.satoshi('90071992.54740992'); }); assert.throws(function() { - utils.satoshi('190071992.54740991'); + btcutils.satoshi('190071992.54740991'); }); }); @@ -99,64 +101,64 @@ describe('Utils', function() { var n = 0; var b = new Buffer(1); b.fill(0x00); - utils.writeVarint2(b, 0, 0); - assert.equal(utils.readVarint2(b, 0).value, 0); + encoding.writeVarint2(b, 0, 0); + assert.equal(encoding.readVarint2(b, 0).value, 0); assert.deepEqual(b, [0]); var b = new Buffer(1); b.fill(0x00); - utils.writeVarint2(b, 1, 0); - assert.equal(utils.readVarint2(b, 0).value, 1); + encoding.writeVarint2(b, 1, 0); + assert.equal(encoding.readVarint2(b, 0).value, 1); assert.deepEqual(b, [1]); var b = new Buffer(1); b.fill(0x00); - utils.writeVarint2(b, 127, 0); - assert.equal(utils.readVarint2(b, 0).value, 127); + encoding.writeVarint2(b, 127, 0); + assert.equal(encoding.readVarint2(b, 0).value, 127); assert.deepEqual(b, [0x7f]); var b = new Buffer(2); b.fill(0x00); - utils.writeVarint2(b, 128, 0); - assert.equal(utils.readVarint2(b, 0).value, 128); + encoding.writeVarint2(b, 128, 0); + assert.equal(encoding.readVarint2(b, 0).value, 128); assert.deepEqual(b, [0x80, 0x00]); var b = new Buffer(2); b.fill(0x00); - utils.writeVarint2(b, 255, 0); - assert.equal(utils.readVarint2(b, 0).value, 255); + encoding.writeVarint2(b, 255, 0); + assert.equal(encoding.readVarint2(b, 0).value, 255); assert.deepEqual(b, [0x80, 0x7f]); var b = new Buffer(2); b.fill(0x00); - utils.writeVarint2(b, 16383, 0); - assert.equal(utils.readVarint2(b, 0).value, 16383); + encoding.writeVarint2(b, 16383, 0); + assert.equal(encoding.readVarint2(b, 0).value, 16383); assert.deepEqual(b, [0xfe, 0x7f]); var b = new Buffer(2); b.fill(0x00); - utils.writeVarint2(b, 16384, 0); - assert.equal(utils.readVarint2(b, 0).value, 16384); + encoding.writeVarint2(b, 16384, 0); + assert.equal(encoding.readVarint2(b, 0).value, 16384); assert.deepEqual(b, [0xff, 0x00]); var b = new Buffer(3); b.fill(0x00); - utils.writeVarint2(b, 16511, 0); - assert.equal(utils.readVarint2(b, 0).value, 16511); + encoding.writeVarint2(b, 16511, 0); + assert.equal(encoding.readVarint2(b, 0).value, 16511); // assert.deepEqual(b, [0x80, 0xff, 0x7f]); assert.deepEqual(b, [0xff, 0x7f, 0x00]); var b = new Buffer(3); b.fill(0x00); - utils.writeVarint2(b, 65535, 0); - assert.equal(utils.readVarint2(b, 0).value, 65535); + encoding.writeVarint2(b, 65535, 0); + assert.equal(encoding.readVarint2(b, 0).value, 65535); // assert.deepEqual(b, [0x82, 0xfd, 0x7f]); assert.deepEqual(b, [0x82, 0xfe, 0x7f]); var b = new Buffer(5); b.fill(0x00); - utils.writeVarint2(b, Math.pow(2, 32), 0); - assert.equal(utils.readVarint2(b, 0).value, Math.pow(2, 32)); + encoding.writeVarint2(b, Math.pow(2, 32), 0); + assert.equal(encoding.readVarint2(b, 0).value, Math.pow(2, 32)); assert.deepEqual(b, [0x8e, 0xfe, 0xfe, 0xff, 0x00]); }); @@ -189,11 +191,11 @@ describe('Utils', function() { var buf2 = new Buffer(8); var msg = 'should write+read a ' + num.bitLength() + ' bit unsigned int'; it(msg, function() { - utils.writeU64(buf1, num, 0); - utils.writeU64N(buf2, num.toNumber(), 0); + encoding.writeU64(buf1, num, 0); + encoding.writeU64N(buf2, num.toNumber(), 0); assert.deepEqual(buf1, buf2); - var n1 = utils.readU64(buf1, 0); - var n2 = utils.readU64N(buf2, 0); + var n1 = encoding.readU64(buf1, 0); + var n2 = encoding.readU64N(buf2, 0); assert.equal(n1.toNumber(), n2); }); }); @@ -204,26 +206,26 @@ describe('Utils', function() { var msg = 'should write+read a ' + num.bitLength() + ' bit ' + (num.isNeg() ? 'negative' : 'positive') + ' int'; it(msg, function() { - utils.write64(buf1, num, 0); - utils.write64N(buf2, num.toNumber(), 0); + encoding.write64(buf1, num, 0); + encoding.write64N(buf2, num.toNumber(), 0); assert.deepEqual(buf1, buf2); - var n1 = utils.read64(buf1, 0); - var n2 = utils.read64N(buf2, 0); + var n1 = encoding.read64(buf1, 0); + var n2 = encoding.read64N(buf2, 0); assert.equal(n1.toNumber(), n2); }); var msg = 'should write+read a ' + num.bitLength() + ' bit ' + (num.isNeg() ? 'negative' : 'positive') + ' int as unsigned'; it(msg, function() { - utils.writeU64(buf1, num, 0); - utils.writeU64N(buf2, num.toNumber(), 0); + encoding.writeU64(buf1, num, 0); + encoding.writeU64N(buf2, num.toNumber(), 0); assert.deepEqual(buf1, buf2); - var n1 = utils.readU64(buf1, 0); + var n1 = encoding.readU64(buf1, 0); if (num.isNeg()) { assert.throws(function() { - utils.readU64N(buf2, 0); + encoding.readU64N(buf2, 0); }); } else { - var n2 = utils.readU64N(buf2, 0); + var n2 = encoding.readU64N(buf2, 0); assert.equal(n1.toNumber(), n2); } }); @@ -294,8 +296,8 @@ describe('Utils', function() { }); it('should do proper schnorr', function() { - var key = bcoin.ec.generatePrivateKey(); - var pub = bcoin.ec.publicKeyCreate(key, true); + var key = ec.generatePrivateKey(); + var pub = ec.publicKeyCreate(key, true); var msg = crypto.hash256(new Buffer('foo', 'ascii')); var sig = schnorr.sign(msg, key); assert(schnorr.verify(msg, sig, pub)); diff --git a/test/wallet-test.js b/test/wallet-test.js index 5e273504..d53d23db 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -5,6 +5,7 @@ var bcoin = require('../').set('main'); var constants = bcoin.constants; var network = bcoin.networks; var utils = bcoin.utils; +var encoding = require('../lib/utils/encoding'); var crypto = require('../lib/crypto/crypto'); var assert = require('assert'); var scriptTypes = constants.scriptTypes; @@ -26,8 +27,8 @@ function nextBlock(height) { if (height == null) height = globalHeight++; - hash = crypto.hash256(utils.U32(height)).toString('hex'); - prev = crypto.hash256(utils.U32(height - 1)).toString('hex'); + hash = crypto.hash256(encoding.U32(height)).toString('hex'); + prev = crypto.hash256(encoding.U32(height - 1)).toString('hex'); return { hash: hash,