modules: more refactoring.

This commit is contained in:
Christopher Jeffrey 2016-11-19 05:29:16 -08:00
parent 729aea3b41
commit 0631148705
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
46 changed files with 1582 additions and 1521 deletions

View File

@ -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);

View File

@ -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);
};
/**

View File

@ -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]);
/**

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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;
};

103
lib/hd/common.js Normal file
View File

@ -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;
};

View File

@ -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

View File

@ -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}

View File

@ -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;
};

View File

@ -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));
};
/**

View File

@ -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;

View File

@ -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');

View File

@ -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);
};
/**

View File

@ -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;

View File

@ -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());
};
/**

View File

@ -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);
};
/**

View File

@ -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');

View File

@ -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.

View File

@ -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));
};
/**

View File

@ -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);
};
/**

View File

@ -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

View File

@ -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');

View File

@ -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);
};
/**

View File

@ -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);
};
/*

View File

@ -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;

View File

@ -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.

View File

@ -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
*/

View File

@ -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;

403
lib/utils/btcutils.js Normal file
View File

@ -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;
};

653
lib/utils/encoding.js Normal file
View File

@ -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;
};

View File

@ -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;

11
lib/utils/lazy-browser.js Normal file
View File

@ -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() {};
};

View File

@ -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;
};

View File

@ -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');

View File

@ -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]);

View File

@ -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;
}

26
lib/wallet/common.js Normal file
View File

@ -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;
};

View File

@ -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);
};
/**

View File

@ -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]);

View File

@ -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]);

View File

@ -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)

View File

@ -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) {

View File

@ -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));

View File

@ -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,