diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index 620186b1..ee7ddbc6 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -216,63 +216,79 @@ Block.prototype.getMerkleRoot = function getMerkleRoot() { return merkleTree[merkleTree.length - 1]; }; -// This mimics the behavior of CheckBlockHeader() -// and CheckBlock() in bitcoin/src/main.cpp. Block.prototype._verify = function _verify() { var uniq = {}; var i, tx, hash; - // Check proof of work matches claimed amount - if (!utils.testTarget(this.bits, this.hash())) + // Check proof of work + if (!utils.testTarget(this.bits, this.hash())) { + this.chain.emit('debug', 'Block failed POW test: %s', this.rhash); return false; - - // Check timestamp - if (this.ts > utils.now() + 2 * 60 * 60) - return false; - - if (this.subtype === 'merkleblock') { - if (!this._verifyPartial()) - return false; } + // Check timestamp against now + 2 hours + if (this.ts > utils.now() + 2 * 60 * 60) { + this.chain.emit('debug', 'Block timestamp is too high: %s', this.rhash); + return false; + } + + // Verify the partial merkle tree if we are a merkleblock. + if (this.subtype === 'merkleblock') { + if (!this._verifyPartial()) { + this.chain.emit('debug', 'Block failed merkle test: %s', this.rhash); + return false; + } + } + + // Merkleblock and headers cannot do anymore tests. if (this.subtype !== 'block') return true; // Size can't be bigger than MAX_BLOCK_SIZE if (this.txs.length > constants.block.maxSize || this.size() > constants.block.maxSize) { + this.chain.emit('debug', 'Block is too large: %s', this.rhash); return false; } // First TX must be a coinbase - if (!this.txs.length || !this.txs[0].isCoinbase()) + if (!this.txs.length || !this.txs[0].isCoinbase()) { + this.chain.emit('debug', 'Block has no coinbase: %s', this.rhash); return false; + } // Test all txs for (i = 0; i < this.txs.length; i++) { tx = this.txs[i]; // The rest of the txs must not be coinbases - if (i > 0 && tx.isCoinbase()) + if (i > 0 && tx.isCoinbase()) { + this.chain.emit('debug', 'Block more than one coinbase: %s', this.rhash); return false; + } // Check for duplicate txids hash = tx.hash('hex'); - if (uniq[hash]) + if (uniq[hash]) { + this.chain.emit('debug', 'Block has duplicate txids: %s', this.rhash); return false; + } uniq[hash] = true; } // Check merkle root - if (this.getMerkleRoot() !== this.merkleRoot) + if (this.getMerkleRoot() !== this.merkleRoot) { + this.chain.emit('debug', 'Block failed merkleroot test: %s', this.rhash); return false; + } return true; }; Block.prototype.postVerify = function postVerify() { var flags = {}; - var prev, height, i, j, tx, cb, sigops, input; + var sigops = 0; + var prev, height, ts, i, j, tx, cb, input; if (this.subtype !== 'block') return true; @@ -284,96 +300,121 @@ Block.prototype.postVerify = function postVerify() { return true; prev = this.chain.getBlock(this.prevBlock); - height = prev.height + 1; // Ensure it's not an orphan if (!prev) { - console.log('NO PREV: %s', height); + this.chain.emit('debug', 'Block has no previous entry: %s', this.rhash); return false; } + height = prev.height + 1; + // Ensure the timestamp is correct if (this.ts <= prev.getMedianTime()) { - console.log('BAD TIME: %s', height); + this.chain.emit('debug', 'Block time is lower than median: %s', this.rhash); return false; } - // Test all txs - for (i = 0; i < this.txs.length; i++) { - tx = this.txs[i]; - - // TXs must be finalized with regards to seq and locktime - if (!tx.isFinal(this, prev)) { - console.log('IS NOT FINAL: %s', height); - return false; - } - } - // Ensure the miner's target is equal to what we expect if (this.bits !== this.chain.target(prev, this)) { - console.log('BAD TARGET: %s', height); + this.chain.emit('debug', 'Block is using wrong target: %s', this.rhash); return false; } // Only allow version 2 blocks (coinbase height) // once the majority of blocks are using it. if (this.version < 2 && prev.isOutdated(2)) { - console.log('OUTDATED 2: %s', height); + this.chain.emit('debug', 'Block is outdated (v2): %s', this.rhash); return false; } // Only allow version 3 blocks (sig validation) // once the majority of blocks are using it. if (this.version < 3 && prev.isOutdated(3)) { - console.log('OUTDATED 3: %s', height); + this.chain.emit('debug', 'Block is outdated (v3): %s', this.rhash); return false; } // Only allow version 4 blocks (checklocktimeverify) // once the majority of blocks are using it. if (this.version < 4 && prev.isOutdated(4)) { - console.log('OUTDATED 4: %s', height); + this.chain.emit('debug', 'Block is outdated (v4): %s', this.rhash); return false; } - // Make sure the height contained in the - // coinbase is correct. + // Only allow version 8 blocks (locktime median past) + // once the majority of blocks are using it. + // if (this.version < 8 && prev.isOutdated(8)) { + // this.chain.emit('debug', 'Block is outdated (v8): %s', this.rhash); + // return false; + // } + + // Make sure the height contained in the coinbase is correct. if (this.version >= 2 && prev.isUpgraded(2)) { cb = bcoin.script.isCoinbase(this.txs[0].inputs[0].script, this); + // Make sure the coinbase is parseable. if (!cb) { - console.log('BAD COINBASE: %s', height); + this.chain.emit('debug', 'Block has malformed coinbase: %s', this.rhash); return false; } + // Make sure coinbase height is equal to the actual height. if (cb.height !== height) { - console.log('BAD COINBASE HEIGHT: %s', height); + this.chain.emit('debug', 'Block has bad coinbase height: %s', this.rhash); return false; } } // Signature validation is now enforced (bip66) - if (this.version >= 3 && prev.isUpgraded(3)) - flags.strictder = true; + if (!(this.version >= 3 && prev.isUpgraded(3))) + flags.strictder = false; // CHECKLOCKTIMEVERIFY is now usable (bip65) - if (this.version >= 4 && prev.isUpgraded(4)) - flags.cltv = true; + if (!(this.version >= 4 && prev.isUpgraded(4))) + flags.cltv = false; - // Check for sigops limits - sigops = 0; + // Use nLockTime median past (bip113) + // https://github.com/btcdrak/bips/blob/d4c9a236ecb947866c61aefb868b284498489c2b/bip-0113.mediawiki + // Support version bits: + // https://gist.github.com/sipa/bf69659f43e763540550 + // http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010396.html + // if (this.version >= 8 && prev.isUpgraded(8)) + // flags.locktimeMedian = true; + + // If we are an ancestor of a checkpoint, we can + // skip the input verification. + if (height < network.checkpoints.lastHeight && !network.checkpoints[height]) + flags.scriptChecks = false; + + // Get timestamp for tx.isFinal(). + ts = flags.locktimeMedian + ? prev.getMedianTime() + : this.ts; + + // Check all transactions for (i = 0; i < this.txs.length; i++) { tx = this.txs[i]; + // Transactions must be finalized with + // regards to nSequence and nLockTime. + if (!tx.isFinal(height, ts)) { + this.chain.emit('debug', 'TX is not final: %s (%s)', this.rhash, i); + return false; + } + + // Check for tx sigops limits // Bitcoind does not check for this when accepting // a block even though it probably should. // if (tx.sigops(true) > constants.script.maxTxSigops) { // // Block 71036 abused checksig to // // include a huge number of sigops. + // this.chain.emit('debug', 'Block TX has too many sigops: %s', this.rhash); // if (!(network.type === 'main' && height === 71036)) // return false; // } + // Check for block sigops limits // Start counting P2SH sigops once block // timestamps reach March 31st, 2012. if (this.ts >= constants.block.bip16time) @@ -382,50 +423,46 @@ Block.prototype.postVerify = function postVerify() { sigops += tx.sigops(); if (sigops > constants.script.maxBlockSigops) { - console.log('BAD SIGOPS: %s', height); + this.chain.emit('debug', 'Block has too many sigops: %s', this.rhash); return false; } - } - // BIP30 - Ensure there are no duplicate txids - for (i = 0; i < this.txs.length; i++) { - tx = this.txs[i]; + // BIP30 - Ensure there are no duplicate txids if (this.chain.index[tx.hash('hex')]) { // Blocks 91842 and 91880 created duplicate // txids by carefully crafting the coinbases. - if (!(network.type === 'main' && height === 91842 && height === 91880)) + this.chain.emit('debug', 'Block is overwriting txids: %s', this.rhash); + if (!(network.type === 'main' && (height === 91842 || height === 91880))) return false; } - } - // If we are an ancestor of a checkpoint, - // we can skip the input verification. - if (height < network.checkpoints.lastHeight && !network.checkpoints[height]) - flags.noScriptChecks = true; - - // Verify the inputs of every tx (CheckInputs) - for (i = 0; i < this.txs.length; i++) { - tx = this.txs[i]; - - if (tx.isCoinbase()) - continue; - - if (flags.noScriptChecks) - continue; - - for (j = 0; j < tx.inputs.length; j++) { - input = tx.inputs[j]; - - if (!input.out.tx) + // Verify the inputs of every tx (CheckInputs) + if (flags.scriptChecks !== false) { + if (tx.isCoinbase()) continue; - assert(input.out.tx); + for (j = 0; j < tx.inputs.length; j++) { + input = tx.inputs[j]; - if (!tx.verify(j, true, flags)) - return false; + // We need the previous output in order + // to verify the script. + if (!input.out.tx) + continue; - // if (this.chain.isSpent(input.out.hash, input.out.index)) - // return false; + assert(input.out.tx); + + // Verify the script + if (!tx.verify(j, true, flags)) { + this.chain.emit('debug', 'Block has invalid inputs: %s', this.rhash); + return false; + } + + // Ensure tx is not double spending an output + // if (this.chain.isSpent(input.out.hash, input.out.index)) { + // this.chain.emit('debug', 'Block is using spent inputs: %s', this.rhash); + // return false; + // } + } } } diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 5cf1a77c..623c811a 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -50,6 +50,12 @@ function Chain(options) { this.request = new utils.RequestCache(); + this.fromJSON(require('./protocol/preload-full')); + this.storage = null; + //this.resetHeight(133000); + this.resetHeight(145000); + + if (0) this.fromJSON({ v: 2, type: 'chain', @@ -608,7 +614,10 @@ Chain.prototype.height = function height() { return this.getTip().height; }; -// /home/chjj/bitcoin/src/pow.cpp +Chain.prototype.currentTarget = function currentTarget() { + return this.target(this.getTip()); +}; + Chain.prototype.target = function target(last, block) { var powLimit = utils.toCompact(network.powLimit); var ts, first, i; diff --git a/lib/bcoin/miner.js b/lib/bcoin/miner.js index 943559e5..0d1f8036 100644 --- a/lib/bcoin/miner.js +++ b/lib/bcoin/miner.js @@ -139,7 +139,9 @@ Miner.prototype.addBlock = function addBlock(block) { }; Miner.prototype.addTX = function addTX(tx) { - var full = this.index.inputs.every(function(input) { + var full, ts; + + full = this.index.inputs.every(function(input) { return !!input.out.tx; }); @@ -160,7 +162,12 @@ Miner.prototype.addTX = function addTX(tx) { if (tx.isCoinbase()) return; - if (!tx.isFinal(this.block, this.last)) + // Get timestamp for tx.isFinal() - bip113 + ts = this.block.version === 8 + ? this.last.getMedianTime() + : this.block.ts; + + if (!tx.isFinal(this.last.height + 1, ts)) return; // Deliver me from the block size debate, please diff --git a/lib/bcoin/peer.js b/lib/bcoin/peer.js index a5fc2133..818e8172 100644 --- a/lib/bcoin/peer.js +++ b/lib/bcoin/peer.js @@ -548,6 +548,10 @@ Peer.prototype.loadHeaders = function loadHeaders(hashes, stop) { this.emit('debug', 'Requesting headers packet from %s with getheaders', this.host); + this.pool.emit('debug', 'Height: %s, Hash: %s, Stop: %s', + this.pool.chain.getHeight(hashes[0]), + hashes ? utils.revHex(hashes[0]) : 0, + stop ? utils.revHex(stop) : 0); this._write(this.framer.getHeaders(hashes, stop)); }; @@ -555,6 +559,10 @@ Peer.prototype.loadBlocks = function loadBlocks(hashes, stop) { this.emit('debug', 'Requesting inv packet from %s with getblocks', this.host); + this.pool.emit('debug', 'Height: %s, Hash: %s, Stop: %s', + this.pool.chain.getHeight(hashes[0]), + hashes ? utils.revHex(hashes[0]) : 0, + stop ? utils.revHex(stop) : 0); this._write(this.framer.getBlocks(hashes, stop)); }; @@ -571,6 +579,13 @@ Peer.prototype.loadMempool = function loadMempool() { this._write(this.framer.mempool()); }; +Peer.prototype.reject = function reject(details) { + this.emit('debug', + 'Sending reject packet to %s', + this.host); + this._write(this.framer.reject(details)); +}; + /** * Expose */ diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index 84aa8837..4e3bad5f 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -42,7 +42,7 @@ function Pool(options) { this.destroyed = false; this.size = options.size || 32; this.parallel = options.parallel || 2000; - this.redundancy = options.redundancy || 2; + this.redundancy = options.redundancy || 1; this.seeds = options.seeds ? options.seeds.slice() : network.seeds.slice(); @@ -320,10 +320,14 @@ Pool.prototype._addLoader = function _addLoader() { }); peer.on('merkleblock', function(block) { + self._startInterval(); + self._startTimer(); self._handleBlock(block, peer); }); peer.on('block', function(block) { + self._startInterval(); + self._startTimer(); self._handleBlock(block, peer); }); @@ -346,7 +350,6 @@ Pool.prototype._addLoader = function _addLoader() { }; Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) { - var reqs = 0; var i, header, last, block; assert(this.options.headers); @@ -375,10 +378,8 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) { if (!block.verify()) break; - if (!this.chain.has(block)) { + if (!this.chain.has(block)) this._request(this.block.type, block.hash('hex')); - reqs++; - } last = block; } @@ -401,15 +402,9 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) { // Reset timeout to avoid killing the loader this._startTimer(); - - this.emit('debug', - 'Requesting %s block packets from %s with getdata', - reqs, peer.host - ); }; Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) { - var reqs = 0; var i, hash; assert(!this.options.headers); @@ -435,7 +430,6 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) { // Request block if we don't have it if (!this.chain.has(hash)) { this._request(this.block.type, hash); - reqs++; continue; } @@ -457,11 +451,6 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) { // Reset timeout to avoid killing the loader this._startTimer(); - - this.emit('debug', - 'Requesting %s block packets from %s with getdata', - reqs, peer.host - ); }; Pool.prototype._handleInv = function _handleInv(hashes, peer) { @@ -490,10 +479,6 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) { var requested = this._response(block); - // Someone is sending us blocks without us requesting them. - if (!requested) - return; - // Emulate bip37 - emit all the "watched" txs if (this.options.fullNode && this.listeners('watched').length > 0) { block.txs.forEach(function(tx) { @@ -503,15 +488,21 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) { } // Ignore if we already have - if (this.chain.has(block)) + if (this.chain.has(block)) { + this.emit('debug', 'Already have block %s (%s)', block.height, peer.host); return; + } // Make sure the block is valid if (!block.verify()) { - this.emit('debug', 'Block verification failed for %s', block.hash('hex')); + this.emit('debug', 'Block verification failed for %s (%s)', block.rhash, peer.host); return; } + // Someone is sending us blocks without us requesting them. + if (!requested) + this.emit('debug', 'Recieved unrequested block: %s (%s)', block.rhash, peer.host); + // Resolve orphan chain if (!this.options.headers) { if (!this.chain.hasBlock(block.prevBlock)) { @@ -521,10 +512,11 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) { // the height until later. if (this._addIndex(block, peer)) this.emit('pool block', block, peer); - peer.loadBlocks( + this.peers.load.loadBlocks( this.chain.locatorHashes(), this.chain.getOrphanRoot(block) ); + this.emit('debug', 'Handled orphan %s (%s)', block.rhash, peer.host); return; } } @@ -786,11 +778,6 @@ Pool.prototype._removePeer = function _removePeer(peer) { if (this.peers.load === peer) { this.emit('debug', 'Removed loader peer (%s).', peer.host); this.peers.load = null; - // i = this.seeds.indexOf(peer.host); - // if (i === -1) - // i = this.seeds.indexOf(peer.host + ':' + peer.port); - // if (i !== -1) - // this.seeds.splice(i, 1); } }; @@ -1236,6 +1223,9 @@ Pool.prototype._doRequests = function _doRequests() { if (above && below && this.load.hiReached) this._load(); + if (items.length === 0) + return; + if (this.options.multiplePeers) { mapReq = function(item) { return item.start(this.peers.block[i]); @@ -1258,6 +1248,12 @@ Pool.prototype._doRequests = function _doRequests() { return item.start(this.peers.load); }, this); + this.emit('debug', + 'Requesting %s/%s items from %s with getdata', + req.length, + this.request.queue.length, + this.peers.load.host); + this.peers.load.getData(req); }; @@ -1506,16 +1502,17 @@ LoadRequest.prototype.start = function start(peer) { var reqType; assert(!this.active); + assert(!this.timer); + assert(!this.peer); + this.active = true; this.pool.request.active++; - assert(!this.timer); - this.timer = setTimeout(function() { - self.timer = null; - self.retry(); - }, this.pool.requestTimeout); + // this.timer = setTimeout(function() { + // self.timer = null; + // self.retry(); + // }, this.pool.requestTimeout); - assert(!this.peer); this.peer = peer; this.peer.once('close', this.onclose); diff --git a/lib/bcoin/protocol/constants.js b/lib/bcoin/protocol/constants.js index 0ad589a7..2afebb3d 100644 --- a/lib/bcoin/protocol/constants.js +++ b/lib/bcoin/protocol/constants.js @@ -5,6 +5,7 @@ */ var bcoin = require('../../bcoin'); +var bn = require('bn.js'); var utils = bcoin.utils; var i; @@ -219,3 +220,7 @@ exports.zeroHash = utils.toArray( exports.userVersion = require('../../../package.json').version; exports.userAgent = '/bcoin:' + exports.userVersion + '/'; + +exports.coin = new bn(10000000).muln(10); +exports.cent = new bn(1000000); +exports.maxMoney = new bn(21000000).mul(exports.coin); diff --git a/lib/bcoin/protocol/framer.js b/lib/bcoin/protocol/framer.js index dfb49abf..fa7faed9 100644 --- a/lib/bcoin/protocol/framer.js +++ b/lib/bcoin/protocol/framer.js @@ -357,6 +357,32 @@ Framer.prototype.merkleBlock = function merkleBlock(block) { return this.packet('merkleblock', Framer.block(block, 'merkleblock')); }; +Framer.prototype.reject = function reject(details) { + var p = []; + var off = 0; + + var message = details.message || ''; + var ccode = constants.reject[details.ccode] || constants.reject.malformed; + var reason = details.reason || ''; + var data = details.data || []; + + off += utils.writeIntv(p, message.length, off); + utils.writeAscii(p, message, off); + off += message.length; + + p[off] = ccode; + off++; + + off += utils.writeIntv(p, reason.length, off); + utils.writeAscii(p, reason, off); + off += reason.length; + + utils.copy(data, p, off, true); + off += data.length; + + return this.packet('reject', p); +}; + Framer.prototype.addr = function addr(peers) { var p = []; var off = 0; diff --git a/lib/bcoin/protocol/parser.js b/lib/bcoin/protocol/parser.js index 868cb0da..25a61d55 100644 --- a/lib/bcoin/protocol/parser.js +++ b/lib/bcoin/protocol/parser.js @@ -295,12 +295,12 @@ Parser.prototype.parseBlock = function parseBlock(p) { off = result.off; totalTX = result.r; - if (p.length >= off + 10) { - for (i = 0; i < totalTX; i++) { - tx = this.parseTX(p.slice(off)); - off += tx._off; - txs.push(tx); - } + for (i = 0; i < totalTX; i++) { + tx = this.parseTX(p.slice(off)); + if (!tx) + return this._error('Invalid tx count for block'); + off += tx._off; + txs.push(tx); } return { diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 59b24225..0bcfa6e3 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -686,8 +686,13 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) { if (!constants.hashTypeByVal[type & 0x1f]) return false; - if (!script.isValidSig(sig)) - return false; + if (flags.strictder !== false) { + if (!script.isValidSig(sig)) + return false; + } else { + if (!script.isSig(sig)) + return false; + } subscript = script.subscript(s, lastSep); hash = tx.subscriptHash(index, subscript, type); @@ -743,8 +748,13 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) { if (!constants.hashTypeByVal[type & 0x1f]) return false; - if (!script.isValidSig(sig)) - return false; + if (flags.strictder !== false) { + if (!script.isValidSig(sig)) + return false; + } else { + if (!script.isSig(sig)) + return false; + } hash = tx.subscriptHash(index, subscript, type); @@ -775,6 +785,9 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) { } case 'checklocktimeverify': { // OP_CHECKLOCKTIMEVERIFY = OP_NOP2 + if (flags.cltv === false) + break; + if (!tx || stack.length === 0) return false; @@ -1298,6 +1311,16 @@ script.isCoinbase = function isCoinbase(s, block) { return coinbase; }; +script.isSig = function isSig(sig, allowZero) { + if (!Array.isArray(sig)) + return false; + + if (allowZero && sig.length === 0) + return true; + + return 9 <= sig.length && sig.length <= 73; +}; + // https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki /** * A canonical signature exists of: <30> <02> <02> diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index ebc52b45..53ed14f7 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -838,29 +838,29 @@ TX.prototype.funds = function funds(side) { // Used for postVerify/ContextualBlockCheck and miner isFinalTx call. // BIP113 will require that time-locked transactions have nLockTime set to // less than the median time of the previous block they're contained in. -TX.prototype.isFinal = function isFinal(block, prev) { +TX.prototype.isFinalBlock = function isFinalBlock(block, prev, useMedian) { var height = prev.height + 1; - var ts = this.locktimeMedian ? prev.getMedianTime() : block.ts; - return this._isFinal(height, ts); + var ts = useMedian ? prev.getMedianTime() : block.ts; + return this.isFinal(height, ts); }; // Used in AcceptToMemoryPool -TX.prototype.isFinalAccept = function isFinalAccept() { +TX.prototype.isFinalMempool = function isFinalMempool(useMedian) { var height = this.chain.height() + 1; - var ts = this.lockTimeMedian + var ts = useMedian ? this.chain.getTip().getMedianTime() : utils.now(); - return this._isFinalTx(height, ts); + return this.isFinal(height, ts); }; // Used in the original bitcoind code for AcceptBlock -TX.prototype._isFinalOriginal = function _isFinalOriginal(block) { +TX.prototype.isFinalLegacy = function isFinalLegacy(block) { var ts = block ? block.ts : utils.now(); var height = this.chain.height(); - return this._isFinalTx(height, ts); + return this.isFinal(height, ts); }; -TX.prototype._isFinal = function _isFinal(height, ts) { +TX.prototype.isFinal = function isFinal(height, ts) { var threshold = constants.locktimeThreshold; var i; diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index 497972a9..2f8da9df 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -81,7 +81,7 @@ function Wallet(options, passphrase) { this.m = 1; this.n = 1; - this.prefix = 'bt/' + this.getOwnAddress() + '/'; + this.prefix = 'bt/wallet/' + this.getOwnAddress() + '/'; this.multisig(options.multisig || {});