From b92839c82acd08f8d206e6c19d238192a1bb6cec Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 14 Jul 2018 00:31:19 -0700 Subject: [PATCH] bcoin: use buffer-map. see #533. --- bench/tx.js | 12 +- bench/walletdb.js | 2 +- bin/node | 2 + browser/src/app.js | 4 +- docs/Examples/wallet.js | 4 +- lib/blockchain/chain.js | 53 ++++----- lib/blockchain/chaindb.js | 81 ++++++-------- lib/blockchain/chainentry.js | 26 ++--- lib/blockchain/layout.js | 22 ++-- lib/coins/coinview.js | 9 +- lib/mempool/fees.js | 5 +- lib/mempool/layout.js | 2 +- lib/mempool/mempool.js | 102 ++++++++--------- lib/mining/common.js | 11 -- lib/mining/cpuminer.js | 2 +- lib/mining/miner.js | 5 +- lib/mining/template.js | 10 +- lib/net/bip152.js | 14 +-- lib/net/packets.js | 8 +- lib/net/peer.js | 13 ++- lib/net/pool.js | 61 +++++----- lib/node/http.js | 10 +- lib/node/rpc.js | 61 +++++----- lib/primitives/abstractblock.js | 20 ++-- lib/primitives/address.js | 21 +--- lib/primitives/block.js | 10 +- lib/primitives/coin.js | 15 +-- lib/primitives/headers.js | 2 +- lib/primitives/input.js | 6 +- lib/primitives/invitem.js | 2 +- lib/primitives/merkleblock.js | 33 +++--- lib/primitives/mtx.js | 7 +- lib/primitives/outpoint.js | 28 ++--- lib/primitives/tx.js | 79 +++++-------- lib/primitives/txmeta.js | 6 +- lib/protocol/consensus.js | 9 -- lib/protocol/errors.js | 2 +- lib/protocol/networks.js | 193 ++++++++++++++++++-------------- lib/script/script.js | 2 +- lib/script/sigcache.js | 25 ++--- lib/utils/util.js | 17 ++- lib/wallet/account.js | 2 +- lib/wallet/client.js | 8 +- lib/wallet/common.js | 19 ++-- lib/wallet/http.js | 12 +- lib/wallet/layout.js | 34 +++--- lib/wallet/masterkey.js | 6 - lib/wallet/path.js | 2 +- lib/wallet/records.js | 16 +-- lib/wallet/rpc.js | 37 +++--- lib/wallet/txdb.js | 23 ++-- lib/wallet/wallet.js | 22 ++-- lib/wallet/walletdb.js | 16 ++- lib/wallet/walletkey.js | 2 +- migrate/chaindb2to3.js | 56 ++++----- migrate/coins/coins.js | 6 +- migrate/coins/coinview.js | 3 +- migrate/walletdb5to6.js | 6 +- migrate/walletdb6to7.js | 8 +- package.json | 11 +- scripts/gen.js | 6 +- test/block-test.js | 44 ++++---- test/chain-test.js | 38 +++++-- test/coins-test.js | 4 +- test/headers-test.js | 8 +- test/http-test.js | 2 +- test/input-test.js | 7 +- test/mempool-test.js | 16 +-- test/node-test.js | 34 ++++-- test/outpoint-test.js | 17 +-- test/script-test.js | 4 +- test/tx-test.js | 29 ++--- test/util/memwallet.js | 25 +++-- test/wallet-test.js | 46 ++++---- 74 files changed, 774 insertions(+), 791 deletions(-) diff --git a/bench/tx.js b/bench/tx.js index 32a975fc8..cd37affa9 100644 --- a/bench/tx.js +++ b/bench/tx.js @@ -84,7 +84,7 @@ const tx10 = common.readTX('tx10'); const end = bench('input hashes'); for (let i = 0; i < 10000; i++) - tx.getInputHashes(null, 'hex'); + tx.getInputHashes(); end(10000); } @@ -94,7 +94,7 @@ const tx10 = common.readTX('tx10'); const end = bench('output hashes'); for (let i = 0; i < 10000; i++) - tx.getOutputHashes('hex'); + tx.getOutputHashes(); end(10000); } @@ -104,7 +104,7 @@ const tx10 = common.readTX('tx10'); const end = bench('all hashes'); for (let i = 0; i < 10000; i++) - tx.getHashes(null, 'hex'); + tx.getHashes(); end(10000); } @@ -176,7 +176,7 @@ const tx2 = mtx.toTX(); const end = bench('input hashes'); for (let i = 0; i < 10000; i++) - tx2.getInputHashes(null, 'hex'); + tx2.getInputHashes(); end(10000); } @@ -185,7 +185,7 @@ const tx2 = mtx.toTX(); const end = bench('output hashes'); for (let i = 0; i < 10000; i++) - tx2.getOutputHashes('hex'); + tx2.getOutputHashes(); end(10000); } @@ -194,7 +194,7 @@ const tx2 = mtx.toTX(); const end = bench('all hashes'); for (let i = 0; i < 10000; i++) - tx2.getHashes(null, 'hex'); + tx2.getHashes(); end(10000); } diff --git a/bench/walletdb.js b/bench/walletdb.js index a399919ba..23a92faad 100644 --- a/bench/walletdb.js +++ b/bench/walletdb.js @@ -7,7 +7,7 @@ const MTX = require('../lib/primitives/mtx'); const Outpoint = require('../lib/primitives/outpoint'); function dummy() { - const hash = random.randomBytes(32).toString('hex'); + const hash = random.randomBytes(32); return new Outpoint(hash, 0); } diff --git a/bin/node b/bin/node index 4e1f9a314..635cd3fdf 100755 --- a/bin/node +++ b/bin/node @@ -2,6 +2,8 @@ 'use strict'; +Buffer.poolSize = 2; + process.title = 'bcoin'; if (process.argv.indexOf('--help') !== -1 diff --git a/browser/src/app.js b/browser/src/app.js index c72caddf3..1d8a9f73c 100644 --- a/browser/src/app.js +++ b/browser/src/app.js @@ -4,6 +4,7 @@ const Logger = require('blgr'); const FullNode = require('../../lib/node/fullnode'); const Amount = require('../../lib/btc/amount'); const plugin = require('../../lib/wallet/plugin'); +const util = require('../../lib/utils/util'); const ProxySocket = require('./proxysocket'); const body = document.getElementsByTagName('body')[0]; @@ -268,8 +269,9 @@ async function _formatWallet(wallet) { wdiv.innerHTML = html; for (const tx of det) { + const hash = util.revHex(tx.hash); const el = create( - `${tx.hash}`); + `${hash}`); wdiv.appendChild(el); setMouseup(el, tx.toJSON()); } diff --git a/docs/Examples/wallet.js b/docs/Examples/wallet.js index e579ebd43..1e6f177d5 100644 --- a/docs/Examples/wallet.js +++ b/docs/Examples/wallet.js @@ -4,7 +4,7 @@ const bcoin = require('../..'); const random = require('bcrypto/lib/random'); function dummy() { - const hash = random.randomBytes(32).toString('hex'); + const hash = random.randomBytes(32); return new bcoin.Outpoint(hash, 0); } @@ -36,7 +36,7 @@ const walletdb = new bcoin.wallet.WalletDB({ await walletdb.addTX(tx); - const wtx = await wallet.getTX(tx.hash('hex')); + const wtx = await wallet.getTX(tx.hash()); console.log('Added transaction'); console.log(wtx); diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index 5a91eb86d..d0af56638 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -13,6 +13,7 @@ const AsyncEmitter = require('bevent'); const Logger = require('blgr'); const {Lock} = require('bmutex'); const LRU = require('blru'); +const {BufferMap} = require('buffer-map'); const Network = require('../protocol/network'); const ChainDB = require('./chaindb'); const common = require('./common'); @@ -52,16 +53,16 @@ class Chain extends AsyncEmitter { this.db = new ChainDB(this.options); - this.locker = new Lock(true); - this.invalid = new LRU(100); + this.locker = new Lock(true, BufferMap); + this.invalid = new LRU(100, null, BufferMap); this.state = new DeploymentState(); this.tip = new ChainEntry(); this.height = -1; this.synced = false; - this.orphanMap = new Map(); - this.orphanPrev = new Map(); + this.orphanMap = new BufferMap(); + this.orphanPrev = new BufferMap(); } /** @@ -327,11 +328,11 @@ class Chain extends AsyncEmitter { assert(typeof flags === 'number'); // Extra sanity check. - if (block.prevBlock !== prev.hash) + if (!block.prevBlock.equals(prev.hash)) throw new VerifyError(block, 'invalid', 'bad-prevblk', 0); // Verify a checkpoint if there is one. - const hash = block.hash('hex'); + const hash = block.hash(); if (!this.verifyCheckpoint(prev, hash)) { throw new VerifyError(block, 'checkpoint', @@ -351,9 +352,9 @@ class Chain extends AsyncEmitter { if (flags & common.flags.VERIFY_BODY) { assert(typeof block.createMerkleRoot === 'function'); - const root = block.createMerkleRoot('hex'); + const root = block.createMerkleRoot(); - if (!root || block.merkleRoot !== root) { + if (!root || !block.merkleRoot.equals(root)) { throw new VerifyError(block, 'invalid', 'bad-txnmrklroot', @@ -661,7 +662,7 @@ class Chain extends AsyncEmitter { // Blocks 91842 and 91880 created duplicate // txids by using the same exact output script // and extraNonce. - if (!hash || block.hash('hex') !== hash) + if (!hash || !block.hash().equals(hash)) throw new VerifyError(block, 'invalid', 'bad-txns-BIP30', 100); } } @@ -821,14 +822,14 @@ class Chain extends AsyncEmitter { */ async findFork(fork, longer) { - while (fork.hash !== longer.hash) { + while (!fork.hash.equals(longer.hash)) { while (longer.height > fork.height) { longer = await this.getPrevious(longer); if (!longer) throw new Error('No previous entry for new tip.'); } - if (fork.hash === longer.hash) + if (fork.hash.equals(longer.hash)) return fork; fork = await this.getPrevious(fork); @@ -858,7 +859,7 @@ class Chain extends AsyncEmitter { // Blocks to disconnect. const disconnect = []; let entry = tip; - while (entry.hash !== fork.hash) { + while (!entry.hash.equals(fork.hash)) { disconnect.push(entry); entry = await this.getPrevious(entry); assert(entry); @@ -867,7 +868,7 @@ class Chain extends AsyncEmitter { // Blocks to connect. const connect = []; entry = competitor; - while (entry.hash !== fork.hash) { + while (!entry.hash.equals(fork.hash)) { connect.push(entry); entry = await this.getPrevious(entry); assert(entry); @@ -915,7 +916,7 @@ class Chain extends AsyncEmitter { // Buffer disconnected blocks. const disconnect = []; let entry = tip; - while (entry.hash !== fork.hash) { + while (!entry.hash.equals(fork.hash)) { disconnect.push(entry); entry = await this.getPrevious(entry); assert(entry); @@ -1044,7 +1045,7 @@ class Chain extends AsyncEmitter { async setBestChain(entry, block, prev, flags) { // A higher fork has arrived. // Time to reorganize the chain. - if (entry.prevBlock !== this.tip.hash) { + if (!entry.prevBlock.equals(this.tip.hash)) { this.logger.warning('WARNING: Reorganizing chain.'); // In spv-mode, we reset the @@ -1303,7 +1304,7 @@ class Chain extends AsyncEmitter { */ async add(block, flags, id) { - const hash = block.hash('hex'); + const hash = block.hash(); const unlock = await this.locker.lock(hash); try { return await this._add(block, flags, id); @@ -1322,7 +1323,7 @@ class Chain extends AsyncEmitter { */ async _add(block, flags, id) { - const hash = block.hash('hex'); + const hash = block.hash(); if (flags == null) flags = common.flags.DEFAULT_FLAGS; @@ -1331,7 +1332,7 @@ class Chain extends AsyncEmitter { id = -1; // Special case for genesis block. - if (hash === this.network.genesis.hash) { + if (hash.equals(this.network.genesis.hash)) { this.logger.debug('Saw genesis block: %s.', block.rhash()); throw new VerifyError(block, 'duplicate', 'duplicate', 0); } @@ -1400,7 +1401,7 @@ class Chain extends AsyncEmitter { const start = util.bench(); // Sanity check. - assert(block.prevBlock === prev.hash); + assert(block.prevBlock.equals(prev.hash)); // Explanation: we try to keep as much data // off the javascript heap as possible. Blocks @@ -1559,7 +1560,7 @@ class Chain extends AsyncEmitter { if (!checkpoint) return true; - if (hash === checkpoint) { + if (hash.equals(checkpoint)) { this.logger.debug('Hit checkpoint block %s (%d).', util.revHex(hash), height); this.emit('checkpoint', hash, height); @@ -1596,8 +1597,8 @@ class Chain extends AsyncEmitter { // The orphan chain forked. if (orphan) { - assert(orphan.block.hash('hex') !== block.hash('hex')); - assert(orphan.block.prevBlock === block.prevBlock); + assert(!orphan.block.hash().equals(block.hash())); + assert(orphan.block.prevBlock.equals(block.prevBlock)); this.logger.warning( 'Removing forked orphan block: %s (%d).', @@ -1625,7 +1626,7 @@ class Chain extends AsyncEmitter { addOrphan(orphan) { const block = orphan.block; - const hash = block.hash('hex'); + const hash = block.hash(); assert(!this.orphanMap.has(hash)); assert(!this.orphanPrev.has(block.prevBlock)); @@ -1646,7 +1647,7 @@ class Chain extends AsyncEmitter { removeOrphan(orphan) { const block = orphan.block; - const hash = block.hash('hex'); + const hash = block.hash(); assert(this.orphanMap.has(hash)); assert(this.orphanPrev.has(block.prevBlock)); @@ -1737,7 +1738,7 @@ class Chain extends AsyncEmitter { */ hasInvalid(block) { - const hash = block.hash('hex'); + const hash = block.hash(); if (this.invalid.has(hash)) return true; @@ -2152,7 +2153,7 @@ class Chain extends AsyncEmitter { if (start == null) start = this.tip.hash; - assert(typeof start === 'string'); + assert(Buffer.isBuffer(start)); let entry = await this.getEntry(start); diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index 833255f3a..88026ede0 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -11,6 +11,7 @@ const assert = require('assert'); const bdb = require('bdb'); const bio = require('bufio'); const LRU = require('blru'); +const {BufferMap, BufferSet} = require('buffer-map'); const Amount = require('../btc/amount'); const Network = require('../protocol/network'); const CoinView = require('../coins/coinview'); @@ -47,8 +48,8 @@ class ChainDB { this.pending = null; this.current = null; - this.coinCache = new LRU(this.options.coinCache, getSize); - this.cacheHash = new LRU(this.options.entryCache); + this.coinCache = new LRU(this.options.coinCache, getSize, BufferMap); + this.cacheHash = new LRU(this.options.entryCache, null, BufferMap); this.cacheHeight = new LRU(this.options.entryCache); } @@ -224,7 +225,7 @@ class ChainDB { if (typeof block === 'number') return this.cacheHeight.has(block); - assert(typeof block === 'string'); + assert(Buffer.isBuffer(block)); return this.cacheHash.has(block); } @@ -238,7 +239,7 @@ class ChainDB { if (typeof block === 'number') return this.cacheHeight.get(block); - assert(typeof block === 'string'); + assert(Buffer.isBuffer(block)); return this.cacheHash.get(block); } @@ -253,9 +254,9 @@ class ChainDB { if (typeof hash === 'number') return hash; - assert(typeof hash === 'string'); + assert(Buffer.isBuffer(hash)); - if (hash === consensus.NULL_HASH) + if (hash.equals(consensus.ZERO_HASH)) return -1; const entry = this.cacheHash.get(hash); @@ -279,7 +280,7 @@ class ChainDB { */ async getHash(height) { - if (typeof height === 'string') + if (Buffer.isBuffer(height)) return height; assert(typeof height === 'number'); @@ -292,12 +293,7 @@ class ChainDB { if (entry) return entry.hash; - const hash = await this.db.get(layout.H.build(height)); - - if (!hash) - return null; - - return hash.toString('hex'); + return this.db.get(layout.H.build(height)); } /** @@ -317,13 +313,11 @@ class ChainDB { if (cache) return cache; - const data = await this.db.get(layout.H.build(height)); + const hash = await this.db.get(layout.H.build(height)); - if (!data) + if (!hash) return null; - const hash = data.toString('hex'); - const state = this.state; const entry = await this.getEntryByHash(hash); @@ -346,9 +340,9 @@ class ChainDB { */ async getEntryByHash(hash) { - assert(typeof hash === 'string'); + assert(Buffer.isBuffer(hash)); - if (hash === consensus.NULL_HASH) + if (hash.equals(consensus.ZERO_HASH)) return null; const cache = this.cacheHash.get(hash); @@ -473,7 +467,7 @@ class ChainDB { return null; // Not on main chain. - if (next.prevBlock !== entry.hash) + if (!next.prevBlock.equals(entry.hash)) return null; return next; @@ -810,12 +804,7 @@ class ChainDB { */ async getNextHash(hash) { - const data = await this.db.get(layout.n.build(hash)); - - if (!data) - return null; - - return data.toString('hex'); + return this.db.get(layout.n.build(hash)); } /** @@ -825,15 +814,15 @@ class ChainDB { */ async isMainHash(hash) { - assert(typeof hash === 'string'); + assert(Buffer.isBuffer(hash)); - if (hash === consensus.NULL_HASH) + if (hash.equals(consensus.ZERO_HASH)) return false; - if (hash === this.network.genesis.hash) + if (hash.equals(this.network.genesis.hash)) return true; - if (hash === this.state.tip) + if (hash.equals(this.state.tip)) return true; const cacheHash = this.cacheHash.get(hash); @@ -841,7 +830,7 @@ class ChainDB { if (cacheHash) { const cacheHeight = this.cacheHeight.get(cacheHash.height); if (cacheHeight) - return cacheHeight.hash === hash; + return cacheHeight.hash.equals(hash); } if (await this.getNextHash(hash)) @@ -860,13 +849,13 @@ class ChainDB { if (entry.isGenesis()) return true; - if (entry.hash === this.state.tip) + if (entry.hash.equals(this.state.tip)) return true; const cache = this.getCache(entry.height); if (cache) - return entry.hash === cache.hash; + return entry.hash.equals(cache.hash); if (await this.getNextHash(entry.hash)) return true; @@ -893,8 +882,7 @@ class ChainDB { return this.db.values({ gte: layout.H.min(start), - lte: layout.H.max(end), - parse: data => data.toString('hex') + lte: layout.H.max(end) }); } @@ -1203,7 +1191,7 @@ class ChainDB { if (!this.options.indexTX || !this.options.indexAddress) return []; - const hashes = Object.create(null); + const set = new BufferSet(); for (const addr of addrs) { const hash = Address.getHash(addr); @@ -1213,12 +1201,12 @@ class ChainDB { lte: layout.T.max(hash), parse: (key) => { const [, txid] = layout.T.parse(key); - hashes[txid] = true; + set.add(txid); } }); } - return Object.keys(hashes); + return set.toArray(); } /** @@ -1576,7 +1564,7 @@ class ChainDB { this.start(); // Stop once we hit our target tip. - if (tip.hash === entry.hash) { + if (tip.hash.equals(entry.hash)) { this.put(layout.R.build(), this.pending.commit(tip.hash)); await this.commit(); break; @@ -1735,14 +1723,17 @@ class ChainDB { for (const [index, coin] of coins.outputs) { if (coin.spent) { this.del(layout.c.build(hash, index)); - this.coinCache.unpush(hash + index); + if (this.coinCache.capacity > 0) + this.coinCache.unpush(Outpoint.toKey(hash, index)); continue; } const raw = coin.toRaw(); this.put(layout.c.build(hash, index), raw); - this.coinCache.push(hash + index, raw); + + if (this.coinCache.capacity > 0) + this.coinCache.push(Outpoint.toKey(hash, index), raw); } } } @@ -2130,7 +2121,7 @@ class ChainState { */ constructor() { - this.tip = consensus.NULL_HASH; + this.tip = consensus.ZERO_HASH; this.tx = 0; this.coin = 0; this.value = 0; @@ -2169,8 +2160,6 @@ class ChainState { } commit(hash) { - if (typeof hash !== 'string') - hash = hash.toString('hex'); this.tip = hash; this.committed = true; return this.toRaw(); @@ -2188,7 +2177,7 @@ class ChainState { static fromRaw(data) { const state = new ChainState(); const br = bio.read(data); - state.tip = br.readHash('hex'); + state.tip = br.readHash(); state.tx = br.readU64(); state.coin = br.readU64(); state.value = br.readU64(); @@ -2220,7 +2209,7 @@ class StateCache { for (const {bit} of this.network.deploys) { assert(!this.bits[bit]); - this.bits[bit] = new Map(); + this.bits[bit] = new BufferMap(); } } diff --git a/lib/blockchain/chainentry.js b/lib/blockchain/chainentry.js index 0dae696d6..88d636d0e 100644 --- a/lib/blockchain/chainentry.js +++ b/lib/blockchain/chainentry.js @@ -50,10 +50,10 @@ class ChainEntry { */ constructor(options) { - this.hash = consensus.NULL_HASH; + this.hash = consensus.ZERO_HASH; this.version = 1; - this.prevBlock = consensus.NULL_HASH; - this.merkleRoot = consensus.NULL_HASH; + this.prevBlock = consensus.ZERO_HASH; + this.merkleRoot = consensus.ZERO_HASH; this.time = 0; this.bits = 0; this.nonce = 0; @@ -72,10 +72,10 @@ class ChainEntry { fromOptions(options) { assert(options, 'Block data is required.'); - assert(typeof options.hash === 'string'); + assert(Buffer.isBuffer(options.hash)); assert((options.version >>> 0) === options.version); - assert(typeof options.prevBlock === 'string'); - assert(typeof options.merkleRoot === 'string'); + assert(Buffer.isBuffer(options.prevBlock)); + assert(Buffer.isBuffer(options.merkleRoot)); assert((options.time >>> 0) === options.time); assert((options.bits >>> 0) === options.bits); assert((options.nonce >>> 0) === options.nonce); @@ -188,7 +188,7 @@ class ChainEntry { */ fromBlock(block, prev) { - this.hash = block.hash('hex'); + this.hash = block.hash(); this.version = block.version; this.prevBlock = block.prevBlock; this.merkleRoot = block.merkleRoot; @@ -243,10 +243,10 @@ class ChainEntry { br.seek(-80); - this.hash = hash.toString('hex'); + this.hash = hash; this.version = br.readU32(); - this.prevBlock = br.readHash('hex'); - this.merkleRoot = br.readHash('hex'); + this.prevBlock = br.readHash(); + this.merkleRoot = br.readHash(); this.time = br.readU32(); this.bits = br.readU32(); this.nonce = br.readU32(); @@ -303,10 +303,10 @@ class ChainEntry { assert((json.nonce >>> 0) === json.nonce); assert(typeof json.chainwork === 'string'); - this.hash = util.revHex(json.hash); + this.hash = util.fromRev(json.hash); this.version = json.version; - this.prevBlock = util.revHex(json.prevBlock); - this.merkleRoot = util.revHex(json.merkleRoot); + this.prevBlock = util.fromRev(json.prevBlock); + this.merkleRoot = util.fromRev(json.merkleRoot); this.time = json.time; this.bits = json.bits; this.nonce = json.nonce; diff --git a/lib/blockchain/layout.js b/lib/blockchain/layout.js index 1bc801d57..3a65c0fb9 100644 --- a/lib/blockchain/layout.js +++ b/lib/blockchain/layout.js @@ -33,18 +33,18 @@ const layout = { O: bdb.key('O'), R: bdb.key('R'), D: bdb.key('D'), - e: bdb.key('e', ['hash256']), - h: bdb.key('h', ['hash256']), + e: bdb.key('e', ['bhash256']), + h: bdb.key('h', ['bhash256']), H: bdb.key('H', ['uint32']), - n: bdb.key('n', ['hash256']), - p: bdb.key('p', ['hash256']), - b: bdb.key('b', ['hash256']), - t: bdb.key('t', ['hash256']), - c: bdb.key('c', ['hash256', 'uint32']), - u: bdb.key('u', ['hash256']), - v: bdb.key('v', ['uint8', 'hash256']), - T: bdb.key('T', ['hash', 'hash256']), - C: bdb.key('C', ['hash', 'hash256', 'uint32']) + n: bdb.key('n', ['bhash256']), + p: bdb.key('p', ['bhash256']), + b: bdb.key('b', ['bhash256']), + t: bdb.key('t', ['bhash256']), + c: bdb.key('c', ['bhash256', 'uint32']), + u: bdb.key('u', ['bhash256']), + v: bdb.key('v', ['uint8', 'bhash256']), + T: bdb.key('T', ['bhash', 'bhash256']), + C: bdb.key('C', ['bhash', 'bhash256', 'uint32']) }; /* diff --git a/lib/coins/coinview.js b/lib/coins/coinview.js index 83a8cf1ab..c82097c94 100644 --- a/lib/coins/coinview.js +++ b/lib/coins/coinview.js @@ -6,6 +6,7 @@ 'use strict'; +const {BufferMap} = require('buffer-map'); const Coins = require('./coins'); const UndoCoins = require('./undocoins'); const CoinEntry = require('./coinentry'); @@ -26,7 +27,7 @@ class CoinView { */ constructor() { - this.map = new Map(); + this.map = new BufferMap(); this.undo = new UndoCoins(); } @@ -102,7 +103,7 @@ class CoinView { */ addTX(tx, height) { - const hash = tx.hash('hex'); + const hash = tx.hash(); const coins = Coins.fromTX(tx, height); return this.add(hash, coins); } @@ -115,7 +116,7 @@ class CoinView { */ removeTX(tx, height) { - const hash = tx.hash('hex'); + const hash = tx.hash(); const coins = Coins.fromTX(tx, height); for (const coin of coins.outputs.values()) @@ -170,7 +171,7 @@ class CoinView { */ addIndex(tx, index, height) { - const hash = tx.hash('hex'); + const hash = tx.hash(); const coins = this.ensure(hash); return coins.addIndex(tx, index, height); } diff --git a/lib/mempool/fees.js b/lib/mempool/fees.js index 3f65d3724..d458f1b75 100644 --- a/lib/mempool/fees.js +++ b/lib/mempool/fees.js @@ -11,6 +11,7 @@ const assert = require('assert'); const bio = require('bufio'); const Logger = require('blgr'); +const {BufferMap} = require('buffer-map'); const util = require('../utils/util'); const binary = require('../utils/binary'); const consensus = require('../protocol/consensus'); @@ -420,7 +421,7 @@ class PolicyEstimator { this.priUnlikely = 0; this.priLikely = INF_PRIORITY; - this.map = new Map(); + this.map = new BufferMap(); this.bestHeight = 0; if (policy.MIN_RELAY >= MIN_FEERATE) @@ -536,7 +537,7 @@ class PolicyEstimator { processTX(entry, current) { const height = entry.height; - const hash = entry.hash('hex'); + const hash = entry.hash(); if (this.map.has(hash)) { this.logger.debug('Mempool tx %s already tracked.', entry.txid()); diff --git a/lib/mempool/layout.js b/lib/mempool/layout.js index 81fddc34f..4982c9ea0 100644 --- a/lib/mempool/layout.js +++ b/lib/mempool/layout.js @@ -21,7 +21,7 @@ const layout = { v: bdb.key('v'), R: bdb.key('R'), F: bdb.key('F'), - e: bdb.key('e', ['hash256']) + e: bdb.key('e', ['bhash256']) }; /* diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 500cd8b54..1c98e3f93 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -12,6 +12,7 @@ const EventEmitter = require('events'); const bdb = require('bdb'); const {RollingFilter} = require('bfilter'); const Heap = require('bheep'); +const {BufferMap, BufferSet} = require('buffer-map'); const common = require('../blockchain/common'); const consensus = require('../protocol/consensus'); const policy = require('../protocol/policy'); @@ -66,10 +67,10 @@ class Mempool extends EventEmitter { this.lastFlush = 0; this.tip = this.network.genesis.hash; - this.waiting = new Map(); - this.orphans = new Map(); - this.map = new Map(); - this.spents = new Map(); + this.waiting = new BufferMap(); + this.orphans = new BufferMap(); + this.map = new BufferMap(); + this.spents = new BufferMap(); this.rejects = new RollingFilter(120000, 0.000001); this.coinIndex = new CoinIndex(); @@ -174,7 +175,7 @@ class Mempool extends EventEmitter { for (let i = txs.length - 1; i >= 1; i--) { const tx = txs[i]; - const hash = tx.hash('hex'); + const hash = tx.hash(); const entry = this.getEntry(hash); if (!entry) { @@ -253,7 +254,7 @@ class Mempool extends EventEmitter { for (let i = 1; i < txs.length; i++) { const tx = txs[i]; - const hash = tx.hash('hex'); + const hash = tx.hash(); if (this.hasEntry(hash)) continue; @@ -433,7 +434,7 @@ class Mempool extends EventEmitter { while (queue.size() > 0) { const entry = queue.shift(); - const hash = entry.hash('hex'); + const hash = entry.hash(); assert(this.hasEntry(hash)); @@ -558,7 +559,7 @@ class Mempool extends EventEmitter { const out = []; for (const addr of addrs) { - const hash = Address.getHash(addr, 'hex'); + const hash = Address.getHash(addr); const coins = this.coinIndex.get(hash); for (const coin of coins) @@ -581,7 +582,7 @@ class Mempool extends EventEmitter { const out = []; for (const addr of addrs) { - const hash = Address.getHash(addr, 'hex'); + const hash = Address.getHash(addr); const txs = this.txIndex.get(hash); for (const tx of txs) @@ -604,7 +605,7 @@ class Mempool extends EventEmitter { const out = []; for (const addr of addrs) { - const hash = Address.getHash(addr, 'hex'); + const hash = Address.getHash(addr); const txs = this.txIndex.getMeta(hash); for (const tx of txs) @@ -685,7 +686,7 @@ class Mempool extends EventEmitter { */ hasReject(hash) { - return this.rejects.test(hash, 'hex'); + return this.rejects.test(hash); } /** @@ -699,7 +700,7 @@ class Mempool extends EventEmitter { */ async addTX(tx, id) { - const hash = tx.hash('hex'); + const hash = tx.hash(); const unlock = await this.locker.lock(hash); try { return await this._addTX(tx, id); @@ -754,7 +755,7 @@ class Mempool extends EventEmitter { const lockFlags = common.lockFlags.STANDARD_LOCKTIME_FLAGS; const height = this.chain.height; - const hash = tx.hash('hex'); + const hash = tx.hash(); // Basic sanity checks. // This is important because it ensures @@ -1112,14 +1113,14 @@ class Mempool extends EventEmitter { removeEntry(entry) { const tx = entry.tx; - const hash = tx.hash('hex'); + const hash = tx.hash(); this.untrackEntry(entry); if (this.fees) this.fees.removeTX(hash); - this.cache.remove(tx.hash()); + this.cache.remove(hash); this.emit('remove entry', entry); } @@ -1144,7 +1145,7 @@ class Mempool extends EventEmitter { removeSpenders(entry) { const tx = entry.tx; - const hash = tx.hash('hex'); + const hash = tx.hash(); for (let i = 0; i < tx.outputs.length; i++) { const spender = this.getSpent(hash, i); @@ -1165,7 +1166,7 @@ class Mempool extends EventEmitter { */ countAncestors(entry) { - return this._countAncestors(entry, new Set(), entry, nop); + return this._countAncestors(entry, new BufferSet(), entry, nop); } /** @@ -1178,7 +1179,7 @@ class Mempool extends EventEmitter { */ updateAncestors(entry, map) { - return this._countAncestors(entry, new Set(), entry, map); + return this._countAncestors(entry, new BufferSet(), entry, map); } /** @@ -1228,7 +1229,7 @@ class Mempool extends EventEmitter { */ countDescendants(entry) { - return this._countDescendants(entry, new Set()); + return this._countDescendants(entry, new BufferSet()); } /** @@ -1242,7 +1243,7 @@ class Mempool extends EventEmitter { _countDescendants(entry, set) { const tx = entry.tx; - const hash = tx.hash('hex'); + const hash = tx.hash(); for (let i = 0; i < tx.outputs.length; i++) { const child = this.getSpent(hash, i); @@ -1250,7 +1251,7 @@ class Mempool extends EventEmitter { if (!child) continue; - const next = child.hash('hex'); + const next = child.hash(); if (set.has(next)) continue; @@ -1270,7 +1271,7 @@ class Mempool extends EventEmitter { */ getAncestors(entry) { - return this._getAncestors(entry, [], new Set()); + return this._getAncestors(entry, [], new BufferSet()); } /** @@ -1311,7 +1312,7 @@ class Mempool extends EventEmitter { */ getDescendants(entry) { - return this._getDescendants(entry, [], new Set()); + return this._getDescendants(entry, [], new BufferSet()); } /** @@ -1324,7 +1325,7 @@ class Mempool extends EventEmitter { _getDescendants(entry, entries, set) { const tx = entry.tx; - const hash = tx.hash('hex'); + const hash = tx.hash(); for (let i = 0; i < tx.outputs.length; i++) { const child = this.getSpent(hash, i); @@ -1332,7 +1333,7 @@ class Mempool extends EventEmitter { if (!child) continue; - const next = child.hash('hex'); + const next = child.hash(); if (set.has(next)) continue; @@ -1441,7 +1442,7 @@ class Mempool extends EventEmitter { */ maybeOrphan(tx, view, id) { - const hashes = new Set(); + const hashes = new BufferSet(); const missing = []; for (const {prevout} of tx.inputs) { @@ -1484,11 +1485,11 @@ class Mempool extends EventEmitter { this.limitOrphans(); - const hash = tx.hash('hex'); + const hash = tx.hash(); for (const prev of hashes.keys()) { if (!this.waiting.has(prev)) - this.waiting.set(prev, new Set()); + this.waiting.set(prev, new BufferSet()); this.waiting.get(prev).add(hash); @@ -1551,7 +1552,7 @@ class Mempool extends EventEmitter { this.logger.debug( 'Transaction %s was double-orphaned in mempool.', tx.txid()); - this.removeOrphan(tx.hash('hex')); + this.removeOrphan(tx.hash()); continue; } @@ -1569,7 +1570,7 @@ class Mempool extends EventEmitter { */ resolveOrphans(parent) { - const hash = parent.hash('hex'); + const hash = parent.hash(); const set = this.waiting.get(hash); if (!set) @@ -1779,7 +1780,7 @@ class Mempool extends EventEmitter { trackEntry(entry, view) { const tx = entry.tx; - const hash = tx.hash('hex'); + const hash = tx.hash(); assert(!this.map.has(hash)); this.map.set(hash, entry); @@ -1805,7 +1806,7 @@ class Mempool extends EventEmitter { untrackEntry(entry) { const tx = entry.tx; - const hash = tx.hash('hex'); + const hash = tx.hash(); assert(this.map.has(hash)); this.map.delete(hash); @@ -1852,7 +1853,7 @@ class Mempool extends EventEmitter { unindexEntry(entry) { const tx = entry.tx; - const hash = tx.hash('hex'); + const hash = tx.hash(); this.txIndex.remove(hash); @@ -2148,10 +2149,10 @@ class TXIndex { constructor() { // Map of addr->entries. - this.index = new Map(); + this.index = new BufferMap(); // Map of txid->addrs. - this.map = new Map(); + this.map = new BufferMap(); } reset() { @@ -2192,8 +2193,8 @@ class TXIndex { insert(entry, view) { const tx = entry.tx; - const hash = tx.hash('hex'); - const addrs = tx.getHashes(view, 'hex'); + const hash = tx.hash(); + const addrs = tx.getHashes(view); if (addrs.length === 0) return; @@ -2202,7 +2203,7 @@ class TXIndex { let items = this.index.get(addr); if (!items) { - items = new Map(); + items = new BufferMap(); this.index.set(addr, items); } @@ -2248,10 +2249,10 @@ class CoinIndex { constructor() { // Map of addr->coins. - this.index = new Map(); + this.index = new BufferMap(); // Map of outpoint->addr. - this.map = new Map(); + this.map = new BufferMap(); } reset() { @@ -2275,8 +2276,8 @@ class CoinIndex { insert(tx, index) { const output = tx.outputs[index]; - const hash = tx.hash('hex'); - const addr = output.getHash('hex'); + const hash = tx.hash(); + const addr = output.getHash(); if (!addr) return; @@ -2284,7 +2285,7 @@ class CoinIndex { let items = this.index.get(addr); if (!items) { - items = new Map(); + items = new BufferMap(); this.index.set(addr, items); } @@ -2397,12 +2398,7 @@ class MempoolCache { } async getTip() { - const hash = await this.db.get(layout.R.build()); - - if (!hash) - return null; - - return hash.toString('hex'); + return this.db.get(layout.R.build()); } async getFees() { @@ -2478,7 +2474,7 @@ class MempoolCache { if (!this.db) return; - this.batch.put(layout.R.build(), Buffer.from(tip, 'hex')); + this.batch.put(layout.R.build(), tip); } writeFees(fees) { @@ -2505,7 +2501,7 @@ class MempoolCache { async init(hash) { const batch = this.db.batch(); batch.put(layout.v.build(), fromU32(MempoolCache.VERSION)); - batch.put(layout.R.build(), Buffer.from(hash, 'hex')); + batch.put(layout.R.build(), hash); await batch.write(); } @@ -2536,7 +2532,7 @@ class MempoolCache { tip = await this.getTip(); - if (tip !== this.chain.tip.hash) { + if (!tip || !tip.equals(this.chain.tip.hash)) { this.logger.warning( 'Mempool tip not consistent with chain tip (%s != %s)!', util.revHex(tip), @@ -2557,7 +2553,7 @@ class MempoolCache { batch.del(key); batch.put(layout.v.build(), fromU32(MempoolCache.VERSION)); - batch.put(layout.R.build(), Buffer.from(this.chain.tip.hash, 'hex')); + batch.put(layout.R.build(), this.chain.tip.hash); batch.del(layout.F.build()); await batch.write(); diff --git a/lib/mining/common.js b/lib/mining/common.js index 00f39e750..526fc3592 100644 --- a/lib/mining/common.js +++ b/lib/mining/common.js @@ -41,17 +41,6 @@ common.swap32 = function swap32(data) { return data; }; -/** - * Swap 32 bit endianness of uint256 (hex). - * @param {String} str - * @returns {String} - */ - -common.swap32hex = function swap32hex(str) { - const data = Buffer.from(str, 'hex'); - return common.swap32(data).toString('hex'); -}; - /** * Compare two uint256le's. * @param {Buffer} a diff --git a/lib/mining/cpuminer.js b/lib/mining/cpuminer.js index 98171428e..7a4f92f08 100644 --- a/lib/mining/cpuminer.js +++ b/lib/mining/cpuminer.js @@ -54,7 +54,7 @@ class CPUMiner extends EventEmitter { if (!this.job) return; - if (this.job.attempt.prevBlock === tip.prevBlock) + if (this.job.attempt.prevBlock.equals(tip.prevBlock)) this.job.destroy(); }); } diff --git a/lib/mining/miner.js b/lib/mining/miner.js index 7e01696b9..fcf03ddf0 100644 --- a/lib/mining/miner.js +++ b/lib/mining/miner.js @@ -10,6 +10,7 @@ const assert = require('assert'); const EventEmitter = require('events'); const Heap = require('bheep'); +const {BufferMap} = require('buffer-map'); const Amount = require('../btc/amount'); const Address = require('../primitives/address'); const BlockTemplate = require('./template'); @@ -250,10 +251,10 @@ class Miner extends EventEmitter { return; } - assert(this.mempool.tip === this.chain.tip.hash, + assert(this.mempool.tip.equals(this.chain.tip.hash), 'Mempool/chain tip mismatch! Unsafe to create block.'); - const depMap = new Map(); + const depMap = new BufferMap(); const queue = new Heap(cmpRate); let priority = this.options.priorityWeight > 0; diff --git a/lib/mining/template.js b/lib/mining/template.js index bb7815653..eae2f885a 100644 --- a/lib/mining/template.js +++ b/lib/mining/template.js @@ -42,7 +42,7 @@ class BlockTemplate { */ constructor(options) { - this.prevBlock = consensus.NULL_HASH; + this.prevBlock = consensus.ZERO_HASH; this.version = 1; this.height = 0; this.time = 0; @@ -79,7 +79,7 @@ class BlockTemplate { assert(options); if (options.prevBlock != null) { - assert(typeof options.prevBlock === 'string'); + assert(Buffer.isBuffer(options.prevBlock)); this.prevBlock = options.prevBlock; } @@ -467,7 +467,7 @@ class BlockTemplate { block.version = this.version; block.prevBlock = this.prevBlock; - block.merkleRoot = root.toString('hex'); + block.merkleRoot = root; block.time = time; block.bits = this.bits; block.nonce = nonce; @@ -608,7 +608,7 @@ class BlockEntry { constructor(tx) { this.tx = tx; - this.hash = tx.hash('hex'); + this.hash = tx.hash(); this.fee = 0; this.rate = 0; this.priority = 0; @@ -682,7 +682,7 @@ class BlockProof { } rhash() { - return util.revHex(this.hash.toString('hex')); + return util.revHex(this.hash); } verify(target) { diff --git a/lib/net/bip152.js b/lib/net/bip152.js index 904e6466f..aec7bbbb8 100644 --- a/lib/net/bip152.js +++ b/lib/net/bip152.js @@ -366,11 +366,7 @@ class CompactBlock extends AbstractBlock { */ sid(hash) { - if (typeof hash === 'string') - hash = Buffer.from(hash, 'hex'); - const [hi, lo] = siphash(hash, this.sipKey); - return (hi & 0xffff) * 0x100000000 + (lo >>> 0); } @@ -554,7 +550,7 @@ class TXRequest { */ constructor(options) { - this.hash = consensus.NULL_HASH; + this.hash = consensus.ZERO_HASH; this.indexes = []; if (options) @@ -595,7 +591,7 @@ class TXRequest { */ fromCompact(block) { - this.hash = block.hash('hex'); + this.hash = block.hash(); for (let i = 0; i < block.available.length; i++) { if (!block.available[i]) @@ -623,7 +619,7 @@ class TXRequest { */ fromReader(br) { - this.hash = br.readHash('hex'); + this.hash = br.readHash(); const count = br.readVarint(); @@ -749,7 +745,7 @@ class TXResponse { */ constructor(options) { - this.hash = consensus.NULL_HASH; + this.hash = consensus.ZERO_HASH; this.txs = []; if (options) @@ -790,7 +786,7 @@ class TXResponse { */ fromReader(br) { - this.hash = br.readHash('hex'); + this.hash = br.readHash(); const count = br.readVarint(); diff --git a/lib/net/packets.js b/lib/net/packets.js index 535b398d0..c75bbc17a 100644 --- a/lib/net/packets.js +++ b/lib/net/packets.js @@ -1039,11 +1039,11 @@ class GetBlocksPacket extends Packet { assert(count <= common.MAX_INV, 'Too many block hashes.'); for (let i = 0; i < count; i++) - this.locator.push(br.readHash('hex')); + this.locator.push(br.readHash()); - this.stop = br.readHash('hex'); + this.stop = br.readHash(); - if (this.stop === consensus.NULL_HASH) + if (this.stop.equals(consensus.ZERO_HASH)) this.stop = null; return this; @@ -1626,7 +1626,7 @@ class RejectPacket extends Packet { switch (this.message) { case 'block': case 'tx': - this.hash = br.readHash('hex'); + this.hash = br.readHash(); break; default: this.hash = null; diff --git a/lib/net/peer.js b/lib/net/peer.js index ece374145..ea968f6ee 100644 --- a/lib/net/peer.js +++ b/lib/net/peer.js @@ -15,6 +15,7 @@ const tcp = require('btcp'); const dns = require('bdns'); const Logger = require('blgr'); const {RollingFilter} = require('bfilter'); +const {BufferMap} = require('buffer-map'); const util = require('../utils/util'); const Parser = require('./parser'); const Framer = require('./framer'); @@ -138,10 +139,10 @@ class Peer extends EventEmitter { this.addrFilter = new RollingFilter(5000, 0.001); this.invFilter = new RollingFilter(50000, 0.000001); - this.blockMap = new Map(); - this.txMap = new Map(); + this.blockMap = new BufferMap(); + this.txMap = new BufferMap(); this.responseMap = new Map(); - this.compactBlocks = new Map(); + this.compactBlocks = new BufferMap(); this.init(); } @@ -589,7 +590,7 @@ class Peer extends EventEmitter { // Check the fee filter. if (this.feeRate !== -1) { - const hash = tx.hash('hex'); + const hash = tx.hash(); const rate = this.options.getRate(hash); if (rate !== -1 && rate < this.feeRate) continue; @@ -650,7 +651,7 @@ class Peer extends EventEmitter { const items = []; for (const item of queue) { - if (!this.invFilter.added(item.hash, 'hex')) + if (!this.invFilter.added(item.hash)) continue; items.push(item); @@ -678,7 +679,7 @@ class Peer extends EventEmitter { items = [items]; for (const item of items) - this.invFilter.add(item.hash, 'hex'); + this.invFilter.add(item.hash); if (items.length === 0) return; diff --git a/lib/net/pool.js b/lib/net/pool.js index 3786ca560..732aa6e52 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -17,6 +17,7 @@ const UPNP = require('bupnp'); const socks = require('bsocks'); const List = require('blst'); const {BloomFilter, RollingFilter} = require('bfilter'); +const {BufferMap, BufferSet} = require('buffer-map'); const util = require('../utils/util'); const common = require('./common'); const chainCommon = require('../blockchain/common'); @@ -59,17 +60,17 @@ class Pool extends EventEmitter { this.server = this.options.createServer(); this.nonces = this.options.nonces; - this.locker = new Lock(true); + this.locker = new Lock(true, BufferMap); this.connected = false; this.disconnecting = false; this.syncing = false; this.discovering = false; this.spvFilter = null; this.txFilter = null; - this.blockMap = new Set(); - this.txMap = new Set(); - this.compactBlocks = new Set(); - this.invMap = new Map(); + this.blockMap = new BufferSet(); + this.txMap = new BufferSet(); + this.compactBlocks = new BufferSet(); + this.invMap = new BufferMap(); this.pendingFilter = null; this.pendingRefill = null; @@ -871,7 +872,7 @@ class Pool extends EventEmitter { let total = 0; for (let peer = this.peers.head(); peer; peer = peer.next) { - if (peer.bestHash !== hash) + if (!peer.bestHash || !peer.bestHash.equals(hash)) continue; if (peer.bestHeight !== height) { @@ -1566,7 +1567,7 @@ class Pool extends EventEmitter { unknown = item.type; continue; } - peer.invFilter.add(item.hash, 'hex'); + peer.invFilter.add(item.hash); } this.logger.spam( @@ -1824,7 +1825,7 @@ class Pool extends EventEmitter { } } - if (item.hash === peer.hashContinue) { + if (peer.hashContinue && item.hash.equals(peer.hashContinue)) { peer.sendInv([new InvItem(invTypes.BLOCK, this.chain.tip.hash)]); peer.hashContinue = null; } @@ -1910,7 +1911,7 @@ class Pool extends EventEmitter { while (hash) { blocks.push(new InvItem(invTypes.BLOCK, hash)); - if (hash === packet.stop) + if (packet.stop && hash.equals(packet.stop)) break; if (blocks.length === 500) { @@ -1963,7 +1964,7 @@ class Pool extends EventEmitter { while (entry) { headers.push(entry.toHeaders()); - if (entry.hash === packet.stop) + if (packet.stop && entry.hash.equals(packet.stop)) break; if (headers.length === 2000) @@ -2030,7 +2031,7 @@ class Pool extends EventEmitter { for (const header of headers) { const last = this.headerChain.tail; - const hash = header.hash('hex'); + const hash = header.hash(); const height = last.height + 1; if (!header.verify()) { @@ -2042,7 +2043,7 @@ class Pool extends EventEmitter { return; } - if (header.prevBlock !== last.hash) { + if (!header.prevBlock.equals(last.hash)) { this.logger.warning( 'Peer sent a bad header chain (%s).', peer.hostname()); @@ -2053,7 +2054,7 @@ class Pool extends EventEmitter { node = new HeaderEntry(hash, height); if (node.height === this.headerTip.height) { - if (node.hash !== this.headerTip.hash) { + if (!node.hash.equals(this.headerTip.hash)) { this.logger.warning( 'Peer sent an invalid checkpoint (%s).', peer.hostname()); @@ -2134,7 +2135,7 @@ class Pool extends EventEmitter { */ async addBlock(peer, block, flags) { - const hash = block.hash('hex'); + const hash = block.hash(); const unlock = await this.locker.lock(hash); try { return await this._addBlock(peer, block, flags); @@ -2156,7 +2157,7 @@ class Pool extends EventEmitter { if (!this.syncing) return; - const hash = block.hash('hex'); + const hash = block.hash(); if (!this.resolveBlock(peer, hash)) { this.logger.warning( @@ -2241,7 +2242,7 @@ class Pool extends EventEmitter { assert(node); - if (hash !== node.hash) { + if (!hash.equals(node.hash)) { this.logger.warning( 'Header hash mismatch %s != %s (%s).', util.revHex(hash), @@ -2365,7 +2366,7 @@ class Pool extends EventEmitter { */ async handleTX(peer, packet) { - const hash = packet.tx.hash('hex'); + const hash = packet.tx.hash(); const unlock = await this.locker.lock(hash); try { return await this._handleTX(peer, packet); @@ -2385,7 +2386,7 @@ class Pool extends EventEmitter { async _handleTX(peer, packet) { const tx = packet.tx; - const hash = tx.hash('hex'); + const hash = tx.hash(); const flags = chainCommon.flags.VERIFY_NONE; const block = peer.merkleBlock; @@ -2563,7 +2564,7 @@ class Pool extends EventEmitter { */ async handleMerkleBlock(peer, packet) { - const hash = packet.block.hash('hex'); + const hash = packet.block.hash(); const unlock = await this.locker.lock(hash); try { return await this._handleMerkleBlock(peer, packet); @@ -2594,7 +2595,7 @@ class Pool extends EventEmitter { } const block = packet.block; - const hash = block.hash('hex'); + const hash = block.hash(); if (!peer.blockMap.has(hash)) { this.logger.warning( @@ -2631,7 +2632,7 @@ class Pool extends EventEmitter { peer.merkleBlock = block; peer.merkleTime = Date.now(); peer.merkleMatches = tree.matches.length; - peer.merkleMap = new Set(); + peer.merkleMap = new BufferSet(); } /** @@ -2668,7 +2669,7 @@ class Pool extends EventEmitter { async handleCmpctBlock(peer, packet) { const block = packet.block; - const hash = block.hash('hex'); + const hash = block.hash(); const witness = peer.compactWitness; if (!this.syncing) @@ -3348,7 +3349,7 @@ class Pool extends EventEmitter { if (!this.mempool) { // Check the TX filter if // we don't have a mempool. - if (!this.txFilter.added(hash, 'hex')) + if (!this.txFilter.added(hash)) return true; } else { // Check the mempool. @@ -3447,7 +3448,7 @@ class Pool extends EventEmitter { */ broadcast(msg) { - const hash = msg.hash('hex'); + const hash = msg.hash(); let item = this.invMap.get(hash); @@ -4231,30 +4232,28 @@ class NonceList { */ constructor() { - this.map = new Map(); + this.map = new BufferMap(); this.hosts = new Map(); } alloc(hostname) { for (;;) { const nonce = common.nonce(); - const key = nonce.toString('hex'); - if (this.map.has(key)) + if (this.map.has(nonce)) continue; - this.map.set(key, hostname); + this.map.set(nonce, hostname); assert(!this.hosts.has(hostname)); - this.hosts.set(hostname, key); + this.hosts.set(hostname, nonce); return nonce; } } has(nonce) { - const key = nonce.toString('hex'); - return this.map.has(key); + return this.map.has(nonce); } remove(hostname) { diff --git a/lib/node/http.js b/lib/node/http.js index 2f75035dd..be1dd6046 100644 --- a/lib/node/http.js +++ b/lib/node/http.js @@ -168,7 +168,7 @@ class HTTP extends Server { // UTXO by id this.get('/coin/:hash/:index', async (req, res) => { const valid = Validator.fromRequest(req); - const hash = valid.rhash('hash'); + const hash = valid.brhash('hash'); const index = valid.u32('index'); enforce(hash, 'Hash is required.'); @@ -205,7 +205,7 @@ class HTTP extends Server { // TX by hash this.get('/tx/:hash', async (req, res) => { const valid = Validator.fromRequest(req); - const hash = valid.rhash('hash'); + const hash = valid.brhash('hash'); enforce(hash, 'Hash is required.'); enforce(!this.chain.options.spv, 'Cannot get TX in SPV mode.'); @@ -263,7 +263,7 @@ class HTTP extends Server { // Block by hash/height this.get('/block/:block', async (req, res) => { const valid = Validator.fromRequest(req); - const hash = valid.uintrhash('block'); + const hash = valid.uintbrhash('block'); enforce(hash != null, 'Hash or height required.'); enforce(!this.chain.options.spv, 'Cannot get block in SPV mode.'); @@ -427,7 +427,7 @@ class HTTP extends Server { socket.hook('get entry', async (...args) => { const valid = new Validator(args); - const block = valid.uintrhash(0); + const block = valid.uintbrhash(0); if (block == null) throw new Error('Invalid parameter.'); @@ -509,7 +509,7 @@ class HTTP extends Server { socket.hook('rescan', (...args) => { const valid = new Validator(args); - const start = valid.uintrhash(0); + const start = valid.uintbrhash(0); if (start == null) throw new Error('Invalid parameter.'); diff --git a/lib/node/rpc.js b/lib/node/rpc.js index ab4d221ea..f5a60df40 100644 --- a/lib/node/rpc.js +++ b/lib/node/rpc.js @@ -11,6 +11,7 @@ const bweb = require('bweb'); const {Lock} = require('bmutex'); const IP = require('binet'); const Validator = require('bval'); +const {BufferMap, BufferSet} = require('buffer-map'); const hash160 = require('bcrypto/lib/hash160'); const hash256 = require('bcrypto/lib/hash256'); const ccmp = require('bcrypto/lib/ccmp'); @@ -109,7 +110,7 @@ class RPC extends RPCBase { this.boundChain = false; this.nonce1 = 0; this.nonce2 = 0; - this.merkleMap = new Map(); + this.merkleMap = new BufferMap(); this.pollers = []; this.init(); @@ -607,7 +608,7 @@ class RPC extends RPCBase { throw new RPCError(errs.MISC_ERROR, 'getblock "hash" ( verbose )'); const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); const verbose = valid.bool(1, true); const details = valid.bool(2, false); @@ -701,7 +702,7 @@ class RPC extends RPCBase { throw new RPCError(errs.MISC_ERROR, 'getblockheader "hash" ( verbose )'); const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); const verbose = valid.bool(1, true); if (!hash) @@ -772,7 +773,7 @@ class RPC extends RPCBase { throw new RPCError(errs.MISC_ERROR, 'getmempoolancestors txid (verbose)'); const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); const verbose = valid.bool(1, false); if (!this.mempool) @@ -807,7 +808,7 @@ class RPC extends RPCBase { } const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); const verbose = valid.bool(1, false); if (!this.mempool) @@ -840,7 +841,7 @@ class RPC extends RPCBase { throw new RPCError(errs.MISC_ERROR, 'getmempoolentry txid'); const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); if (!this.mempool) throw new RPCError(errs.MISC_ERROR, 'No mempool available.'); @@ -887,7 +888,7 @@ class RPC extends RPCBase { } const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); const index = valid.u32(1); const mempool = valid.bool(2, true); @@ -931,7 +932,7 @@ class RPC extends RPCBase { const valid = new Validator(args); const txids = valid.array(0); - const hash = valid.rhash(1); + const hash = valid.brhash(1); if (this.chain.options.spv) throw new RPCError(errs.MISC_ERROR, 'Cannot get coins in SPV mode.'); @@ -943,13 +944,13 @@ class RPC extends RPCBase { throw new RPCError(errs.INVALID_PARAMETER, 'Invalid TXIDs.'); const items = new Validator(txids); - const set = new Set(); + const set = new BufferSet(); const hashes = []; let last = null; for (let i = 0; i < txids.length; i++) { - const hash = items.rhash(i); + const hash = items.brhash(i); if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.'); @@ -1007,7 +1008,7 @@ class RPC extends RPCBase { if (!block.verify()) return []; - const entry = await this.chain.getEntry(block.hash('hex')); + const entry = await this.chain.getEntry(block.hash()); if (!entry) throw new RPCError(errs.MISC_ERROR, 'Block not found in chain.'); @@ -1016,7 +1017,7 @@ class RPC extends RPCBase { const out = []; for (const hash of tree.matches) - out.push(util.revHex(hash.toString('hex'))); + out.push(util.revHex(hash)); return out; } @@ -1248,7 +1249,7 @@ class RPC extends RPCBase { const block = Block.fromRaw(data); - if (block.prevBlock !== this.chain.tip.hash) + if (!block.prevBlock.equals(this.chain.tip.hash)) return 'inconclusive-not-best-prevblk'; try { @@ -1365,7 +1366,7 @@ class RPC extends RPCBase { } // Build an index of every transaction. - const index = new Map(); + const index = new BufferMap(); for (let i = 0; i < attempt.items.length; i++) { const entry = attempt.items[i]; index.set(entry.hash, i + 1); @@ -1461,7 +1462,7 @@ class RPC extends RPCBase { vbrequired: 0, height: attempt.height, previousblockhash: util.revHex(attempt.prevBlock), - target: util.revHex(attempt.target.toString('hex')), + target: util.revHex(attempt.target), bits: hex32(attempt.bits), noncerange: '00000000ffffffff', curtime: attempt.time, @@ -1586,7 +1587,7 @@ class RPC extends RPCBase { } const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); const pri = valid.i64(1); const fee = valid.i64(2); @@ -1733,7 +1734,7 @@ class RPC extends RPCBase { for (const obj of inputs) { const valid = new Validator(obj); - const hash = valid.rhash('txid'); + const hash = valid.brhash('txid'); const index = valid.u32('vout'); let sequence = valid.u32('sequence', 0xffffffff); @@ -1834,7 +1835,7 @@ class RPC extends RPCBase { } const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); const verbose = valid.bool(1, false); if (!hash) @@ -1905,7 +1906,7 @@ class RPC extends RPCBase { const tx = MTX.fromRaw(data); tx.view = await this.mempool.getSpentView(tx); - const map = new Map(); + const map = new BufferMap(); const keys = []; if (secrets) { @@ -1913,7 +1914,7 @@ class RPC extends RPCBase { for (let i = 0; i < secrets.length; i++) { const secret = valid.str(i, ''); const key = parseSecret(secret, this.network); - map.set(key.getPublicKey('hex'), key); + map.set(key.getPublicKey(), key); keys.push(key); } } @@ -1921,7 +1922,7 @@ class RPC extends RPCBase { if (prevout) { for (const prev of prevout) { const valid = new Validator(prev); - const hash = valid.rhash('txid'); + const hash = valid.brhash('txid'); const index = valid.u32('vout'); const scriptRaw = valid.buf('scriptPubKey'); const value = valid.ufixed('amount', 8); @@ -1954,7 +1955,7 @@ class RPC extends RPCBase { if (!op.data) continue; - const key = map.get(op.data.toString('hex')); + const key = map.get(op.data); if (key) { key.script = redeem; @@ -2208,7 +2209,7 @@ class RPC extends RPCBase { throw new RPCError(errs.MISC_ERROR, 'invalidateblock "hash"'); const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid block hash.'); @@ -2223,7 +2224,7 @@ class RPC extends RPCBase { throw new RPCError(errs.MISC_ERROR, 'reconsiderblock "hash"'); const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid block hash.'); @@ -2287,7 +2288,7 @@ class RPC extends RPCBase { const hash = util.revHex(watched); - if (this.chain.tip.hash !== hash) + if (!this.chain.tip.hash.equals(hash)) return; await this.longpoll(); @@ -2376,9 +2377,8 @@ class RPC extends RPCBase { const n2 = this.nonce2; const root = attempt.getRoot(n1, n2); - const hash = root.toString('hex'); - this.merkleMap.set(hash, [n1, n2]); + this.merkleMap.set(root, [n1, n2]); return attempt; } @@ -2394,11 +2394,10 @@ class RPC extends RPCBase { const n2 = this.nonce2; const root = attempt.getRoot(n1, n2); - const hash = root.toString('hex'); this.attempt = attempt; this.lastActivity = util.now(); - this.merkleMap.set(hash, [n1, n2]); + this.merkleMap.set(root, [n1, n2]); return attempt; } @@ -2704,7 +2703,7 @@ class RPC extends RPCBase { bits: entry.bits, difficulty: toDifficulty(entry.bits), chainwork: entry.chainwork.toString('hex', 64), - previousblockhash: entry.prevBlock !== consensus.NULL_HASH + previousblockhash: !entry.prevBlock.equals(consensus.ZERO_HASH) ? util.revHex(entry.prevBlock) : null, nextblockhash: next ? util.revHex(next) : null @@ -2742,7 +2741,7 @@ class RPC extends RPCBase { bits: entry.bits, difficulty: toDifficulty(entry.bits), chainwork: entry.chainwork.toString('hex', 64), - previousblockhash: entry.prevBlock !== consensus.NULL_HASH + previousblockhash: !entry.prevBlock.equals(consensus.ZERO_HASH) ? util.revHex(entry.prevBlock) : null, nextblockhash: next ? util.revHex(next) : null diff --git a/lib/primitives/abstractblock.js b/lib/primitives/abstractblock.js index 0559a65df..84ba06743 100644 --- a/lib/primitives/abstractblock.js +++ b/lib/primitives/abstractblock.js @@ -35,8 +35,8 @@ class AbstractBlock { constructor() { this.version = 1; - this.prevBlock = consensus.NULL_HASH; - this.merkleRoot = consensus.NULL_HASH; + this.prevBlock = consensus.ZERO_HASH; + this.merkleRoot = consensus.ZERO_HASH; this.time = 0; this.bits = 0; this.nonce = 0; @@ -56,8 +56,8 @@ class AbstractBlock { parseOptions(options) { assert(options, 'Block data is required.'); assert((options.version >>> 0) === options.version); - assert(typeof options.prevBlock === 'string'); - assert(typeof options.merkleRoot === 'string'); + assert(Buffer.isBuffer(options.prevBlock)); + assert(Buffer.isBuffer(options.merkleRoot)); assert((options.time >>> 0) === options.time); assert((options.bits >>> 0) === options.bits); assert((options.nonce >>> 0) === options.nonce); @@ -93,8 +93,8 @@ class AbstractBlock { assert((json.nonce >>> 0) === json.nonce); this.version = json.version; - this.prevBlock = util.revHex(json.prevBlock); - this.merkleRoot = util.revHex(json.merkleRoot); + this.prevBlock = util.fromRev(json.prevBlock); + this.merkleRoot = util.fromRev(json.merkleRoot); this.time = json.time; this.bits = json.bits; this.nonce = json.nonce; @@ -197,8 +197,8 @@ class AbstractBlock { readHead(br) { this.version = br.readU32(); - this.prevBlock = br.readHash('hex'); - this.merkleRoot = br.readHash('hex'); + this.prevBlock = br.readHash(); + this.merkleRoot = br.readHash(); this.time = br.readU32(); this.bits = br.readU32(); this.nonce = br.readU32(); @@ -244,7 +244,7 @@ class AbstractBlock { */ rhash() { - return util.revHex(this.hash('hex')); + return util.revHex(this.hash()); } /** @@ -253,7 +253,7 @@ class AbstractBlock { */ toInv() { - return new InvItem(InvItem.types.BLOCK, this.hash('hex')); + return new InvItem(InvItem.types.BLOCK, this.hash()); } } diff --git a/lib/primitives/address.js b/lib/primitives/address.js index f2c4799a4..fb0cbbd3b 100644 --- a/lib/primitives/address.js +++ b/lib/primitives/address.js @@ -82,7 +82,7 @@ class Address { getHash(enc) { if (enc === 'hex') - return this.hash.toString(enc); + return this.hash.toString('hex'); return this.hash; } @@ -560,9 +560,6 @@ class Address { */ fromHash(hash, type, version) { - if (typeof hash === 'string') - hash = Buffer.from(hash, 'hex'); - if (typeof type === 'string') { type = Address.types[type.toUpperCase()]; assert(type != null, 'Not a valid address type.'); @@ -719,9 +716,6 @@ class Address { assert(version >= 0, 'Bad version for witness program.'); - if (typeof hash === 'string') - hash = Buffer.from(hash, 'hex'); - return this.fromHash(hash, type, version); } @@ -804,18 +798,13 @@ class Address { * @returns {Hash} */ - static getHash(data, enc, network) { + static getHash(data, network) { if (!data) throw new Error('Object is not an address.'); let hash; - if (typeof data === 'string') { - if (data.length === 40 || data.length === 64) - return enc === 'hex' ? data : Buffer.from(data, 'hex'); - - hash = Address.fromString(data, network).hash; - } else if (Buffer.isBuffer(data)) { + if (Buffer.isBuffer(data)) { if (data.length !== 20 && data.length !== 32) throw new Error('Object is not an address.'); hash = data; @@ -825,9 +814,7 @@ class Address { throw new Error('Object is not an address.'); } - return enc === 'hex' - ? hash.toString('hex') - : hash; + return hash; } /** diff --git a/lib/primitives/block.js b/lib/primitives/block.js index f620df724..be3462a61 100644 --- a/lib/primitives/block.js +++ b/lib/primitives/block.js @@ -260,7 +260,7 @@ class Block extends AbstractBlock { indexOf(hash) { for (let i = 0; i < this.txs.length; i++) { const tx = this.txs[i]; - if (tx.hash('hex') === hash) + if (tx.hash().equals(hash)) return i; } @@ -337,8 +337,8 @@ class Block extends AbstractBlock { getMerkleRoot(enc) { if (enc === 'hex') - return this.merkleRoot; - return Buffer.from(this.merkleRoot, 'hex'); + return this.merkleRoot.toString('hex'); + return this.merkleRoot; } /** @@ -428,14 +428,14 @@ class Block extends AbstractBlock { return [false, 'bad-cb-missing', 100]; // Check merkle root. - const root = this.createMerkleRoot('hex'); + const root = this.createMerkleRoot(); // If the merkle is mutated, // we have duplicate txs. if (!root) return [false, 'bad-txns-duplicate', 100]; - if (this.merkleRoot !== root) + if (!this.merkleRoot.equals(root)) return [false, 'bad-txnmrklroot', 100]; // Test all transactions. diff --git a/lib/primitives/coin.js b/lib/primitives/coin.js index f51d19f37..9c777b8ba 100644 --- a/lib/primitives/coin.js +++ b/lib/primitives/coin.js @@ -42,7 +42,7 @@ class Coin extends Output { this.version = 1; this.height = -1; this.coinbase = false; - this.hash = consensus.NULL_HASH; + this.hash = consensus.ZERO_HASH; this.index = 0; if (options) @@ -90,7 +90,7 @@ class Coin extends Output { } if (options.hash != null) { - assert(typeof options.hash === 'string', 'Hash must be a string.'); + assert(Buffer.isBuffer(options.hash)); this.hash = options.hash; } @@ -152,7 +152,7 @@ class Coin extends Output { */ toKey() { - return this.hash + this.index; + return this.toRaw(); } /** @@ -163,10 +163,7 @@ class Coin extends Output { */ fromKey(key) { - assert(key.length > 64); - this.hash = key.slice(0, 64); - this.index = parseInt(key.slice(64), 10); - return this; + return this.fromRaw(key); } /** @@ -281,7 +278,7 @@ class Coin extends Output { assert(typeof json.hash === 'string', 'Hash must be a string.'); assert(json.hash.length === 64, 'Hash must be a string.'); assert((json.index >>> 0) === json.index, 'Index must be a uint32.'); - this.hash = util.revHex(json.hash); + this.hash = util.fromRev(json.hash); this.index = json.index; } @@ -404,7 +401,7 @@ class Coin extends Output { this.value = tx.outputs[index].value; this.script = tx.outputs[index].script; this.coinbase = tx.isCoinbase(); - this.hash = tx.hash('hex'); + this.hash = tx.hash(); this.index = index; return this; } diff --git a/lib/primitives/headers.js b/lib/primitives/headers.js index 1e52440a5..14b3e35b3 100644 --- a/lib/primitives/headers.js +++ b/lib/primitives/headers.js @@ -145,7 +145,7 @@ class Headers extends AbstractBlock { headers.time = entry.time; headers.bits = entry.bits; headers.nonce = entry.nonce; - headers._hash = Buffer.from(entry.hash, 'hex'); + headers._hash = entry.hash; headers._hhash = entry.hash; return headers; } diff --git a/lib/primitives/input.js b/lib/primitives/input.js index b8ad59cfe..a53b6d7bd 100644 --- a/lib/primitives/input.js +++ b/lib/primitives/input.js @@ -442,7 +442,7 @@ class Input { */ fromOutpoint(outpoint) { - assert(typeof outpoint.hash === 'string'); + assert(Buffer.isBuffer(outpoint.hash)); assert(typeof outpoint.index === 'number'); this.prevout.hash = outpoint.hash; this.prevout.index = outpoint.index; @@ -466,7 +466,7 @@ class Input { */ fromCoin(coin) { - assert(typeof coin.hash === 'string'); + assert(Buffer.isBuffer(coin.hash)); assert(typeof coin.index === 'number'); this.prevout.hash = coin.hash; this.prevout.index = coin.index; @@ -494,7 +494,7 @@ class Input { assert(tx); assert(typeof index === 'number'); assert(index >= 0 && index < tx.outputs.length); - this.prevout.hash = tx.hash('hex'); + this.prevout.hash = tx.hash(); this.prevout.index = index; return this; } diff --git a/lib/primitives/invitem.js b/lib/primitives/invitem.js index 5a8af709d..e00f59a5a 100644 --- a/lib/primitives/invitem.js +++ b/lib/primitives/invitem.js @@ -68,7 +68,7 @@ class InvItem { fromReader(br) { this.type = br.readU32(); - this.hash = br.readHash('hex'); + this.hash = br.readHash(); return this; } diff --git a/lib/primitives/merkleblock.js b/lib/primitives/merkleblock.js index db36514b5..af0176bf2 100644 --- a/lib/primitives/merkleblock.js +++ b/lib/primitives/merkleblock.js @@ -9,6 +9,7 @@ const assert = require('assert'); const bio = require('bufio'); +const {BufferMap, BufferSet} = require('buffer-map'); const util = require('../utils/util'); const hash256 = require('bcrypto/lib/hash256'); const consensus = require('../protocol/consensus'); @@ -60,9 +61,7 @@ class MerkleBlock extends AbstractBlock { assert((options.totalTX >>> 0) === options.totalTX); if (options.hashes) { - for (let hash of options.hashes) { - if (typeof hash === 'string') - hash = Buffer.from(hash, 'hex'); + for (const hash of options.hashes) { assert(Buffer.isBuffer(hash)); this.hashes.push(hash); } @@ -153,7 +152,7 @@ class MerkleBlock extends AbstractBlock { checkBody() { const tree = this.getTree(); - if (tree.root !== this.merkleRoot) + if (!tree.root.equals(this.merkleRoot)) return [false, 'bad-txnmrklroot', 100]; return [true, 'valid', 0]; @@ -186,7 +185,7 @@ class MerkleBlock extends AbstractBlock { extractTree() { const matches = []; const indexes = []; - const map = new Map(); + const map = new BufferMap(); const hashes = this.hashes; const flags = this.flags; const totalTX = this.totalTX; @@ -221,10 +220,9 @@ class MerkleBlock extends AbstractBlock { hashUsed += 1; if (height === 0 && parent) { - const txid = hash.toString('hex'); matches.push(hash); indexes.push(pos); - map.set(txid, pos); + map.set(hash, pos); } return hash; @@ -455,7 +453,7 @@ class MerkleBlock extends AbstractBlock { nonce: this.nonce, totalTX: this.totalTX, hashes: this.hashes.map((hash) => { - return util.revHex(hash.toString('hex')); + return util.revHex(hash); }), flags: this.flags.toString('hex') }; @@ -475,10 +473,8 @@ class MerkleBlock extends AbstractBlock { this.parseJSON(json); - for (let hash of json.hashes) { - hash = util.revHex(hash); - this.hashes.push(Buffer.from(hash, 'hex')); - } + for (const hash of json.hashes) + this.hashes.push(util.fromRev(hash)); this.flags = Buffer.from(json.flags, 'hex'); @@ -524,18 +520,15 @@ class MerkleBlock extends AbstractBlock { */ static fromHashes(block, hashes) { - const filter = new Set(); + const filter = new BufferSet(); - for (let hash of hashes) { - if (Buffer.isBuffer(hash)) - hash = hash.toString('hex'); + for (const hash of hashes) filter.add(hash); - } const matches = []; for (const tx of block.txs) { - const hash = tx.hash('hex'); + const hash = tx.hash(); matches.push(filter.has(hash) ? 1 : 0); } @@ -659,10 +652,10 @@ class MerkleBlock extends AbstractBlock { class PartialTree { constructor(root, matches, indexes, map) { - this.root = root ? root.toString('hex') : consensus.NULL_HASH; + this.root = root || consensus.ZERO_HASH; this.matches = matches || []; this.indexes = indexes || []; - this.map = map || new Map(); + this.map = map || new BufferMap(); } } diff --git a/lib/primitives/mtx.js b/lib/primitives/mtx.js index d20a507cc..4362f084d 100644 --- a/lib/primitives/mtx.js +++ b/lib/primitives/mtx.js @@ -9,6 +9,7 @@ const assert = require('assert'); const {encoding} = require('bufio'); +const {BufferMap} = require('buffer-map'); const Script = require('../script/script'); const TX = require('./tx'); const Input = require('./input'); @@ -1478,7 +1479,7 @@ class MTX extends TX { const coin = Coin.fromJSON(input.coin); - coin.hash = util.revHex(prevout.hash); + coin.hash = util.fromRev(prevout.hash); coin.index = prevout.index; this.view.addCoin(coin); @@ -1592,7 +1593,7 @@ class CoinSelector { this.maxFee = -1; this.round = false; this.changeAddress = null; - this.inputs = new Map(); + this.inputs = new BufferMap(); // Needed for size estimation. this.estimate = null; @@ -1696,7 +1697,7 @@ class CoinSelector { const prevout = options.inputs[i]; assert(prevout && typeof prevout === 'object'); const {hash, index} = prevout; - assert(typeof hash === 'string'); + assert(Buffer.isBuffer(hash)); assert(typeof index === 'number'); this.inputs.set(Outpoint.toKey(hash, index), i); } diff --git a/lib/primitives/outpoint.js b/lib/primitives/outpoint.js index f9c39270b..a037de044 100644 --- a/lib/primitives/outpoint.js +++ b/lib/primitives/outpoint.js @@ -28,11 +28,11 @@ class Outpoint { */ constructor(hash, index) { - this.hash = consensus.NULL_HASH; + this.hash = consensus.ZERO_HASH; this.index = 0xffffffff; if (hash != null) { - assert(typeof hash === 'string', 'Hash must be a string.'); + assert(Buffer.isBuffer(hash)); assert((index >>> 0) === index, 'Index must be a uint32.'); this.hash = hash; this.index = index; @@ -47,7 +47,7 @@ class Outpoint { fromOptions(options) { assert(options, 'Outpoint data is required.'); - assert(typeof options.hash === 'string', 'Hash must be a string.'); + assert(Buffer.isBuffer(options.hash)); assert((options.index >>> 0) === options.index, 'Index must be a uint32.'); this.hash = options.hash; this.index = options.index; @@ -84,7 +84,7 @@ class Outpoint { equals(prevout) { assert(Outpoint.isOutpoint(prevout)); - return this.hash === prevout.hash + return this.hash.equals(prevout.hash) && this.index === prevout.index; } @@ -112,7 +112,7 @@ class Outpoint { */ isNull() { - return this.index === 0xffffffff && this.hash === consensus.NULL_HASH; + return this.index === 0xffffffff && this.hash.equals(consensus.ZERO_HASH); } /** @@ -140,7 +140,7 @@ class Outpoint { */ toKey() { - return Outpoint.toKey(this.hash, this.index); + return this.toRaw(); } /** @@ -151,9 +151,8 @@ class Outpoint { */ fromKey(key) { - assert(key.length > 64); - this.hash = key.slice(0, 64); - this.index = parseInt(key.slice(64), 10); + this.hash = key.slice(0, 32); + this.index = bio.readU32(key, 32); return this; } @@ -203,7 +202,7 @@ class Outpoint { */ fromReader(br) { - this.hash = br.readHash('hex'); + this.hash = br.readHash(); this.index = br.readU32(); return this; } @@ -248,7 +247,7 @@ class Outpoint { assert(json, 'Outpoint data is required.'); assert(typeof json.hash === 'string', 'Hash must be a string.'); assert((json.index >>> 0) === json.index, 'Index must be a uint32.'); - this.hash = util.revHex(json.hash); + this.hash = util.fromRev(json.hash); this.index = json.index; return this; } @@ -289,7 +288,7 @@ class Outpoint { assert(tx); assert(typeof index === 'number'); assert(index >= 0); - this.hash = tx.hash('hex'); + this.hash = tx.hash(); this.index = index; return this; } @@ -314,10 +313,7 @@ class Outpoint { */ static toKey(hash, index) { - assert(typeof hash === 'string'); - assert(hash.length === 64); - assert(index >= 0); - return hash + index; + return new Outpoint(hash, index).toKey(); } /** diff --git a/lib/primitives/tx.js b/lib/primitives/tx.js index 09051c33a..39cdefe6c 100644 --- a/lib/primitives/tx.js +++ b/lib/primitives/tx.js @@ -11,6 +11,7 @@ const assert = require('assert'); const bio = require('bufio'); const hash256 = require('bcrypto/lib/hash256'); const secp256k1 = require('bcrypto/lib/secp256k1'); +const {BufferSet} = require('buffer-map'); const util = require('../utils/util'); const Amount = require('../btc/amount'); const Network = require('../protocol/network'); @@ -1005,7 +1006,7 @@ class TX { */ _getInputAddresses(view) { - const table = Object.create(null); + const table = new BufferSet(); const addrs = []; if (this.isCoinbase()) @@ -1018,10 +1019,10 @@ class TX { if (!addr) continue; - const hash = addr.getHash('hex'); + const hash = addr.getHash(); - if (!table[hash]) { - table[hash] = true; + if (!table.has(hash)) { + table.add(hash); addrs.push(addr); } } @@ -1036,7 +1037,7 @@ class TX { */ _getOutputAddresses() { - const table = Object.create(null); + const table = new BufferSet(); const addrs = []; for (const output of this.outputs) { @@ -1045,10 +1046,10 @@ class TX { if (!addr) continue; - const hash = addr.getHash('hex'); + const hash = addr.getHash(); - if (!table[hash]) { - table[hash] = true; + if (!table.has(hash)) { + table.add(hash); addrs.push(addr); } } @@ -1068,10 +1069,10 @@ class TX { const output = this.getOutputAddresses(); for (const addr of output) { - const hash = addr.getHash('hex'); + const hash = addr.getHash(); - if (!table[hash]) { - table[hash] = true; + if (!table.has(hash)) { + table.add(hash); addrs.push(addr); } } @@ -1118,18 +1119,12 @@ class TX { */ getInputHashes(view, enc) { - if (enc === 'hex') { - const [, table] = this._getInputAddresses(view); - return Object.keys(table); - } - - const addrs = this.getInputAddresses(view); - const hashes = []; + const [, table] = this._getInputAddresses(view); - for (const addr of addrs) - hashes.push(addr.getHash()); + if (enc !== 'hex') + return table.toArray(); - return hashes; + return table.toArray().map(h => h.toString('hex')); } /** @@ -1138,18 +1133,12 @@ class TX { */ getOutputHashes(enc) { - if (enc === 'hex') { - const [, table] = this._getOutputAddresses(); - return Object.keys(table); - } + const [, table] = this._getOutputAddresses(); - const addrs = this.getOutputAddresses(); - const hashes = []; + if (enc !== 'hex') + return table.toArray(); - for (const addr of addrs) - hashes.push(addr.getHash()); - - return hashes; + return table.toArray().map(h => h.toString('hex')); } /** @@ -1159,18 +1148,12 @@ class TX { */ getHashes(view, enc) { - if (enc === 'hex') { - const [, table] = this._getAddresses(view); - return Object.keys(table); - } - - const addrs = this.getAddresses(view); - const hashes = []; + const [, table] = this._getAddresses(view); - for (const addr of addrs) - hashes.push(addr.getHash()); + if (enc !== 'hex') + return table.toArray(); - return hashes; + return table.toArray().map(h => h.toString('hex')); } /** @@ -1448,7 +1431,7 @@ class TX { return [false, 'bad-txns-txouttotal-toolarge', 100]; } - const prevout = new Set(); + const prevout = new BufferSet(); for (const input of this.inputs) { const key = input.prevout.toKey(); @@ -1940,12 +1923,12 @@ class TX { if (this.isCoinbase()) return []; - const prevout = Object.create(null); + const prevout = new BufferSet(); for (const input of this.inputs) - prevout[input.prevout.hash] = true; + prevout.add(input.prevout.hash); - return Object.keys(prevout); + return prevout.toArray(); } /** @@ -2012,7 +1995,7 @@ class TX { */ rhash() { - return util.revHex(this.hash('hex')); + return util.revHex(this.hash()); } /** @@ -2021,7 +2004,7 @@ class TX { */ rwhash() { - return util.revHex(this.witnessHash('hex')); + return util.revHex(this.witnessHash()); } /** @@ -2048,7 +2031,7 @@ class TX { */ toInv() { - return new InvItem(InvItem.types.TX, this.hash('hex')); + return new InvItem(InvItem.types.TX, this.hash()); } /** diff --git a/lib/primitives/txmeta.js b/lib/primitives/txmeta.js index 8b725c193..0aa03a3ed 100644 --- a/lib/primitives/txmeta.js +++ b/lib/primitives/txmeta.js @@ -59,7 +59,7 @@ class TXMeta { } if (options.block !== undefined) { - assert(options.block === null || typeof options.block === 'string'); + assert(options.block == null || Buffer.isBuffer(options.block)); this.block = options.block; } @@ -184,7 +184,7 @@ class TXMeta { this.mtime = json.mtime; this.height = json.height; - this.block = util.revHex(json.block); + this.block = util.fromRev(json.block); this.index = json.index; return this; @@ -267,7 +267,7 @@ class TXMeta { this.mtime = br.readU32(); if (br.readU8() === 1) { - this.block = br.readHash('hex'); + this.block = br.readHash(); this.height = br.readU32(); this.time = br.readU32(); this.index = br.readU32(); diff --git a/lib/protocol/consensus.js b/lib/protocol/consensus.js index 36f8e0729..5e1625638 100644 --- a/lib/protocol/consensus.js +++ b/lib/protocol/consensus.js @@ -234,15 +234,6 @@ exports.BIP16_TIME = 1333238400; exports.ZERO_HASH = Buffer.alloc(32, 0x00); -/** - * A hash of all zeroes. - * @const {String} - * @default - */ - -exports.NULL_HASH = - '0000000000000000000000000000000000000000000000000000000000000000'; - /** * Convert a compact number to a big number. * Used for `block.bits` -> `target` conversion. diff --git a/lib/protocol/errors.js b/lib/protocol/errors.js index 2cdef39d2..030717bdb 100644 --- a/lib/protocol/errors.js +++ b/lib/protocol/errors.js @@ -52,7 +52,7 @@ class VerifyError extends Error { this.code = code; this.reason = reason; this.score = score; - this.hash = msg.hash('hex'); + this.hash = msg.hash(); this.malleated = malleated || false; this.message = `Verification failure: ${reason}` diff --git a/lib/protocol/networks.js b/lib/protocol/networks.js index 19df6b579..63e81668a 100644 --- a/lib/protocol/networks.js +++ b/lib/protocol/networks.js @@ -15,6 +15,14 @@ const BN = require('bn.js'); const network = exports; +/* + * Helpers + */ + +function b(hash) { + return Buffer.from(hash, 'hex'); +} + /** * Network type list. * @memberof module:protocol/networks @@ -78,35 +86,35 @@ main.port = 8333; */ main.checkpointMap = { - 11111: '1d7c6eb2fd42f55925e92efad68b61edd22fba29fde8783df744e26900000000', - 33333: 'a6d0b5df7d0df069ceb1e736a216ad187a50b07aaa4e78748a58d52d00000000', - 74000: '201a66b853f9e7814a820e2af5f5dc79c07144e31ce4c9a39339570000000000', - 105000: '97dc6b1d15fbeef373a744fee0b254b0d2c820a3ae7f0228ce91020000000000', - 134444: 'feb0d2420d4a18914c81ac30f494a5d4ff34cd15d34cfd2fb105000000000000', - 168000: '63b703835cb735cb9a89d733cbe66f212f63795e0172ea619e09000000000000', - 193000: '17138bca83bdc3e6f60f01177c3877a98266de40735f2a459f05000000000000', - 210000: '2e3471a19b8e22b7f939c63663076603cf692f19837e34958b04000000000000', - 216116: '4edf231bf170234e6a811460f95c94af9464e41ee833b4f4b401000000000000', - 225430: '32595730b165f097e7b806a679cf7f3e439040f750433808c101000000000000', - 250000: '14d2f24d29bed75354f3f88a5fb50022fc064b02291fdf873800000000000000', - 279000: '407ebde958e44190fa9e810ea1fc3a7ef601c3b0a0728cae0100000000000000', - 295000: '83a93246c67003105af33ae0b29dd66f689d0f0ff54e9b4d0000000000000000', - 300255: 'b2f3a0f0de4120c1089d5f5280a263059f9b6e7c520428160000000000000000', - 319400: '3bf115fd057391587ca39a531c5d4989e1adec9b2e05c6210000000000000000', - 343185: '548536d48e7678fcfa034202dd45d4a76b1ad061f38b2b070000000000000000', - 352940: 'ffc9520143e41c94b6e03c2fa3e62bb76b55ba2df45d75100000000000000000', - 382320: 'b28afdde92b0899715e40362f56afdb20e3d135bedc68d0a0000000000000000', - 401465: 'eed16cb3e893ed9366f27c39a9ecd95465d02e3ef40e45010000000000000000', - 420000: 'a1ff746b2d42b834cb7d6b8981b09c265c2cabc016e8cc020000000000000000', - 440000: '9bf296b8de5f834f7635d5e258a434ad51b4dbbcf7c08c030000000000000000', - 450000: '0ba2070c62cd9da1f8cef88a0648c661a411d33e728340010000000000000000', - 460000: '8c25fc7e414d3e868d6ce0ec473c30ad44e7e8bc1b75ef000000000000000000', - 470000: '89756d1ed75901437300af10d5ab69070a282e729c536c000000000000000000', - 480000: 'b1a896fd31e639e0c74d1abeb1dbc93f176b767a5d4c02010000000000000000', - 490000: '90dec4d0153f20fbdcb245b1d5fb3d5a8d7bb1379106de000000000000000000', - 500000: '045d94a1c33354c3759cc0512dcc49fd81bf4c3637fb24000000000000000000', - 510000: '297301b8ca28584cb0c31c7e3fed51696bc33ef8782615000000000000000000', - 525000: '1dde8e3fb49bbd5ab66a1b847544d67fff10b108a1fa2f000000000000000000' + 11111: b('1d7c6eb2fd42f55925e92efad68b61edd22fba29fde8783df744e26900000000'), + 33333: b('a6d0b5df7d0df069ceb1e736a216ad187a50b07aaa4e78748a58d52d00000000'), + 74000: b('201a66b853f9e7814a820e2af5f5dc79c07144e31ce4c9a39339570000000000'), + 105000: b('97dc6b1d15fbeef373a744fee0b254b0d2c820a3ae7f0228ce91020000000000'), + 134444: b('feb0d2420d4a18914c81ac30f494a5d4ff34cd15d34cfd2fb105000000000000'), + 168000: b('63b703835cb735cb9a89d733cbe66f212f63795e0172ea619e09000000000000'), + 193000: b('17138bca83bdc3e6f60f01177c3877a98266de40735f2a459f05000000000000'), + 210000: b('2e3471a19b8e22b7f939c63663076603cf692f19837e34958b04000000000000'), + 216116: b('4edf231bf170234e6a811460f95c94af9464e41ee833b4f4b401000000000000'), + 225430: b('32595730b165f097e7b806a679cf7f3e439040f750433808c101000000000000'), + 250000: b('14d2f24d29bed75354f3f88a5fb50022fc064b02291fdf873800000000000000'), + 279000: b('407ebde958e44190fa9e810ea1fc3a7ef601c3b0a0728cae0100000000000000'), + 295000: b('83a93246c67003105af33ae0b29dd66f689d0f0ff54e9b4d0000000000000000'), + 300255: b('b2f3a0f0de4120c1089d5f5280a263059f9b6e7c520428160000000000000000'), + 319400: b('3bf115fd057391587ca39a531c5d4989e1adec9b2e05c6210000000000000000'), + 343185: b('548536d48e7678fcfa034202dd45d4a76b1ad061f38b2b070000000000000000'), + 352940: b('ffc9520143e41c94b6e03c2fa3e62bb76b55ba2df45d75100000000000000000'), + 382320: b('b28afdde92b0899715e40362f56afdb20e3d135bedc68d0a0000000000000000'), + 401465: b('eed16cb3e893ed9366f27c39a9ecd95465d02e3ef40e45010000000000000000'), + 420000: b('a1ff746b2d42b834cb7d6b8981b09c265c2cabc016e8cc020000000000000000'), + 440000: b('9bf296b8de5f834f7635d5e258a434ad51b4dbbcf7c08c030000000000000000'), + 450000: b('0ba2070c62cd9da1f8cef88a0648c661a411d33e728340010000000000000000'), + 460000: b('8c25fc7e414d3e868d6ce0ec473c30ad44e7e8bc1b75ef000000000000000000'), + 470000: b('89756d1ed75901437300af10d5ab69070a282e729c536c000000000000000000'), + 480000: b('b1a896fd31e639e0c74d1abeb1dbc93f176b767a5d4c02010000000000000000'), + 490000: b('90dec4d0153f20fbdcb245b1d5fb3d5a8d7bb1379106de000000000000000000'), + 500000: b('045d94a1c33354c3759cc0512dcc49fd81bf4c3637fb24000000000000000000'), + 510000: b('297301b8ca28584cb0c31c7e3fed51696bc33ef8782615000000000000000000'), + 525000: b('1dde8e3fb49bbd5ab66a1b847544d67fff10b108a1fa2f000000000000000000') }; /** @@ -131,10 +139,11 @@ main.halvingInterval = 210000; main.genesis = { version: 1, - hash: '6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000', - prevBlock: '0000000000000000000000000000000000000000000000000000000000000000', + hash: b('6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000'), + prevBlock: + b('0000000000000000000000000000000000000000000000000000000000000000'), merkleRoot: - '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', + b('3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a'), time: 1231006505, bits: 486604799, nonce: 2083236893, @@ -252,7 +261,8 @@ main.block = { * Hash of the block that activated bip34. */ - bip34hash: 'b808089c756add1591b1d17bab44bba3fed9e02f942ab4894b02000000000000', + bip34hash: + b('b808089c756add1591b1d17bab44bba3fed9e02f942ab4894b02000000000000'), /** * Height at which bip65 was activated. @@ -264,7 +274,8 @@ main.block = { * Hash of the block that activated bip65. */ - bip65hash: 'f035476cfaeb9f677c2cdad00fd908c556775ded24b6c2040000000000000000', + bip65hash: + b('f035476cfaeb9f677c2cdad00fd908c556775ded24b6c2040000000000000000'), /** * Height at which bip66 was activated. @@ -276,7 +287,8 @@ main.block = { * Hash of the block that activated bip66. */ - bip66hash: '3109b588941188a9f1c2576aae462d729b8cce9da1ea79030000000000000000', + bip66hash: + b('3109b588941188a9f1c2576aae462d729b8cce9da1ea79030000000000000000'), /** * Safe height to start pruning. @@ -314,8 +326,8 @@ main.block = { */ main.bip30 = { - 91842: 'eccae000e3c8e4e093936360431f3b7603c563c1ff6181390a4d0a0000000000', - 91880: '21d77ccb4c08386a04ac0196ae10f6a1d2c2a377558ca190f143070000000000' + 91842: b('eccae000e3c8e4e093936360431f3b7603c563c1ff6181390a4d0a0000000000'), + 91880: b('21d77ccb4c08386a04ac0196ae10f6a1d2c2a377558ca190f143070000000000') }; /** @@ -508,39 +520,40 @@ testnet.magic = 0x0709110b; testnet.port = 18333; testnet.checkpointMap = { - 546: '70cb6af7ebbcb1315d3414029c556c55f3e2fc353c4c9063a76c932a00000000', - 10000: '02a1b43f52591e53b660069173ac83b675798e12599dbb0442b7580000000000', - 50000: '0c6ceabe803cec55ba2831e445956d0a43ba9521743a802cddac7e0700000000', - 90000: 'cafc21e17faf90461a5905aa03302c394912651ed9475ae711723e0d00000000', - 100000: '1e0a16bbadccde1d80c66597b1939e45f91b570d29f95fc158299e0000000000', - 140000: '92c0877b54c556889b72175ccbe0c91a1208f6ef7efb2c006101062300000000', - 170000: '508125560d202b89757889bb0e49c712477be20440058f05db4f0e0000000000', - 210000: '32365454b5f29a826bff8ad9b0448cad0072fc73d50e482d91a3dece00000000', - 230000: 'b11a447e62643e0b27406eb0fc270cb8126d7b5b70822fb642d9513400000000', - 270000: '1c42b811cf9c163932f6e95ec55bf9b5e2cb5324e7e93001572e000000000000', - 300000: 'a141bf3972424853f04367b47995e220e0b5a2706e5618766f22000000000000', - 340000: '67edd4d92e405608109164b15f92b193377d49325b0ed036739c010000000000', - 350000: '592b44bc0f7a4286cf07ead8497114c6952c1c7dea7305193deacf8e00000000', - 390000: 'f217e183484fb6d695609cc71fa2ae24c3020943407e0150b298030000000000', - 420000: 'de9e73a3b91fbb014e036e8583a17d6b638a699aeb2de8573d12580800000000', - 460000: '2e8baaffc107f15c87aebe01664b63d07476afa53bcbada1281a030000000000', - 500000: '06f60922a2aab2757317820fc6ffaf6a470e2cbb0f63a2aac0a7010000000000', - 540000: '8dd0bebfbc4878f5af09d3e848dcc57827d2c1cebea8ec5d8cbe420500000000', - 570000: '87acbd4cd3c40ec9bd648f8698ed226b31187274c06cc7a9af79030000000000', - 600000: '169a05b3bb04b7d13ad628915630900a5ed2e89f3a9dc6064f62000000000000', - 630000: 'bbbe117035432a6a4effcb297207a02b031735b43e0d19a9217c000000000000', - 670000: '080bfe75caed8624fcfdfbc65973c8f962d7bdc495a891f5d16b7d0000000000', - 700000: 'c14d3f6a1e7c7d66fd940951e44f3c3be1273bea4d2ab1786140000000000000', - 740000: 'b3b423f0462fd78a01e4f1a59a2737a0525b5dbb9bba0b4634f9000000000000', - 780000: '0381582e34c3755964dc2813e2b33e521e5596367144e1670851050000000000', - 800000: '03b5f8ab257e02903f509f5ff2935220eec2e77b1819651d099b200000000000', - 840000: 'dac1648107bd4394e57e4083c86d42b548b1cfb119665f179ea80a0000000000', - 880000: 'ff90b4bb07eded8e96715bf595c09c7d21dd8c61b8306ff48705d60000000000', - 900000: '9bd8ac418beeb1a2cf5d68c8b5c6ebaa947a5b766e5524898d6f350000000000', - 940000: 'c98f1651a475b00d12f8c25eb166ee843affaa90610e36a19d68030000000000', - 980000: 'cc8e9774542d044a9698ca2336ae02d5987157e676f1c76aa3877c0000000000', - 1010000: '9d9fb11abc2712d80368229e97b8d827b2a07d27eb5335e5c924000000000000', - 1050000: 'd8190cf0af7f08e179cab51d67db0b44b87951a78f7fdc31b4a01a0000000000' + 546: b('70cb6af7ebbcb1315d3414029c556c55f3e2fc353c4c9063a76c932a00000000'), + 10000: b('02a1b43f52591e53b660069173ac83b675798e12599dbb0442b7580000000000'), + 50000: b('0c6ceabe803cec55ba2831e445956d0a43ba9521743a802cddac7e0700000000'), + 90000: b('cafc21e17faf90461a5905aa03302c394912651ed9475ae711723e0d00000000'), + 100000: b('1e0a16bbadccde1d80c66597b1939e45f91b570d29f95fc158299e0000000000'), + 140000: b('92c0877b54c556889b72175ccbe0c91a1208f6ef7efb2c006101062300000000'), + 170000: b('508125560d202b89757889bb0e49c712477be20440058f05db4f0e0000000000'), + 210000: b('32365454b5f29a826bff8ad9b0448cad0072fc73d50e482d91a3dece00000000'), + 230000: b('b11a447e62643e0b27406eb0fc270cb8126d7b5b70822fb642d9513400000000'), + 270000: b('1c42b811cf9c163932f6e95ec55bf9b5e2cb5324e7e93001572e000000000000'), + 300000: b('a141bf3972424853f04367b47995e220e0b5a2706e5618766f22000000000000'), + 340000: b('67edd4d92e405608109164b15f92b193377d49325b0ed036739c010000000000'), + 350000: b('592b44bc0f7a4286cf07ead8497114c6952c1c7dea7305193deacf8e00000000'), + 390000: b('f217e183484fb6d695609cc71fa2ae24c3020943407e0150b298030000000000'), + 420000: b('de9e73a3b91fbb014e036e8583a17d6b638a699aeb2de8573d12580800000000'), + 460000: b('2e8baaffc107f15c87aebe01664b63d07476afa53bcbada1281a030000000000'), + 500000: b('06f60922a2aab2757317820fc6ffaf6a470e2cbb0f63a2aac0a7010000000000'), + 540000: b('8dd0bebfbc4878f5af09d3e848dcc57827d2c1cebea8ec5d8cbe420500000000'), + 570000: b('87acbd4cd3c40ec9bd648f8698ed226b31187274c06cc7a9af79030000000000'), + 600000: b('169a05b3bb04b7d13ad628915630900a5ed2e89f3a9dc6064f62000000000000'), + 630000: b('bbbe117035432a6a4effcb297207a02b031735b43e0d19a9217c000000000000'), + 670000: b('080bfe75caed8624fcfdfbc65973c8f962d7bdc495a891f5d16b7d0000000000'), + 700000: b('c14d3f6a1e7c7d66fd940951e44f3c3be1273bea4d2ab1786140000000000000'), + 740000: b('b3b423f0462fd78a01e4f1a59a2737a0525b5dbb9bba0b4634f9000000000000'), + 780000: b('0381582e34c3755964dc2813e2b33e521e5596367144e1670851050000000000'), + 800000: b('03b5f8ab257e02903f509f5ff2935220eec2e77b1819651d099b200000000000'), + 840000: b('dac1648107bd4394e57e4083c86d42b548b1cfb119665f179ea80a0000000000'), + 880000: b('ff90b4bb07eded8e96715bf595c09c7d21dd8c61b8306ff48705d60000000000'), + 900000: b('9bd8ac418beeb1a2cf5d68c8b5c6ebaa947a5b766e5524898d6f350000000000'), + 940000: b('c98f1651a475b00d12f8c25eb166ee843affaa90610e36a19d68030000000000'), + 980000: b('cc8e9774542d044a9698ca2336ae02d5987157e676f1c76aa3877c0000000000'), + 1010000: + b('9d9fb11abc2712d80368229e97b8d827b2a07d27eb5335e5c924000000000000'), + 1050000: b('d8190cf0af7f08e179cab51d67db0b44b87951a78f7fdc31b4a01a0000000000') }; testnet.lastCheckpoint = 1050000; @@ -549,10 +562,11 @@ testnet.halvingInterval = 210000; testnet.genesis = { version: 1, - hash: '43497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000', - prevBlock: '0000000000000000000000000000000000000000000000000000000000000000', + hash: b('43497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000'), + prevBlock: + b('0000000000000000000000000000000000000000000000000000000000000000'), merkleRoot: - '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', + b('3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a'), time: 1296688602, bits: 486604799, nonce: 414098458, @@ -589,11 +603,14 @@ testnet.pow = { testnet.block = { bip34height: 21111, - bip34hash: 'f88ecd9912d00d3f5c2a8e0f50417d3e415c75b3abe584346da9b32300000000', + bip34hash: + b('f88ecd9912d00d3f5c2a8e0f50417d3e415c75b3abe584346da9b32300000000'), bip65height: 581885, - bip65hash: 'b61e864fbec41dfaf09da05d1d76dc068b0dd82ee7982ff255667f0000000000', + bip65hash: + b('b61e864fbec41dfaf09da05d1d76dc068b0dd82ee7982ff255667f0000000000'), bip66height: 330776, - bip66hash: '82a14b9e5ea81d4832b8e2cd3c2a6092b5a3853285a8995ec4c8042100000000', + bip66hash: + b('82a14b9e5ea81d4832b8e2cd3c2a6092b5a3853285a8995ec4c8042100000000'), pruneAfterHeight: 1000, keepBlocks: 10000, maxTipAge: 24 * 60 * 60, @@ -712,10 +729,11 @@ regtest.halvingInterval = 150; regtest.genesis = { version: 1, - hash: '06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f', - prevBlock: '0000000000000000000000000000000000000000000000000000000000000000', + hash: b('06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f'), + prevBlock: + b('0000000000000000000000000000000000000000000000000000000000000000'), merkleRoot: - '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', + b('3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a'), time: 1296688602, bits: 545259519, nonce: 2, @@ -876,10 +894,12 @@ simnet.halvingInterval = 210000; simnet.genesis = { version: 1, - hash: 'f67ad7695d9b662a72ff3d8edbbb2de0bfa67b13974bb9910d116d5cbd863e68', - prevBlock: '0000000000000000000000000000000000000000000000000000000000000000', + hash: + b('f67ad7695d9b662a72ff3d8edbbb2de0bfa67b13974bb9910d116d5cbd863e68'), + prevBlock: + b('0000000000000000000000000000000000000000000000000000000000000000'), merkleRoot: - '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a', + b('3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a'), time: 1401292357, bits: 545259519, nonce: 2, @@ -917,11 +937,14 @@ simnet.pow = { simnet.block = { bip34height: 0, - bip34hash: 'f67ad7695d9b662a72ff3d8edbbb2de0bfa67b13974bb9910d116d5cbd863e68', + bip34hash: + b('f67ad7695d9b662a72ff3d8edbbb2de0bfa67b13974bb9910d116d5cbd863e68'), bip65height: 0, - bip65hash: 'f67ad7695d9b662a72ff3d8edbbb2de0bfa67b13974bb9910d116d5cbd863e68', + bip65hash: + b('f67ad7695d9b662a72ff3d8edbbb2de0bfa67b13974bb9910d116d5cbd863e68'), bip66height: 0, - bip66hash: 'f67ad7695d9b662a72ff3d8edbbb2de0bfa67b13974bb9910d116d5cbd863e68', + bip66hash: + b('f67ad7695d9b662a72ff3d8edbbb2de0bfa67b13974bb9910d116d5cbd863e68'), pruneAfterHeight: 1000, keepBlocks: 10000, maxTipAge: 0xffffffff, diff --git a/lib/script/script.js b/lib/script/script.js index 7f2290330..8506949ce 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -3270,7 +3270,7 @@ class Script { */ fromRaw(data) { - const br = bio.read(data, true); + const br = bio.read(data); this.raw = data; diff --git a/lib/script/sigcache.js b/lib/script/sigcache.js index 2fe96aa5e..a8bb148b2 100644 --- a/lib/script/sigcache.js +++ b/lib/script/sigcache.js @@ -7,6 +7,7 @@ 'use strict'; const assert = require('assert'); +const {BufferMap} = require('buffer-map'); const secp256k1 = require('bcrypto/lib/secp256k1'); /** @@ -32,7 +33,7 @@ class SigCache { this.size = size; this.keys = []; - this.valid = new Map(); + this.valid = new BufferMap(); } /** @@ -51,37 +52,37 @@ class SigCache { /** * Add item to the sigcache. * Potentially evict a random member. - * @param {Hash} hash - Sig hash. + * @param {Hash} msg - Sig hash. * @param {Buffer} sig * @param {Buffer} key */ - add(hash, sig, key) { + add(msg, sig, key) { if (this.size === 0) return; - this.valid.set(hash, new SigCacheEntry(sig, key)); + this.valid.set(msg, new SigCacheEntry(sig, key)); if (this.keys.length >= this.size) { const i = Math.floor(Math.random() * this.keys.length); const k = this.keys[i]; this.valid.delete(k); - this.keys[i] = hash; + this.keys[i] = msg; } else { - this.keys.push(hash); + this.keys.push(msg); } } /** * Test whether the sig exists. - * @param {Hash} hash - Sig hash. + * @param {Hash} msg - Sig hash. * @param {Buffer} sig * @param {Buffer} key * @returns {Boolean} */ - has(hash, sig, key) { - const entry = this.valid.get(hash); + has(msg, sig, key) { + const entry = this.valid.get(msg); if (!entry) return false; @@ -102,9 +103,7 @@ class SigCache { if (this.size === 0) return secp256k1.verifyDER(msg, sig, key); - const hash = msg.toString('hex'); - - if (this.has(hash, sig, key)) + if (this.has(msg, sig, key)) return true; const result = secp256k1.verifyDER(msg, sig, key); @@ -112,7 +111,7 @@ class SigCache { if (!result) return false; - this.add(hash, sig, key); + this.add(msg, sig, key); return true; } diff --git a/lib/utils/util.js b/lib/utils/util.js index a43ce46aa..4c15b9cf2 100644 --- a/lib/utils/util.js +++ b/lib/utils/util.js @@ -100,7 +100,20 @@ util.time = function time(date) { * @returns {String} Reversed hex string. */ -util.revHex = function revHex(str) { +util.revHex = function revHex(buf) { + assert(Buffer.isBuffer(buf)); + + const str = buf.toString('hex'); + + let out = ''; + + for (let i = str.length - 2; i >= 0; i -= 2) + out += str[i] + str[i + 1]; + + return out; +}; + +util.fromRev = function fromRev(str) { assert(typeof str === 'string'); assert((str.length & 1) === 0); @@ -109,5 +122,5 @@ util.revHex = function revHex(str) { for (let i = str.length - 2; i >= 0; i -= 2) out += str[i] + str[i + 1]; - return out; + return Buffer.from(out, 'hex'); }; diff --git a/lib/wallet/account.js b/lib/wallet/account.js index d0f737a47..26547d1c0 100644 --- a/lib/wallet/account.js +++ b/lib/wallet/account.js @@ -296,7 +296,7 @@ class Account { return false; const ring = this.deriveReceive(0); - const hash = ring.getScriptHash('hex'); + const hash = ring.getScriptHash(); return this.wdb.hasPath(this.wid, hash); } diff --git a/lib/wallet/client.js b/lib/wallet/client.js index 1bdd52a3a..382c31d02 100644 --- a/lib/wallet/client.js +++ b/lib/wallet/client.js @@ -57,7 +57,7 @@ class WalletClient extends NodeClient { } async getEntry(block) { - if (typeof block === 'string') + if (Buffer.isBuffer(block)) block = util.revHex(block); return parseEntry(await super.getEntry(block)); @@ -72,7 +72,7 @@ class WalletClient extends NodeClient { } async rescan(start) { - if (typeof start === 'string') + if (Buffer.isBuffer(start)) start = util.revHex(start); return super.rescan(start); @@ -87,10 +87,10 @@ function parseEntry(data) { assert(Buffer.isBuffer(data)); assert(data.length >= 84); - const h = hash256.digest(data.slice(0, 80)); + const hash = hash256.digest(data.slice(0, 80)); return { - hash: h.toString('hex'), + hash: hash, height: data.readUInt32LE(80, true), time: data.readUInt32LE(68, true) }; diff --git a/lib/wallet/common.js b/lib/wallet/common.js index 549acc093..01a7c209a 100644 --- a/lib/wallet/common.js +++ b/lib/wallet/common.js @@ -6,6 +6,8 @@ 'use strict'; +const {BufferMap} = require('buffer-map'); + /** * @exports wallet/common */ @@ -81,15 +83,15 @@ common.sortCoins = function sortCoins(coins) { */ common.sortDeps = function sortDeps(txs) { - const map = new Map(); + const map = new BufferMap(); for (const tx of txs) { - const hash = tx.hash('hex'); + const hash = tx.hash(); map.set(hash, tx); } - const depMap = new Map(); - const depCount = new Map(); + const depMap = new BufferMap(); + const depCount = new BufferMap(); const top = []; for (const [hash, tx] of map) { @@ -122,8 +124,7 @@ common.sortDeps = function sortDeps(txs) { const result = []; for (const tx of top) { - const hash = tx.hash('hex'); - const deps = depMap.get(hash); + const deps = depMap.get(tx.hash()); result.push(tx); @@ -131,14 +132,12 @@ common.sortDeps = function sortDeps(txs) { continue; for (const tx of deps) { - const hash = tx.hash('hex'); - - let count = depCount.get(hash); + let count = depCount.get(tx.hash()); if (--count === 0) top.push(tx); - depCount.set(hash, count); + depCount.set(tx.hash(), count); } } diff --git a/lib/wallet/http.js b/lib/wallet/http.js index 7c3edd689..99eacf441 100644 --- a/lib/wallet/http.js +++ b/lib/wallet/http.js @@ -455,7 +455,7 @@ class HTTP extends Server { const tx = await req.wallet.send(options, passphrase); - const details = await req.wallet.getDetails(tx.hash('hex')); + const details = await req.wallet.getDetails(tx.hash()); res.json(200, details.toJSON(this.network, this.wdb.height)); }); @@ -536,7 +536,7 @@ class HTTP extends Server { // Abandon Wallet TX this.del('/wallet/:id/tx/:hash', async (req, res) => { const valid = Validator.fromRequest(req); - const hash = valid.rhash('hash'); + const hash = valid.brhash('hash'); enforce(hash, 'Hash is required.'); @@ -711,7 +711,7 @@ class HTTP extends Server { // Lock coin this.put('/wallet/:id/locked/:hash/:index', async (req, res) => { const valid = Validator.fromRequest(req); - const hash = valid.rhash('hash'); + const hash = valid.brhash('hash'); const index = valid.u32('index'); enforce(hash, 'Hash is required.'); @@ -727,7 +727,7 @@ class HTTP extends Server { // Unlock coin this.del('/wallet/:id/locked/:hash/:index', async (req, res) => { const valid = Validator.fromRequest(req); - const hash = valid.rhash('hash'); + const hash = valid.brhash('hash'); const index = valid.u32('index'); enforce(hash, 'Hash is required.'); @@ -743,7 +743,7 @@ class HTTP extends Server { // Wallet Coin this.get('/wallet/:id/coin/:hash/:index', async (req, res) => { const valid = Validator.fromRequest(req); - const hash = valid.rhash('hash'); + const hash = valid.brhash('hash'); const index = valid.u32('index'); enforce(hash, 'Hash is required.'); @@ -834,7 +834,7 @@ class HTTP extends Server { // Wallet TX this.get('/wallet/:id/tx/:hash', async (req, res) => { const valid = Validator.fromRequest(req); - const hash = valid.rhash('hash'); + const hash = valid.brhash('hash'); enforce(hash, 'Hash is required.'); diff --git a/lib/wallet/layout.js b/lib/wallet/layout.js index dfaebf5df..2c0a66c6c 100644 --- a/lib/wallet/layout.js +++ b/lib/wallet/layout.js @@ -35,9 +35,9 @@ exports.wdb = { O: bdb.key('O'), R: bdb.key('R'), D: bdb.key('D'), - p: bdb.key('p', ['hash']), - P: bdb.key('P', ['uint32', 'hash']), - r: bdb.key('r', ['uint32', 'uint32', 'hash']), + p: bdb.key('p', ['bhash']), + P: bdb.key('P', ['uint32', 'bhash']), + r: bdb.key('r', ['uint32', 'uint32', 'bhash']), w: bdb.key('w', ['uint32']), W: bdb.key('W', ['uint32']), l: bdb.key('l', ['ascii']), @@ -46,8 +46,8 @@ exports.wdb = { n: bdb.key('n', ['uint32', 'uint32']), h: bdb.key('h', ['uint32']), b: bdb.key('b', ['uint32']), - o: bdb.key('o', ['hash256', 'uint32']), - T: bdb.key('T', ['hash256']), + o: bdb.key('o', ['bhash256', 'uint32']), + T: bdb.key('T', ['bhash256']), t: bdb.key('t', ['uint32']) }; @@ -74,17 +74,17 @@ exports.txdb = { prefix: bdb.key('t', ['uint32']), R: bdb.key('R'), r: bdb.key('r', ['uint32']), - t: bdb.key('t', ['hash256']), - c: bdb.key('c', ['hash256', 'uint32']), - d: bdb.key('d', ['hash256', 'uint32']), - s: bdb.key('s', ['hash256', 'uint32']), - p: bdb.key('p', ['hash256']), - m: bdb.key('m', ['uint32', 'hash256']), - h: bdb.key('h', ['uint32', 'hash256']), - T: bdb.key('T', ['uint32', 'hash256']), - P: bdb.key('P', ['uint32', 'hash256']), - M: bdb.key('M', ['uint32', 'uint32', 'hash256']), - H: bdb.key('H', ['uint32', 'uint32', 'hash256']), - C: bdb.key('C', ['uint32', 'hash256', 'uint32']), + t: bdb.key('t', ['bhash256']), + c: bdb.key('c', ['bhash256', 'uint32']), + d: bdb.key('d', ['bhash256', 'uint32']), + s: bdb.key('s', ['bhash256', 'uint32']), + p: bdb.key('p', ['bhash256']), + m: bdb.key('m', ['uint32', 'bhash256']), + h: bdb.key('h', ['uint32', 'bhash256']), + T: bdb.key('T', ['uint32', 'bhash256']), + P: bdb.key('P', ['uint32', 'bhash256']), + M: bdb.key('M', ['uint32', 'uint32', 'bhash256']), + H: bdb.key('H', ['uint32', 'uint32', 'bhash256']), + C: bdb.key('C', ['uint32', 'bhash256', 'uint32']), b: bdb.key('b', ['uint32']) }; diff --git a/lib/wallet/masterkey.js b/lib/wallet/masterkey.js index 1ed64d425..f0fdc8794 100644 --- a/lib/wallet/masterkey.js +++ b/lib/wallet/masterkey.js @@ -256,9 +256,6 @@ class MasterKey { if (!this.aesKey) return null; - if (typeof iv === 'string') - iv = Buffer.from(iv, 'hex'); - return aes.encipher(data, this.aesKey, iv.slice(0, 16)); } @@ -273,9 +270,6 @@ class MasterKey { if (!this.aesKey) return null; - if (typeof iv === 'string') - iv = Buffer.from(iv, 'hex'); - return aes.decipher(data, this.aesKey, iv.slice(0, 16)); } diff --git a/lib/wallet/path.js b/lib/wallet/path.js index 7e187cd24..d81bd010c 100644 --- a/lib/wallet/path.js +++ b/lib/wallet/path.js @@ -240,7 +240,7 @@ class Path { this.account = account.accountIndex; this.version = address.version; this.type = address.type; - this.hash = address.getHash('hex'); + this.hash = address.getHash(); return this; } diff --git a/lib/wallet/records.js b/lib/wallet/records.js index 24521467a..3c12075a0 100644 --- a/lib/wallet/records.js +++ b/lib/wallet/records.js @@ -28,7 +28,7 @@ class ChainState { constructor() { this.startHeight = 0; - this.startHash = consensus.NULL_HASH; + this.startHash = consensus.ZERO_HASH; this.height = 0; this.marked = false; } @@ -57,7 +57,7 @@ class ChainState { const br = bio.read(data); this.startHeight = br.readU32(); - this.startHash = br.readHash('hex'); + this.startHash = br.readHash(); this.height = br.readU32(); this.marked = br.readU8() === 1; @@ -106,7 +106,7 @@ class BlockMeta { */ constructor(hash, height, time) { - this.hash = hash || consensus.NULL_HASH; + this.hash = hash || consensus.ZERO_HASH; this.height = height != null ? height : -1; this.time = time || 0; } @@ -126,7 +126,7 @@ class BlockMeta { */ toHash() { - return Buffer.from(this.hash, 'hex'); + return this.hash; } /** @@ -163,7 +163,7 @@ class BlockMeta { fromRaw(data) { const br = bio.read(data); - this.hash = br.readHash('hex'); + this.hash = br.readHash(); this.height = br.readU32(); this.time = br.readU32(); return this; @@ -262,7 +262,7 @@ class TXRecord { fromTX(tx, block) { this.tx = tx; - this.hash = tx.hash('hex'); + this.hash = tx.hash(); if (block) this.setBlock(block); @@ -397,11 +397,11 @@ class TXRecord { this.tx = new TX(); this.tx.fromReader(br); - this.hash = this.tx.hash('hex'); + this.hash = this.tx.hash(); this.mtime = br.readU32(); if (br.readU8() === 1) { - this.block = br.readHash('hex'); + this.block = br.readHash(); this.height = br.readU32(); this.time = br.readU32(); this.index = br.readU32(); diff --git a/lib/wallet/rpc.js b/lib/wallet/rpc.js index 564dc4365..7fb7d267e 100644 --- a/lib/wallet/rpc.js +++ b/lib/wallet/rpc.js @@ -13,6 +13,7 @@ const {Lock} = require('bmutex'); const fs = require('bfile'); const Validator = require('bval'); const hash256 = require('bcrypto/lib/hash256'); +const {BufferMap, BufferSet} = require('buffer-map'); const util = require('../utils/util'); const Amount = require('../btc/amount'); const Script = require('../script/script'); @@ -520,7 +521,7 @@ class RPC extends RPCBase { name = 'default'; const paths = await wallet.getPaths(name); - const filter = new Set(); + const filter = new BufferSet(); for (const path of paths) filter.add(path.hash); @@ -540,7 +541,7 @@ class RPC extends RPCBase { lastConf = conf; for (const output of wtx.tx.outputs) { - const hash = output.getHash('hex'); + const hash = output.getHash(); if (hash && filter.has(hash)) total += output.value; } @@ -571,7 +572,7 @@ class RPC extends RPCBase { continue; for (const output of wtx.tx.outputs) { - if (output.getHash('hex') === hash) + if (output.getHash().equals(hash)) total += output.value; } } @@ -660,7 +661,7 @@ class RPC extends RPCBase { const wallet = this.wallet; const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); const watchOnly = valid.bool(1, false); if (!hash) @@ -680,7 +681,7 @@ class RPC extends RPCBase { const wallet = this.wallet; const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); @@ -950,7 +951,7 @@ class RPC extends RPCBase { const paths = await wallet.getPaths(); const height = this.wdb.state.height; - const map = new Map(); + const map = new BufferMap(); for (const path of paths) { const addr = path.toAddress(); map.set(path.hash, { @@ -977,7 +978,7 @@ class RPC extends RPCBase { if (!addr) continue; - const hash = addr.getHash('hex'); + const hash = addr.getHash(); const entry = map.get(hash); if (entry) { @@ -1031,7 +1032,7 @@ class RPC extends RPCBase { const wallet = this.wallet; const chainHeight = this.wdb.state.height; const valid = new Validator(args); - const block = valid.rhash(0); + const block = valid.brhash(0); const minconf = valid.u32(1, 0); const watchOnly = valid.bool(2, false); @@ -1078,7 +1079,7 @@ class RPC extends RPCBase { transactions: out, lastblock: highest && highest.block ? util.revHex(highest.block) - : consensus.NULL_HASH + : util.revHex(consensus.ZERO_HASH) }; } @@ -1217,7 +1218,7 @@ class RPC extends RPCBase { const addrs = valid.array(2); const height = this.wdb.state.height; - const map = new Set(); + const map = new BufferSet(); if (addrs) { const valid = new Validator(addrs); @@ -1249,7 +1250,7 @@ class RPC extends RPCBase { if (!addr) continue; - const hash = coin.getHash('hex'); + const hash = coin.getHash(); if (addrs) { if (!hash || !map.has(hash)) @@ -1299,7 +1300,7 @@ class RPC extends RPCBase { for (const output of outputs) { const valid = new Validator(output); - const hash = valid.rhash('txid'); + const hash = valid.brhash('txid'); const index = valid.u32('vout'); if (hash == null || index == null) @@ -1380,13 +1381,13 @@ class RPC extends RPCBase { throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); const to = new Validator(sendTo); - const uniq = new Set(); + const uniq = new BufferSet(); const outputs = []; for (const key of Object.keys(sendTo)) { const value = to.ufixed(key, 8); const addr = parseAddress(key, this.network); - const hash = addr.getHash('hex'); + const hash = addr.getHash(); if (value == null) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.'); @@ -1585,12 +1586,12 @@ class RPC extends RPCBase { const tx = TX.fromRaw(txRaw); const block = MerkleBlock.fromRaw(blockRaw); - const hash = block.hash('hex'); + const hash = block.hash(); if (!block.verify()) throw new RPCError(errs.VERIFY_ERROR, 'Invalid proof.'); - if (!block.hasTX(tx.hash('hex'))) + if (!block.hasTX(tx.hash())) throw new RPCError(errs.VERIFY_ERROR, 'Invalid proof.'); const height = await this.client.getEntry(hash); @@ -1616,7 +1617,7 @@ class RPC extends RPCBase { const wallet = this.wallet; const valid = new Validator(args); - const hash = valid.rhash(0); + const hash = valid.brhash(0); if (!hash) throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.'); @@ -1670,7 +1671,7 @@ class RPC extends RPCBase { function parseHash(raw, network) { const addr = parseAddress(raw, network); - return addr.getHash('hex'); + return addr.getHash(); } function parseAddress(raw, network) { diff --git a/lib/wallet/txdb.js b/lib/wallet/txdb.js index b809bf730..d90e4778b 100644 --- a/lib/wallet/txdb.js +++ b/lib/wallet/txdb.js @@ -9,6 +9,7 @@ const assert = require('assert'); const bio = require('bufio'); +const {BufferSet} = require('buffer-map'); const util = require('../utils/util'); const Amount = require('../btc/amount'); const CoinView = require('../coins/coinview'); @@ -40,7 +41,7 @@ class TXDB { this.wid = wid || 0; this.bucket = null; this.wallet = null; - this.locked = new Set(); + this.locked = new BufferSet(); } /** @@ -76,7 +77,7 @@ class TXDB { */ getPath(output) { - const hash = output.getHash('hex'); + const hash = output.getHash(); if (!hash) return null; @@ -91,7 +92,7 @@ class TXDB { */ hasPath(output) { - const hash = output.getHash('hex'); + const hash = output.getHash(); if (!hash) return false; @@ -413,7 +414,7 @@ class TXDB { */ async add(tx, block) { - const hash = tx.hash('hex'); + const hash = tx.hash(); const existing = await this.getTX(hash); assert(!tx.mutable, 'Cannot add mutable TX to wallet.'); @@ -1091,7 +1092,7 @@ class TXDB { if (tx.isCoinbase()) return true; - const txid = tx.hash('hex'); + const txid = tx.hash(); const spends = []; // Gather all spent records first. @@ -1105,7 +1106,7 @@ class TXDB { continue; // Did _we_ spend it? - if (spent.hash === txid) + if (spent.hash.equals(txid)) continue; const spender = await this.getTX(spent.hash); @@ -1617,7 +1618,7 @@ class TXDB { if (tx.isCoinbase()) return []; - const hash = tx.hash('hex'); + const hash = tx.hash(); const credits = []; for (let i = 0; i < tx.inputs.length; i++) @@ -2549,10 +2550,10 @@ class BlockRecord { */ constructor(hash, height, time) { - this.hash = hash || consensus.NULL_HASH; + this.hash = hash || consensus.ZERO_HASH; this.height = height != null ? height : -1; this.time = time || 0; - this.hashes = new Set(); + this.hashes = new BufferSet(); } /** @@ -2589,14 +2590,14 @@ class BlockRecord { fromRaw(data) { const br = bio.read(data); - this.hash = br.readHash('hex'); + this.hash = br.readHash(); this.height = br.readU32(); this.time = br.readU32(); const count = br.readU32(); for (let i = 0; i < count; i++) { - const hash = br.readHash('hex'); + const hash = br.readHash(); this.hashes.add(hash); } diff --git a/lib/wallet/wallet.js b/lib/wallet/wallet.js index 608b8fd53..3dfaff9d1 100644 --- a/lib/wallet/wallet.js +++ b/lib/wallet/wallet.js @@ -858,7 +858,7 @@ class Wallet extends EventEmitter { */ async hasAddress(address) { - const hash = Address.getHash(address, 'hex'); + const hash = Address.getHash(address); const path = await this.getPath(hash); return path != null; } @@ -870,7 +870,7 @@ class Wallet extends EventEmitter { */ async getPath(address) { - const hash = Address.getHash(address, 'hex'); + const hash = Address.getHash(address); return this.wdb.getPath(this.wid, hash); } @@ -882,7 +882,7 @@ class Wallet extends EventEmitter { */ async readPath(address) { - const hash = Address.getHash(address, 'hex'); + const hash = Address.getHash(address); return this.wdb.readPath(this.wid, hash); } @@ -893,7 +893,7 @@ class Wallet extends EventEmitter { */ async hasPath(address) { - const hash = Address.getHash(address, 'hex'); + const hash = Address.getHash(address); return this.wdb.hasPath(this.wid, hash); } @@ -979,7 +979,7 @@ class Wallet extends EventEmitter { throw new Error('Cannot import privkey into watch-only wallet.'); } - const hash = ring.getHash('hex'); + const hash = ring.getHash(); if (await this.getPath(hash)) throw new Error('Key already exists.'); @@ -1143,7 +1143,7 @@ class Wallet extends EventEmitter { */ async getAccountByAddress(address) { - const hash = Address.getHash(address, 'hex'); + const hash = Address.getHash(address); const path = await this.getPath(hash); if (!path) @@ -1504,7 +1504,7 @@ class Wallet extends EventEmitter { */ async getKey(address) { - const hash = Address.getHash(address, 'hex'); + const hash = Address.getHash(address); const path = await this.getPath(hash); if (!path) @@ -1527,7 +1527,7 @@ class Wallet extends EventEmitter { */ async getPrivateKey(address, passphrase) { - const hash = Address.getHash(address, 'hex'); + const hash = Address.getHash(address); const path = await this.getPath(hash); if (!path) @@ -1560,7 +1560,7 @@ class Wallet extends EventEmitter { if (!mtx.hasCoins()) throw new Error('Not all coins available.'); - const hashes = mtx.getInputHashes('hex'); + const hashes = mtx.getInputHashes(); const paths = []; for (const hash of hashes) { @@ -1580,7 +1580,7 @@ class Wallet extends EventEmitter { async getOutputPaths(tx) { const paths = []; - const hashes = tx.getOutputHashes('hex'); + const hashes = tx.getOutputHashes(); for (const hash of hashes) { const path = await this.getPath(hash); @@ -1637,7 +1637,7 @@ class Wallet extends EventEmitter { async syncOutputDepth(tx) { const map = new Map(); - for (const hash of tx.getOutputHashes('hex')) { + for (const hash of tx.getOutputHashes()) { const path = await this.readPath(hash); if (!path) diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index ab95c65f3..4bd20e39f 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -264,7 +264,7 @@ class WalletDB extends EventEmitter { await piter.each((key) => { const data = layout.p.parse(key); - this.filter.add(data, 'hex'); + this.filter.add(data); hashes += 1; }); @@ -620,7 +620,7 @@ class WalletDB extends EventEmitter { */ testFilter(data) { - return this.filter.test(data, 'hex'); + return this.filter.test(data); } /** @@ -630,7 +630,7 @@ class WalletDB extends EventEmitter { */ addHash(hash) { - this.filter.add(hash, 'hex'); + this.filter.add(hash); return this.addFilter(hash); } @@ -1409,8 +1409,7 @@ class WalletDB extends EventEmitter { assert(!path.encrypted); - const bhash = Buffer.from(hash, 'hex'); - const iv = bhash.slice(0, 16); + const iv = hash.slice(0, 16); path.data = aes.encipher(path.data, key, iv); path.encrypted = true; @@ -1442,8 +1441,7 @@ class WalletDB extends EventEmitter { assert(path.encrypted); - const bhash = Buffer.from(hash, 'hex'); - const iv = bhash.slice(0, 16); + const iv = hash.slice(0, 16); path.data = aes.decipher(path.data, key, iv); path.encrypted = false; @@ -1541,7 +1539,7 @@ class WalletDB extends EventEmitter { } } - const hashes = tx.getOutputHashes('hex'); + const hashes = tx.getOutputHashes(); for (const hash of hashes) { if (!this.testFilter(hash)) @@ -1845,7 +1843,7 @@ class WalletDB extends EventEmitter { return null; const block = new BlockMeta(); - block.hash = data.toString('hex'); + block.hash = data; block.height = height; return block; diff --git a/lib/wallet/walletkey.js b/lib/wallet/walletkey.js index 36a0bbee6..3ebd29dd7 100644 --- a/lib/wallet/walletkey.js +++ b/lib/wallet/walletkey.js @@ -174,7 +174,7 @@ class WalletKey extends KeyRing { path.version = this.getVersion(); path.type = this.getType(); - path.hash = this.getHash('hex'); + path.hash = this.getHash(); return path; } diff --git a/migrate/chaindb2to3.js b/migrate/chaindb2to3.js index 011b61e1c..2357a7d2d 100644 --- a/migrate/chaindb2to3.js +++ b/migrate/chaindb2to3.js @@ -21,6 +21,7 @@ const hash256 = require('bcrypto/lib/hash256'); const BN = require('bn.js'); const bio = require('bufio'); const LRU = require('blru'); +const {BufferMap} = require('buffer-map'); const util = require('../lib/utils/util'); const OldCoins = require('./coins/coins'); const OldUndoCoins = require('./coins/undocoins'); @@ -53,18 +54,18 @@ const STATE_ENTRY = 3; const STATE_FINAL = 4; const STATE_DONE = 5; -const metaCache = new Map(); -const lruCache = new LRU(200000); +const metaCache = new BufferMap(); +const lruCache = new LRU(200000, null, BufferMap); function writeJournal(batch, state, hash) { const data = Buffer.allocUnsafe(34); if (!hash) - hash = consensus.NULL_HASH; + hash = consensus.ZERO_HASH; data[0] = MIGRATION_ID; data[1] = state; - data.write(hash, 2, 'hex'); + hash.copy(data, 2); batch.put(JOURNAL_KEY, data); } @@ -73,7 +74,7 @@ async function readJournal() { const data = await db.get(JOURNAL_KEY); if (!data) - return [STATE_VERSION, consensus.NULL_HASH]; + return [STATE_VERSION, consensus.ZERO_HASH]; if (data.length !== 34) throw new Error('Bad migration length.'); @@ -82,7 +83,7 @@ async function readJournal() { throw new Error('Bad migration id.'); const state = data.readUInt8(1, true); - const hash = data.toString('hex', 2, 34); + const hash = data.slice(2, 34); console.log('Reading journal.'); console.log('Recovering from state %d.', state); @@ -118,7 +119,7 @@ async function updateVersion() { await batch.write(); - return [STATE_UNDO, consensus.NULL_HASH]; + return [STATE_UNDO, consensus.ZERO_HASH]; } async function reserializeUndo(hash) { @@ -126,7 +127,7 @@ async function reserializeUndo(hash) { const height = tip.height; - if (hash !== consensus.NULL_HASH) + if (!hash.equals(consensus.ZERO_HASH)) tip = await getEntry(hash); console.log('Reserializing undo coins from tip %s.', @@ -254,12 +255,12 @@ async function reserializeUndo(hash) { 'Reserialized %d undo records (%d coins).', total, totalCoins); - return [STATE_CLEANUP, consensus.NULL_HASH]; + return [STATE_CLEANUP, consensus.ZERO_HASH]; } async function cleanupIndex() { if (hasSPV) - return [STATE_COINS, consensus.NULL_HASH]; + return [STATE_COINS, consensus.ZERO_HASH]; const iter = db.iterator({ gte: pair(0x01, consensus.ZERO_HASH), @@ -290,12 +291,12 @@ async function cleanupIndex() { console.log('Cleaned up %d undo records.', total); - return [STATE_COINS, consensus.NULL_HASH]; + return [STATE_COINS, consensus.ZERO_HASH]; } async function reserializeCoins(hash) { if (hasSPV) - return [STATE_ENTRY, consensus.NULL_HASH]; + return [STATE_ENTRY, consensus.ZERO_HASH]; const iter = db.iterator({ gte: pair('c', hash), @@ -306,7 +307,7 @@ async function reserializeCoins(hash) { let start = true; - if (hash !== consensus.NULL_HASH) { + if (!hash.equals(consensus.ZERO_HASH)) { const item = await iter.next(); if (!item) start = false; @@ -326,7 +327,7 @@ async function reserializeCoins(hash) { if (item.key.length !== 33) continue; - const hash = item.key.toString('hex', 1, 33); + const hash = item.key.slice(1, 33); const old = OldCoins.fromRaw(item.value, hash); let update = false; @@ -367,7 +368,7 @@ async function reserializeCoins(hash) { console.log('Reserialized %d coins.', total); - return [STATE_ENTRY, consensus.NULL_HASH]; + return [STATE_ENTRY, consensus.ZERO_HASH]; } async function reserializeEntries(hash) { @@ -379,7 +380,7 @@ async function reserializeEntries(hash) { let start = true; - if (hash !== consensus.NULL_HASH) { + if (!hash.equals(consensus.ZERO_HASH)) { const item = await iter.next(); if (!item) start = false; @@ -418,7 +419,7 @@ async function reserializeEntries(hash) { console.log('Reserialized %d entries.', total); - return [STATE_FINAL, consensus.NULL_HASH]; + return [STATE_FINAL, consensus.ZERO_HASH]; } async function finalize() { @@ -454,7 +455,7 @@ async function finalize() { await db.compactRange(); - return [STATE_DONE, consensus.NULL_HASH]; + return [STATE_DONE, consensus.ZERO_HASH]; } async function getMeta(coin, prevout) { @@ -538,7 +539,7 @@ async function getTip() { async function getTipHash() { const state = await db.get('R'); assert(state); - return state.toString('hex', 0, 32); + return state.slice(0, 32); } async function getEntry(hash) { @@ -566,7 +567,7 @@ async function isIndexed() { } async function isMainChain(entry, tip) { - if (entry.hash === tip) + if (entry.hash.equals(tip)) return true; if (await db.get(pair('n', entry.hash))) @@ -582,10 +583,10 @@ function entryFromRaw(data) { br.seek(-80); const entry = {}; - entry.hash = hash.toString('hex'); + entry.hash = hash.toString(); entry.version = br.readU32(); - entry.prevBlock = br.readHash('hex'); - entry.merkleRoot = br.readHash('hex'); + entry.prevBlock = br.readHash(); + entry.merkleRoot = br.readHash(); entry.time = br.readU32(); entry.bits = br.readU32(); entry.nonce = br.readU32(); @@ -611,10 +612,9 @@ function entryToRaw(entry, main) { return bw.render(); } -function write(data, str, off) { - if (Buffer.isBuffer(str)) - return str.copy(data, off); - return data.write(str, off, 'hex'); +function write(data, hash, off) { + assert(Buffer.isBuffer(hash)); + return hash.copy(data, off); } function pair(prefix, hash) { @@ -682,7 +682,7 @@ reserializeEntries; // [state, hash] = await reserializeEntries(hash); if (state === STATE_ENTRY) - [state, hash] = [STATE_FINAL, consensus.NULL_HASH]; + [state, hash] = [STATE_FINAL, consensus.ZERO_HASH]; if (state === STATE_FINAL) [state, hash] = await finalize(); diff --git a/migrate/coins/coins.js b/migrate/coins/coins.js index 5e8b6c868..401992697 100644 --- a/migrate/coins/coins.js +++ b/migrate/coins/coins.js @@ -37,7 +37,7 @@ function Coins(options) { return new Coins(options); this.version = 1; - this.hash = encoding.NULL_HASH; + this.hash = encoding.ZERO_HASH; this.height = -1; this.coinbase = true; this.outputs = []; @@ -59,7 +59,7 @@ Coins.prototype.fromOptions = function fromOptions(options) { } if (options.hash) { - assert(typeof options.hash === 'string'); + assert(Buffer.isBuffer(options.hash)); this.hash = options.hash; } @@ -562,7 +562,7 @@ Coins.prototype.fromTX = function fromTX(tx, height) { assert(typeof height === 'number'); this.version = tx.version; - this.hash = tx.hash('hex'); + this.hash = tx.hash(); this.height = height; this.coinbase = tx.isCoinbase(); diff --git a/migrate/coins/coinview.js b/migrate/coins/coinview.js index 91b9e4257..8d27a08aa 100644 --- a/migrate/coins/coinview.js +++ b/migrate/coins/coinview.js @@ -9,6 +9,7 @@ 'use strict'; const assert = require('assert'); +const {BufferMap} = require('buffer-map'); const Coins = require('./coins'); const UndoCoins = require('./undocoins'); const CoinEntry = Coins.CoinEntry; @@ -26,7 +27,7 @@ function CoinView() { if (!(this instanceof CoinView)) return new CoinView(); - this.map = new Map(); + this.map = new BufferMap(); this.undo = new UndoCoins(); } diff --git a/migrate/walletdb5to6.js b/migrate/walletdb5to6.js index 3757ef647..ac584fb52 100644 --- a/migrate/walletdb5to6.js +++ b/migrate/walletdb5to6.js @@ -89,7 +89,7 @@ async function indexPaths() { for (let i = 0; i < items.length; i++) { const item = items[i]; const wid = item.key.readUInt32BE(1, true); - const hash = item.key.toString('hex', 5); + const hash = item.key.slice(5); const index = item.value.readUInt32LE(0, true); console.log('r[%d][%d][%s] -> NUL', wid, index, hash); batch.put(r(wid, index, hash), Buffer.from([0])); @@ -104,7 +104,7 @@ async function patchPathMaps() { for (let i = 0; i < items.length; i++) { const item = items[i]; - const hash = item.key.toString('hex', 1); + const hash = item.key.slice(1); const wids = parseWallets(item.value); console.log('p[%s] -> u32(%d)', hash, wids.length); batch.put(item.key, serializeWallets(wids)); @@ -200,7 +200,7 @@ function r(wid, index, hash) { key[0] = 0x72; key.writeUInt32BE(wid, 1, true); key.writeUInt32BE(index, 5, true); - key.write(hash, 9, 'hex'); + hash.copy(key, 9); return key; } diff --git a/migrate/walletdb6to7.js b/migrate/walletdb6to7.js index ff7a954fd..127048e8b 100644 --- a/migrate/walletdb6to7.js +++ b/migrate/walletdb6to7.js @@ -689,7 +689,7 @@ class BlockMapRecord { const count = br.readU32(); for (let i = 0; i < count; i++) { - const hash = br.readHash('hex'); + const hash = br.readHash(); const tx = TXMapRecord.fromReader(hash, br); this.txs.set(tx.hash, tx); } @@ -863,13 +863,13 @@ function serializeBalance(bal) { function parsep(key) { // p[hash] assert(Buffer.isBuffer(key)); assert(key.length >= 21); - return [key.toString('hex', 1)]; + return [key.slice(1)]; } function parseP(key) { // P[wid][hash] assert(Buffer.isBuffer(key)); assert(key.length >= 25); - return [key.readUInt32BE(1, true), key.toString('hex', 5)]; + return [key.readUInt32BE(1, true), key.slice(5)]; } function parser(key) { // r[wid][index][hash] @@ -878,7 +878,7 @@ function parser(key) { // r[wid][index][hash] return [ key.readUInt32BE(1, true), key.readUInt32BE(5, true), - key.toString('hex', 9) + key.slice(9) ]; } diff --git a/package.json b/package.json index 05ecfa7f8..4d0a6d44f 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "bcfg": "~0.1.0", "bclient": "~0.1.1", "bcrypto": "~0.3.7", - "bdb": "~0.2.1", + "bdb": "~0.2.2", "bdns": "~0.1.0", "bevent": "~0.1.0", "bfile": "~0.1.0", @@ -34,19 +34,20 @@ "bheep": "~0.1.0", "binet": "~0.3.0", "blgr": "~0.1.0", - "blru": "~0.1.0", + "blru": "~0.1.1", "blst": "~0.1.0", - "bmutex": "~0.1.0", + "bmutex": "~0.1.1", "bn.js": "~4.11.8", "bsip": "~0.1.0", "bsock": "~0.1.2", "bsocks": "~0.2.0", "bstring": "~0.1.0", "btcp": "~0.1.0", + "buffer-map": "~0.0.0", "bufio": "~0.2.0", "bupnp": "~0.2.1", - "bval": "~0.1.0", - "bweb": "~0.1.3", + "bval": "~0.1.1", + "bweb": "~0.1.1", "mrmr": "~0.1.0", "n64": "~0.2.0" }, diff --git a/scripts/gen.js b/scripts/gen.js index 76b4e1b74..c9c2c80ad 100644 --- a/scripts/gen.js +++ b/scripts/gen.js @@ -30,7 +30,7 @@ function createGenesisBlock(options) { version: 1, inputs: [{ prevout: { - hash: consensus.NULL_HASH, + hash: consensus.ZERO_HASH, index: 0xffffffff }, script: Script() @@ -49,8 +49,8 @@ function createGenesisBlock(options) { const block = new Block({ version: options.version, - prevBlock: consensus.NULL_HASH, - merkleRoot: tx.hash('hex'), + prevBlock: consensus.ZERO_HASH, + merkleRoot: tx.hash(), time: options.time, bits: options.bits, nonce: options.nonce, diff --git a/test/block-test.js b/test/block-test.js index fbde92719..adef42237 100644 --- a/test/block-test.js +++ b/test/block-test.js @@ -6,6 +6,7 @@ const assert = require('./util/assert'); const common = require('./util/common'); const {BloomFilter} = require('bfilter'); +const {BufferMap} = require('buffer-map'); const Block = require('../lib/primitives/block'); const MerkleBlock = require('../lib/primitives/merkleblock'); const consensus = require('../lib/protocol/consensus'); @@ -52,7 +53,7 @@ describe('Block', function() { const tree = block.getTree(); assert.strictEqual(tree.matches.length, 2); - assert.strictEqual(block.hash('hex'), + assert.strictEqual(block.hash().toString('hex'), '8cc72c02a958de5a8b35a23bb7e3bced8bf840cc0a4e1c820000000000000000'); assert.strictEqual(block.rhash(), '0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c'); @@ -94,23 +95,26 @@ describe('Block', function() { it('should parse JSON', () => { const [block1] = block300025.getBlock(); const block2 = Block.fromJSON(block1.toJSON()); - assert.strictEqual(block2.hash('hex'), + assert.strictEqual(block2.hash().toString('hex'), '8cc72c02a958de5a8b35a23bb7e3bced8bf840cc0a4e1c820000000000000000'); assert.strictEqual(block2.rhash(), '0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c'); - assert.strictEqual(block2.merkleRoot, block2.createMerkleRoot('hex')); + assert.bufferEqual(block2.merkleRoot, block2.createMerkleRoot()); }); it('should create a merkle block', () => { const filter = BloomFilter.fromRate(1000, 0.01, BloomFilter.flags.NONE); - const item1 = '8e7445bbb8abd4b3174d80fa4c409fea6b94d96b'; - const item2 = '047b00000078da0dca3b0ec2300c00d0ab4466ed10' + const item1 = Buffer.from( + '8e7445bbb8abd4b3174d80fa4c409fea6b94d96b', + 'hex'); + + const item2 = Buffer.from('047b00000078da0dca3b0ec2300c00d0ab4466ed10' + 'e763272c6c9ca052972c69e3884a9022084215e2eef' - + '0e6f781656b5d5a87231cd4349e534b6dea55ad4ff55e'; + + '0e6f781656b5d5a87231cd4349e534b6dea55ad4ff55e', 'hex'); - filter.add(item1, 'hex'); - filter.add(item2, 'hex'); + filter.add(item1); + filter.add(item2); const [block1] = block300025.getBlock(); const block2 = MerkleBlock.fromBlock(block1, filter); @@ -157,7 +161,7 @@ describe('Block', function() { it('should fail with a bad merkle root', () => { const [block] = block300025.getBlock(); const merkleRoot = block.merkleRoot; - block.merkleRoot = consensus.NULL_HASH; + block.merkleRoot = consensus.ZERO_HASH; block.refresh(); assert(!block.verifyPOW()); const [, reason] = block.checkBody(); @@ -171,7 +175,7 @@ describe('Block', function() { it('should fail on merkle block with a bad merkle root', () => { const [block] = merkle300025.getBlock(); const merkleRoot = block.merkleRoot; - block.merkleRoot = consensus.NULL_HASH; + block.merkleRoot = consensus.ZERO_HASH; block.refresh(); assert(!block.verifyPOW()); const [, reason] = block.checkBody(); @@ -220,11 +224,11 @@ describe('Block', function() { assert.bufferEqual(cblock1.toRaw(), compact426884.getRaw()); assert.bufferEqual(cblock2.toRaw(), compact426884.getRaw()); - const map = new Map(); + const map = new BufferMap(); for (let i = 1; i < block.txs.length; i++) { const tx = block.txs[i]; - map.set(tx.hash('hex'), { tx }); + map.set(tx.hash(), { tx }); } const full = cblock1.fillMempool(false, { map }); @@ -246,11 +250,11 @@ describe('Block', function() { assert.bufferEqual(cblock1.toRaw(), compact426884.getRaw()); assert.bufferEqual(cblock2.toRaw(), compact426884.getRaw()); - const map = new Map(); + const map = new BufferMap(); for (let i = 1; i < ((block.txs.length + 1) >>> 1); i++) { const tx = block.txs[i]; - map.set(tx.hash('hex'), { tx }); + map.set(tx.hash(), { tx }); } const full = cblock1.fillMempool(false, { map }); @@ -258,7 +262,7 @@ describe('Block', function() { const rawReq = cblock1.toRequest().toRaw(); const req = TXRequest.fromRaw(rawReq); - assert.strictEqual(req.hash, cblock1.hash('hex')); + assert.bufferEqual(req.hash, cblock1.hash()); const rawRes = TXResponse.fromBlock(block, req).toRaw(); const res = TXResponse.fromRaw(rawRes); @@ -284,11 +288,11 @@ describe('Block', function() { assert.strictEqual(cblock1.sid(block.txs[1].hash()), 125673511480291); - const map = new Map(); + const map = new BufferMap(); for (let i = 1; i < block.txs.length; i++) { const tx = block.txs[i]; - map.set(tx.hash('hex'), { tx }); + map.set(tx.hash(), { tx }); } const full = cblock1.fillMempool(false, { map }); @@ -312,11 +316,11 @@ describe('Block', function() { assert.strictEqual(cblock1.sid(block.txs[1].hash()), 125673511480291); - const map = new Map(); + const map = new BufferMap(); for (let i = 1; i < ((block.txs.length + 1) >>> 1); i++) { const tx = block.txs[i]; - map.set(tx.hash('hex'), { tx }); + map.set(tx.hash(), { tx }); } const full = cblock1.fillMempool(false, { map }); @@ -324,7 +328,7 @@ describe('Block', function() { const rawReq = cblock1.toRequest().toRaw(); const req = TXRequest.fromRaw(rawReq); - assert.strictEqual(req.hash, cblock1.hash('hex')); + assert.bufferEqual(req.hash, cblock1.hash()); assert.deepStrictEqual(req.indexes, [5, 6, 7, 8, 9]); const rawRes = TXResponse.fromBlock(block, req).toRaw(); diff --git a/test/chain-test.js b/test/chain-test.js index 1cf13ed0e..591616627 100644 --- a/test/chain-test.js +++ b/test/chain-test.js @@ -154,13 +154,13 @@ describe('Chain', function() { const blk1 = await job1.mineAsync(); const blk2 = await job2.mineAsync(); - const hash1 = blk1.hash('hex'); - const hash2 = blk2.hash('hex'); + const hash1 = blk1.hash(); + const hash2 = blk2.hash(); assert(await chain.add(blk1)); assert(await chain.add(blk2)); - assert.strictEqual(chain.tip.hash, hash1); + assert.bufferEqual(chain.tip.hash, hash1); tip1 = await chain.getEntry(hash1); tip2 = await chain.getEntry(hash2); @@ -200,7 +200,7 @@ describe('Chain', function() { assert(await chain.add(block)); assert(forked); - assert.strictEqual(chain.tip.hash, block.hash('hex')); + assert.bufferEqual(chain.tip.hash, block.hash()); assert(chain.tip.chainwork.gt(tip1.chainwork)); }); @@ -224,11 +224,11 @@ describe('Chain', function() { assert(await chain.add(block)); - const hash = block.hash('hex'); + const hash = block.hash(); const entry = await chain.getEntry(hash); assert(entry); - assert.strictEqual(chain.tip.hash, entry.hash); + assert.bufferEqual(chain.tip.hash, entry.hash); const result = await chain.isMainChain(entry); assert(result); @@ -318,7 +318,7 @@ describe('Chain', function() { const tx = block.txs[1]; const output = Coin.fromTX(tx, 2, chain.height); - const coin = await chain.getCoin(tx.hash('hex'), 2); + const coin = await chain.getCoin(tx.hash(), 2); assert.bufferEqual(coin.toRaw(), output.toRaw()); }); @@ -334,7 +334,14 @@ describe('Chain', function() { { const tips = await chain.db.getTips(); - assert.notStrictEqual(tips.indexOf(chain.tip.hash), -1); + let index = -1; + + for (let i = 0; i < tips.length; i++) { + if (tips[i].equals(chain.tip.hash)) + index = i; + } + + assert.notStrictEqual(index, -1); assert.strictEqual(tips.length, 2); } @@ -343,7 +350,14 @@ describe('Chain', function() { { const tips = await chain.db.getTips(); - assert.notStrictEqual(tips.indexOf(chain.tip.hash), -1); + let index = -1; + + for (let i = 0; i < tips.length; i++) { + if (tips[i].equals(chain.tip.hash)) + index = i; + } + + assert.notStrictEqual(index, -1); assert.strictEqual(tips.length, 1); } }); @@ -578,7 +592,7 @@ describe('Chain', function() { output.script.compile(); block.refresh(true); - block.merkleRoot = block.createMerkleRoot('hex'); + block.merkleRoot = block.createMerkleRoot(); assert.strictEqual(await addBlock(block, flags), 'bad-witness-merkle-match'); @@ -595,7 +609,7 @@ describe('Chain', function() { tx.outputs.pop(); block.refresh(true); - block.merkleRoot = block.createMerkleRoot('hex'); + block.merkleRoot = block.createMerkleRoot(); assert.strictEqual(await addBlock(block, flags), 'unexpected-witness'); }); @@ -817,7 +831,7 @@ describe('Chain', function() { } block.refresh(true); - block.merkleRoot = block.createMerkleRoot('hex'); + block.merkleRoot = block.createMerkleRoot(); assert(await chain.add(block, flags)); } diff --git a/test/coins-test.js b/test/coins-test.js index 72ef2944e..daa88b9c0 100644 --- a/test/coins-test.js +++ b/test/coins-test.js @@ -31,7 +31,7 @@ function deepCoinsEqual(a, b) { describe('Coins', function() { it('should instantiate coinview from tx', () => { const [tx] = tx1.getTX(); - const hash = tx.hash('hex'); + const hash = tx.hash(); const view = new CoinView(); const prevout = new Outpoint(hash, 0); const input = Input.fromOutpoint(prevout); @@ -59,7 +59,7 @@ describe('Coins', function() { it('should spend an output', () => { const [tx] = tx1.getTX(); - const hash = tx.hash('hex'); + const hash = tx.hash(); const view = new CoinView(); view.addTX(tx, 1); diff --git a/test/headers-test.js b/test/headers-test.js index 41b17745c..f0512a51c 100644 --- a/test/headers-test.js +++ b/test/headers-test.js @@ -26,9 +26,9 @@ describe('Headers', function() { assert.strictEqual(headers.nonce, 2573394689); assert.strictEqual(headers.version, 1); - assert.strictEqual(headers.prevBlock, + assert.strictEqual(headers.prevBlock.toString('hex'), '6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000'); - assert.strictEqual(headers.merkleRoot, + assert.strictEqual(headers.merkleRoot.toString('hex'), '982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e'); assert.strictEqual(headers.rhash(), '00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048'); @@ -45,9 +45,9 @@ describe('Headers', function() { assert.strictEqual(headers.nonce, 2573394689); assert.strictEqual(headers.version, 1); - assert.strictEqual(headers.prevBlock, + assert.strictEqual(headers.prevBlock.toString('hex'), '6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000'); - assert.strictEqual(headers.merkleRoot, + assert.strictEqual(headers.merkleRoot.toString('hex'), '982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e'); assert.strictEqual(headers.rhash(), '00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048'); diff --git a/test/http-test.js b/test/http-test.js index 216f46812..1f9d04716 100644 --- a/test/http-test.js +++ b/test/http-test.js @@ -80,7 +80,7 @@ describe('HTTP', function() { it('should fill with funds', async () => { const mtx = new MTX(); - mtx.addOutpoint(new Outpoint(consensus.NULL_HASH, 0)); + mtx.addOutpoint(new Outpoint(consensus.ZERO_HASH, 0)); mtx.addOutput(addr, 50460); mtx.addOutput(addr, 50460); mtx.addOutput(addr, 50460); diff --git a/test/input-test.js b/test/input-test.js index 83e7e2f6c..8fa4f18a5 100644 --- a/test/input-test.js +++ b/test/input-test.js @@ -216,8 +216,9 @@ describe('Input', function() { const options = { prevout: { - hash: '8759d7397a86d6c42dfe2c55612e523d' + - '171e51708fec9e289118deb5ba994001', + hash: Buffer.from( + '8759d7397a86d6c42dfe2c55612e523d' + + '171e51708fec9e289118deb5ba994001', 'hex'), index: 1 }, script: rawscript, @@ -236,7 +237,7 @@ describe('Input', function() { const inputs = test.inputs.map((prevout, i) => { const input = Input.fromOptions({ prevout: { - hash: util.revHex(prevout.txId), + hash: util.fromRev(prevout.txId), index: prevout.vout } }); diff --git a/test/mempool-test.js b/test/mempool-test.js index 773796327..992e82e46 100644 --- a/test/mempool-test.js +++ b/test/mempool-test.js @@ -81,7 +81,7 @@ describe('Mempool', function() { const script = Script.fromPubkey(key.publicKey); - t1.addCoin(dummyInput(script, ONE_HASH.toString('hex'))); + t1.addCoin(dummyInput(script, ONE_HASH)); const sig = t1.signature(0, script, 70000, key.privateKey, ALL, 0); @@ -173,7 +173,7 @@ describe('Mempool', function() { const txs = mempool.getHistory(); assert(txs.some((tx) => { - return tx.hash('hex') === f1.hash('hex'); + return tx.hash().equals(f1.hash()); })); }); @@ -185,7 +185,7 @@ describe('Mempool', function() { tx.addOutput(wallet.getAddress(), 10000); const prev = Script.fromPubkey(key.publicKey); - const prevHash = random.randomBytes(32).toString('hex'); + const prevHash = random.randomBytes(32); tx.addCoin(dummyInput(prev, prevHash)); tx.setLocktime(200); @@ -207,7 +207,7 @@ describe('Mempool', function() { tx.addOutput(wallet.getAddress(), 10000); const prev = Script.fromPubkey(key.publicKey); - const prevHash = random.randomBytes(32).toString('hex'); + const prevHash = random.randomBytes(32); tx.addCoin(dummyInput(prev, prevHash)); tx.setLocktime(200); @@ -238,7 +238,7 @@ describe('Mempool', function() { tx.addOutput(wallet.getAddress(), 10000); const prev = Script.fromProgram(0, key.getKeyHash()); - const prevHash = random.randomBytes(32).toString('hex'); + const prevHash = random.randomBytes(32); tx.addCoin(dummyInput(prev, prevHash)); @@ -268,7 +268,7 @@ describe('Mempool', function() { tx.addOutput(wallet.getAddress(), 10000); const prev = Script.fromPubkey(key.publicKey); - const prevHash = random.randomBytes(32).toString('hex'); + const prevHash = random.randomBytes(32); tx.addCoin(dummyInput(prev, prevHash)); @@ -297,7 +297,7 @@ describe('Mempool', function() { tx.addOutput(wallet.getAddress(), 10000); const prev = Script.fromProgram(0, key.getKeyHash()); - const prevHash = random.randomBytes(32).toString('hex'); + const prevHash = random.randomBytes(32); tx.addCoin(dummyInput(prev, prevHash)); @@ -321,7 +321,7 @@ describe('Mempool', function() { tx.addOutput(wallet.getAddress(), 10000); const prev = Script.fromPubkey(key.publicKey); - const prevHash = random.randomBytes(32).toString('hex'); + const prevHash = random.randomBytes(32); tx.addCoin(dummyInput(prev, prevHash)); diff --git a/test/node-test.js b/test/node-test.js index ed13cecd5..6b9937eb3 100644 --- a/test/node-test.js +++ b/test/node-test.js @@ -115,10 +115,10 @@ describe('Node', function() { await chain.add(block2); - assert.strictEqual(chain.tip.hash, block1.hash('hex')); + assert.bufferEqual(chain.tip.hash, block1.hash()); - tip1 = await chain.getEntry(block1.hash('hex')); - tip2 = await chain.getEntry(block2.hash('hex')); + tip1 = await chain.getEntry(block1.hash()); + tip2 = await chain.getEntry(block2.hash()); assert(tip1); assert(tip2); @@ -162,7 +162,7 @@ describe('Node', function() { await chain.add(block); assert(forked); - assert.strictEqual(chain.tip.hash, block.hash('hex')); + assert.bufferEqual(chain.tip.hash, block.hash()); assert(chain.tip.chainwork.gt(tip1.chainwork)); }); @@ -190,9 +190,9 @@ describe('Node', function() { await chain.add(block); - const entry = await chain.getEntry(block.hash('hex')); + const entry = await chain.getEntry(block.hash()); assert(entry); - assert.strictEqual(chain.tip.hash, entry.hash); + assert.bufferEqual(chain.tip.hash, entry.hash); const result = await chain.isMainChain(entry); assert(result); @@ -246,7 +246,7 @@ describe('Node', function() { const tx = block2.txs[1]; const output = Coin.fromTX(tx, 1, chain.height); - const coin = await chain.getCoin(tx.hash('hex'), 1); + const coin = await chain.getCoin(tx.hash(), 1); assert.bufferEqual(coin.toRaw(), output.toRaw()); }); @@ -271,7 +271,14 @@ describe('Node', function() { { const tips = await chain.db.getTips(); - assert.notStrictEqual(tips.indexOf(chain.tip.hash), -1); + let index = -1; + + for (let i = 0; i < tips.length; i++) { + if (tips[i].equals(chain.tip.hash)) + index = i; + } + + assert.notStrictEqual(index, -1); assert.strictEqual(tips.length, 2); } @@ -280,7 +287,14 @@ describe('Node', function() { { const tips = await chain.db.getTips(); - assert.notStrictEqual(tips.indexOf(chain.tip.hash), -1); + let index = -1; + + for (let i = 0; i < tips.length; i++) { + if (tips[i].equals(chain.tip.hash)) + index = i; + } + + assert.notStrictEqual(index, -1); assert.strictEqual(tips.length, 1); } }); @@ -545,7 +559,7 @@ describe('Node', function() { assert(!json.error); assert.strictEqual(json.result, null); - assert.strictEqual(node.chain.tip.hash, block.hash('hex')); + assert.bufferEqual(node.chain.tip.hash, block.hash()); }); it('should validate an address', async () => { diff --git a/test/outpoint-test.js b/test/outpoint-test.js index 46c715754..cab9ae7e4 100644 --- a/test/outpoint-test.js +++ b/test/outpoint-test.js @@ -44,7 +44,8 @@ describe('Outpoint', () => { it('should compare the indexes between outpoints', () => { const out1RevHash = out1.clone(); - out1RevHash.hash = out1RevHash.rhash(); + out1RevHash.hash = Buffer.from(out1RevHash.hash); + out1RevHash.hash[0] = 0; const out1AdjIndex = out1.clone(); out1AdjIndex.index += 1; @@ -66,18 +67,18 @@ describe('Outpoint', () => { }); it('should retrieve little endian hash', () => { - assert.equal(out1.rhash(), util.revHex(out1.hash)); - assert.equal(out1.txid(), util.revHex(out1.hash)); + assert.strictEqual(out1.rhash(), util.revHex(out1.hash)); + assert.strictEqual(out1.txid(), util.revHex(out1.hash)); }); it('should serialize to a key suitable for hash table', () => { - const expected = out1.hash + out1.index; + const expected = out1.toRaw(); const actual = out1.toKey(); - assert.equal(expected, actual); + assert.bufferEqual(expected, actual); }); it('should inject properties from hash table key', () => { - const key = out1.hash + out1.index; + const key = out1.toKey(); const fromKey = Outpoint.fromKey(key); assert(out1.equals(fromKey), true); }); @@ -112,7 +113,7 @@ describe('Outpoint', () => { const index = 0; const fromTX = Outpoint.fromTX(tx, index); - assert.equal(fromTX.hash, tx.hash('hex')); - assert.equal(fromTX.index, index); + assert.bufferEqual(fromTX.hash, tx.hash()); + assert.strictEqual(fromTX.index, index); }); }); diff --git a/test/script-test.js b/test/script-test.js index b4ae3e46b..38bbcd886 100644 --- a/test/script-test.js +++ b/test/script-test.js @@ -286,7 +286,7 @@ describe('Script', function() { version: 1, inputs: [{ prevout: { - hash: consensus.NULL_HASH, + hash: consensus.ZERO_HASH, index: 0xffffffff }, script: [ @@ -308,7 +308,7 @@ describe('Script', function() { version: 1, inputs: [{ prevout: { - hash: prev.hash('hex'), + hash: prev.hash(), index: 0 }, script: input, diff --git a/test/tx-test.js b/test/tx-test.js index 659d8d841..0a83eab73 100644 --- a/test/tx-test.js +++ b/test/tx-test.js @@ -69,7 +69,7 @@ function parseTXTest(data) { const view = new CoinView(); for (const [txid, index, str, amount] of coins) { - const hash = util.revHex(txid); + const hash = util.fromRev(txid); const script = Script.fromString(str); const value = parseInt(amount || '0', 10); @@ -106,7 +106,7 @@ function parseSighashTest(data) { const tx = TX.fromRaw(txHex, 'hex'); const script = Script.fromRaw(scriptHex, 'hex'); - const expected = util.revHex(hash); + const expected = util.fromRev(hash); let hex = type & 3; @@ -130,7 +130,7 @@ function parseSighashTest(data) { } function createInput(value, view) { - const hash = random.randomBytes(32).toString('hex'); + const hash = random.randomBytes(32); const input = { prevout: { @@ -173,7 +173,7 @@ function sigopContext(scriptSig, witness, scriptPubkey) { spend.version = 1; const input = new Input(); - input.prevout.hash = fund.hash('hex'); + input.prevout.hash = fund.hash(); input.prevout.index = 0; input.script = scriptSig; input.witness = witness; @@ -235,7 +235,7 @@ describe('TX', function() { assert.strictEqual(tx.outputs.length, 1980); assert(tx.hasWitness()); assert.notStrictEqual(tx.txid(), tx.wtxid()); - assert.strictEqual(tx.witnessHash('hex'), + assert.strictEqual(tx.witnessHash().toString('hex'), '088c919cd8408005f255c411f786928385688a9e8fdb2db4c9bc3578ce8c94cf'); assert.strictEqual(tx.getSize(), 62138); assert.strictEqual(tx.getVirtualSize(), 61813); @@ -339,7 +339,7 @@ describe('TX', function() { it(`should get sighash of ${hash} (${hex}) ${suffix}`, () => { const subscript = script.getSubscript(0).removeSeparators(); const hash = tx.signatureHash(index, subscript, 0, type, 0); - assert.strictEqual(hash.toString('hex'), expected); + assert.bufferEqual(hash, expected); }); } } @@ -695,7 +695,7 @@ describe('TX', function() { const output = Script.fromProgram(0, key.getKeyHash()); const ctx = sigopContext(input, witness, output); - ctx.spend.inputs[0].prevout.hash = consensus.NULL_HASH; + ctx.spend.inputs[0].prevout.hash = consensus.ZERO_HASH; ctx.spend.inputs[0].prevout.index = 0xffffffff; ctx.spend.refresh(); @@ -899,14 +899,11 @@ describe('TX', function() { ]; const hashesBuf = tx.getHashes(view); - const hashesHex = tx.getHashes(view, 'hex'); assert.strictEqual(hashes.length, hashesBuf.length); - assert.strictEqual(hashes.length, hashesHex.length); hashes.forEach((hash, i) => { assert.bufferEqual(hash, hashesBuf[i]); - assert.strictEqual(hash.toString('hex'), hashesHex[i]); }); }); @@ -919,14 +916,11 @@ describe('TX', function() { ]; const hashesBuf = tx.getInputHashes(view); - const hashesHex = tx.getInputHashes(view, 'hex'); assert.strictEqual(inputHashes.length, hashesBuf.length); - assert.strictEqual(inputHashes.length, hashesHex.length); inputHashes.forEach((hash, i) => { assert.bufferEqual(hash, hashesBuf[i]); - assert.strictEqual(hash.toString('hex'), hashesHex[i]); }); }); @@ -940,14 +934,11 @@ describe('TX', function() { ]; const hashesBuf = tx.getOutputHashes(); - const hashesHex = tx.getOutputHashes('hex'); assert.strictEqual(outputHashes.length, hashesBuf.length); - assert.strictEqual(outputHashes.length, hashesHex.length); outputHashes.forEach((hash, i) => { assert.bufferEqual(hash, hashesBuf[i]); - assert.strictEqual(hash.toString('hex'), hashesHex[i]); }); }); @@ -963,7 +954,7 @@ describe('TX', function() { assert(expectedPrevouts.length, prevouts.length); expectedPrevouts.forEach((prevout, i) => { - assert.strictEqual(prevout, prevouts[i]); + assert.strictEqual(prevout, prevouts[i].toString('hex')); }); }); @@ -1063,7 +1054,9 @@ describe('TX', function() { // hack for ChainEntry const entry = { height: 1000, - hash: 'c82d447db6150d2308d9571c19bc3dc6efde97a8227d9e57bc77ec0900000000', + hash: Buffer.from( + 'c82d447db6150d2308d9571c19bc3dc6efde97a8227d9e57bc77ec0900000000', + 'hex'), time: 1365870306 }; const network = 'testnet'; diff --git a/test/util/memwallet.js b/test/util/memwallet.js index 7e9c2725d..ace6d3a2e 100644 --- a/test/util/memwallet.js +++ b/test/util/memwallet.js @@ -7,6 +7,7 @@ 'use strict'; const assert = require('assert'); +const {BufferMap, BufferSet} = require('buffer-map'); const Network = require('../../lib/protocol/network'); const MTX = require('../../lib/primitives/mtx'); const HD = require('../../lib/hd/hd'); @@ -26,10 +27,10 @@ class MemWallet { this.changeDepth = 1; this.receive = null; this.change = null; - this.map = new Set(); - this.coins = new Map(); - this.spent = new Map(); - this.paths = new Map(); + this.map = new BufferSet(); + this.coins = new BufferMap(); + this.spent = new BufferMap(); + this.paths = new BufferMap(); this.balance = 0; this.txs = 0; this.filter = BloomFilter.fromRate(1000000, 0.001, -1); @@ -102,8 +103,8 @@ class MemWallet { createReceive() { const index = this.receiveDepth++; const key = this.deriveReceive(index); - const hash = key.getHash('hex'); - this.filter.add(hash, 'hex'); + const hash = key.getHash(); + this.filter.add(hash); this.paths.set(hash, new Path(hash, 0, index)); this.receive = key; return key; @@ -112,8 +113,8 @@ class MemWallet { createChange() { const index = this.changeDepth++; const key = this.deriveChange(index); - const hash = key.getHash('hex'); - this.filter.add(hash, 'hex'); + const hash = key.getHash(); + this.filter.add(hash); this.paths.set(hash, new Path(hash, 1, index)); this.change = key; return key; @@ -246,7 +247,7 @@ class MemWallet { } addTX(tx, height) { - const hash = tx.hash('hex'); + const hash = tx.hash(); let result = false; if (height == null) @@ -270,7 +271,7 @@ class MemWallet { for (let i = 0; i < tx.outputs.length; i++) { const output = tx.outputs[i]; - const addr = output.getHash('hex'); + const addr = output.getHash(); if (!addr) continue; @@ -297,7 +298,7 @@ class MemWallet { } removeTX(tx, height) { - const hash = tx.hash('hex'); + const hash = tx.hash(); let result = false; if (!this.map.has(hash)) @@ -346,7 +347,7 @@ class MemWallet { if (!coin) continue; - const addr = coin.getHash('hex'); + const addr = coin.getHash(); if (!addr) continue; diff --git a/test/wallet-test.js b/test/wallet-test.js index e59f7fbc9..669a88415 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -55,9 +55,9 @@ function fakeBlock(height) { const root = hash256.digest(fromU32((height | 0x80000000) >>> 0)); return { - hash: hash.toString('hex'), - prevBlock: prev.toString('hex'), - merkleRoot: root.toString('hex'), + hash: hash, + prevBlock: prev, + merkleRoot: root, time: 500000000 + (height * (10 * 60)), bits: 0, nonce: 0, @@ -66,7 +66,7 @@ function fakeBlock(height) { } function dummyInput() { - const hash = random.randomBytes(32).toString('hex'); + const hash = random.randomBytes(32); return Input.fromOutpoint(new Outpoint(hash, 0)); } @@ -398,7 +398,7 @@ describe('Wallet', function() { const txs = await alice.getHistory(); assert(txs.some((wtx) => { - return wtx.hash === f1.hash('hex'); + return wtx.hash.equals(f1.hash()); })); } @@ -408,7 +408,7 @@ describe('Wallet', function() { const txs = await bob.getHistory(); assert(txs.some((wtx) => { - return wtx.tx.hash('hex') === f1.hash('hex'); + return wtx.tx.hash().equals(f1.hash()); })); } @@ -428,7 +428,7 @@ describe('Wallet', function() { const txs = await alice.getHistory(); assert(txs.some((wtx) => { - return wtx.hash === f1.hash('hex'); + return wtx.hash.equals(f1.hash()); })); } @@ -439,7 +439,7 @@ describe('Wallet', function() { const txs = await bob.getHistory(); assert(txs.some((wtx) => { - return wtx.tx.hash('hex') === f1.hash('hex'); + return wtx.tx.hash().equals(f1.hash()); })); } }); @@ -589,7 +589,7 @@ describe('Wallet', function() { const txs = await alice.getHistory(); assert(txs.some((wtx) => { - return wtx.tx.hash('hex') === f1.hash('hex'); + return wtx.tx.hash().equals(f1.hash()); })); } @@ -599,7 +599,7 @@ describe('Wallet', function() { const txs = await bob.getHistory(); assert(txs.some((wtx) => { - return wtx.tx.hash('hex') === f1.hash('hex'); + return wtx.tx.hash().equals(f1.hash()); })); } @@ -685,7 +685,7 @@ describe('Wallet', function() { // Coinbase const t1 = new MTX(); - t1.addOutpoint(new Outpoint(consensus.NULL_HASH, 0)); + t1.addOutpoint(new Outpoint(consensus.ZERO_HASH, 0)); t1.addOutput(await alice.receiveAddress(), 5460); t1.addOutput(await alice.receiveAddress(), 5460); t1.addOutput(await alice.receiveAddress(), 5460); @@ -1263,9 +1263,9 @@ describe('Wallet', function() { await wallet.importKey('default', key, 'test'); - const wkey = await wallet.getKey(key.getHash('hex')); + const wkey = await wallet.getKey(key.getHash()); - assert.strictEqual(wkey.getHash('hex'), key.getHash('hex')); + assert.bufferEqual(wkey.getHash(), key.getHash()); // Coinbase const t1 = new MTX(); @@ -1278,9 +1278,9 @@ describe('Wallet', function() { await wdb.addTX(t1.toTX()); - const wtx = await wallet.getTX(t1.hash('hex')); + const wtx = await wallet.getTX(t1.hash()); assert(wtx); - assert.strictEqual(t1.hash('hex'), wtx.hash); + assert.bufferEqual(t1.hash(), wtx.hash); const options = { rate: 10000, @@ -1295,7 +1295,7 @@ describe('Wallet', function() { const t2 = await wallet.createTX(options); await wallet.sign(t2); assert(t2.verify()); - assert.strictEqual(t2.inputs[0].prevout.hash, wtx.hash); + assert.bufferEqual(t2.inputs[0].prevout.hash, wtx.hash); importedWallet = wallet; importedKey = key; @@ -1311,10 +1311,10 @@ describe('Wallet', function() { await wallet.importKey('default', pub); - const path = await wallet.getPath(pub.getHash('hex')); - assert.strictEqual(path.hash, pub.getHash('hex')); + const path = await wallet.getPath(pub.getHash()); + assert.bufferEqual(path.hash, pub.getHash()); - const wkey = await wallet.getKey(pub.getHash('hex')); + const wkey = await wallet.getKey(pub.getHash()); assert(wkey); }); @@ -1327,11 +1327,11 @@ describe('Wallet', function() { await wallet.importAddress('default', key.getAddress()); - const path = await wallet.getPath(key.getHash('hex')); + const path = await wallet.getPath(key.getHash()); assert(path); - assert.strictEqual(path.hash, key.getHash('hex')); + assert.bufferEqual(path.hash, key.getHash()); - const wkey = await wallet.getKey(key.getHash('hex')); + const wkey = await wallet.getKey(key.getHash()); assert(!wkey); }); @@ -1401,7 +1401,7 @@ describe('Wallet', function() { const key = await wallet.getKey(addr); assert(key); - assert.strictEqual(key.getHash('hex'), addr.getHash('hex')); + assert.bufferEqual(key.getHash(), addr.getHash()); }); it('should recover from a missed tx', async () => {