db: drop old migrations. avoid using encoding.

This commit is contained in:
Christopher Jeffrey 2017-12-05 03:14:34 -08:00
parent 83e1de2e98
commit cb978df380
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
41 changed files with 153 additions and 2263 deletions

View File

@ -1,11 +1,11 @@
'use strict';
const random = require('bcrypto/lib/random');
const Address = require('../lib/primitives/address');
const TX = require('../lib/primitives/tx');
const Script = require('../lib/script/script');
const MTX = require('../lib/primitives/mtx');
const encoding = require('../lib/utils/encoding');
const random = require('bcrypto/lib/random');
const consensus = require('../lib/protocol/consensus');
const common = require('../test/util/common');
const bench = require('./bench');
@ -156,7 +156,7 @@ const mtx = new MTX();
for (let i = 0; i < 100; i++) {
mtx.addInput({
prevout: {
hash: encoding.NULL_HASH,
hash: consensus.NULL_HASH,
index: 0
},
script: new Script()

View File

@ -17,13 +17,13 @@ const UndoCoins = require('../coins/undocoins');
const layout = require('./layout');
const LRU = require('../utils/lru');
const util = require('../utils/util');
const consensus = require('../protocol/consensus');
const Block = require('../primitives/block');
const Outpoint = require('../primitives/outpoint');
const Address = require('../primitives/address');
const ChainEntry = require('./chainentry');
const TXMeta = require('../primitives/txmeta');
const CoinEntry = require('../coins/coinentry');
const {encoding} = bio;
/**
* ChainDB
@ -255,7 +255,7 @@ class ChainDB {
assert(typeof hash === 'string');
if (hash === encoding.NULL_HASH)
if (hash === consensus.NULL_HASH)
return -1;
const entry = this.cacheHash.get(hash);
@ -348,7 +348,7 @@ class ChainDB {
async getEntryByHash(hash) {
assert(typeof hash === 'string');
if (hash === encoding.NULL_HASH)
if (hash === consensus.NULL_HASH)
return null;
const cache = this.cacheHash.get(hash);
@ -827,7 +827,7 @@ class ChainDB {
async isMainHash(hash) {
assert(typeof hash === 'string');
if (hash === encoding.NULL_HASH)
if (hash === consensus.NULL_HASH)
return false;
if (hash === this.network.genesis.hash)
@ -2129,7 +2129,7 @@ class ChainState {
*/
constructor() {
this.tip = encoding.NULL_HASH;
this.tip = consensus.NULL_HASH;
this.tx = 0;
this.coin = 0;
this.value = 0;

View File

@ -15,7 +15,6 @@ const hash256 = require('bcrypto/lib/hash256');
const util = require('../utils/util');
const Headers = require('../primitives/headers');
const InvItem = require('../primitives/invitem');
const {encoding} = bio;
/*
* Constants
@ -51,10 +50,10 @@ class ChainEntry {
*/
constructor(options) {
this.hash = encoding.NULL_HASH;
this.hash = consensus.NULL_HASH;
this.version = 1;
this.prevBlock = encoding.NULL_HASH;
this.merkleRoot = encoding.NULL_HASH;
this.prevBlock = consensus.NULL_HASH;
this.merkleRoot = consensus.NULL_HASH;
this.time = 0;
this.bits = 0;
this.nonce = 0;

View File

@ -16,10 +16,10 @@ const cleanse = require('bcrypto/lib/cleanse');
const random = require('bcrypto/lib/random');
const secp256k1 = require('bcrypto/lib/secp256k1');
const Network = require('../protocol/network');
const consensus = require('../protocol/consensus');
const common = require('./common');
const Mnemonic = require('./mnemonic');
const HDPublicKey = require('./public');
const {encoding} = bio;
/*
* Constants
@ -53,8 +53,8 @@ class HDPrivateKey {
this.depth = 0;
this.parentFingerPrint = 0;
this.childIndex = 0;
this.chainCode = encoding.ZERO_HASH;
this.privateKey = encoding.ZERO_HASH;
this.chainCode = consensus.ZERO_HASH;
this.privateKey = consensus.ZERO_HASH;
this.publicKey = common.ZERO_KEY;
this.fingerPrint = -1;

View File

@ -15,8 +15,8 @@ const hash256 = require('bcrypto/lib/hash256');
const cleanse = require('bcrypto/lib/cleanse');
const secp256k1 = require('bcrypto/lib/secp256k1');
const Network = require('../protocol/network');
const consensus = require('../protocol/consensus');
const common = require('./common');
const {encoding} = bio;
/**
* HDPublicKey
@ -45,7 +45,7 @@ class HDPublicKey {
this.depth = 0;
this.parentFingerPrint = 0;
this.childIndex = 0;
this.chainCode = encoding.ZERO_HASH;
this.chainCode = consensus.ZERO_HASH;
this.publicKey = common.ZERO_KEY;
this.fingerPrint = -1;

View File

@ -11,12 +11,14 @@ const bdb = require('bdb');
/*
* Database Layout:
* V -> db version
* v -> serialization version
* R -> tip hash
* e[hash] -> entry
*/
const layout = {
V: bdb.key('v'),
V: bdb.key('V'),
v: bdb.key('v'),
R: bdb.key('R'),
F: bdb.key('F'),
e: bdb.key('e', ['hash256'])

View File

@ -2389,7 +2389,7 @@ class MempoolCache {
}
async getVersion() {
const data = await this.db.get(layout.V.build());
const data = await this.db.get(layout.v.build());
if (!data)
return -1;
@ -2412,7 +2412,8 @@ class MempoolCache {
if (!data)
return null;
let fees;
let fees = null;
try {
fees = Fees.fromRaw(data);
} catch (e) {
@ -2444,6 +2445,8 @@ class MempoolCache {
return;
await this.db.open();
await this.db.verify(layout.V.build(), 'mempool', 0);
await this.verify();
this.batch = this.db.batch();
@ -2502,7 +2505,7 @@ class MempoolCache {
async init(hash) {
const batch = this.db.batch();
batch.put(layout.V.build(), encoding.u32(MempoolCache.VERSION));
batch.put(layout.v.build(), encoding.u32(MempoolCache.VERSION));
batch.put(layout.R.build(), Buffer.from(hash, 'hex'));
await batch.write();
}
@ -2554,7 +2557,7 @@ class MempoolCache {
for (const key of keys)
batch.del(key);
batch.put(layout.V.build(), encoding.u32(MempoolCache.VERSION));
batch.put(layout.v.build(), encoding.u32(MempoolCache.VERSION));
batch.put(layout.R.build(), Buffer.from(this.chain.tip.hash, 'hex'));
batch.del(layout.F.build());

View File

@ -22,7 +22,11 @@ const policy = require('../protocol/policy');
const CoinView = require('../coins/coinview');
const Script = require('../script/script');
const common = require('./common');
const {encoding} = bio;
/*
* Constants
*/
const DUMMY = Buffer.alloc(0);
/**
@ -38,12 +42,12 @@ class BlockTemplate {
*/
constructor(options) {
this.prevBlock = encoding.NULL_HASH;
this.prevBlock = consensus.NULL_HASH;
this.version = 1;
this.height = 0;
this.time = 0;
this.bits = 0;
this.target = encoding.ZERO_HASH;
this.target = consensus.ZERO_HASH;
this.locktime = 0;
this.mtp = 0;
this.flags = 0;
@ -55,7 +59,7 @@ class BlockTemplate {
this.interval = 210000;
this.fees = 0;
this.tree = new MerkleTree();
this.commitment = encoding.ZERO_HASH;
this.commitment = consensus.ZERO_HASH;
this.left = DUMMY;
this.right = DUMMY;
this.items = [];
@ -172,10 +176,10 @@ class BlockTemplate {
*/
getWitnessHash() {
const nonce = encoding.ZERO_HASH;
const nonce = consensus.ZERO_HASH;
const leaves = [];
leaves.push(encoding.ZERO_HASH);
leaves.push(consensus.ZERO_HASH);
for (const {tx} of this.items)
leaves.push(tx.witnessHash());
@ -260,7 +264,7 @@ class BlockTemplate {
// Set up the witness nonce.
if (this.witness) {
input.witness.push(encoding.ZERO_HASH);
input.witness.push(consensus.ZERO_HASH);
input.witness.compile();
}
@ -439,7 +443,7 @@ class BlockTemplate {
if (this.witness) {
const input = tx.inputs[0];
input.witness.push(encoding.ZERO_HASH);
input.witness.push(consensus.ZERO_HASH);
input.witness.compile();
tx.refresh();
}
@ -723,7 +727,7 @@ class MerkleTree {
fromItems(items) {
const leaves = [];
leaves.push(encoding.ZERO_HASH);
leaves.push(consensus.ZERO_HASH);
for (const item of items)
leaves.push(item.tx.hash());
@ -738,7 +742,7 @@ class MerkleTree {
fromBlock(txs) {
const leaves = [];
leaves.push(encoding.ZERO_HASH);
leaves.push(consensus.ZERO_HASH);
for (let i = 1; i < txs.length; i++) {
const tx = txs[i];
@ -756,7 +760,7 @@ class MerkleTree {
let len = leaves.length;
while (len > 1) {
const hashes = [encoding.ZERO_HASH];
const hashes = [consensus.ZERO_HASH];
this.steps.push(leaves[1]);

View File

@ -22,9 +22,9 @@ const hash160 = require('bcrypto/lib/hash160');
const hash256 = require('bcrypto/lib/hash256');
const random = require('bcrypto/lib/random');
const secp256k1 = require('bcrypto/lib/secp256k1');
const consensus = require('../protocol/consensus');
const packets = require('./packets');
const common = require('./common');
const {encoding} = bio;
/**
* BIP150
@ -129,7 +129,7 @@ class BIP150 extends EventEmitter {
assert(!this.challengeReceived, 'Peer challenged twice.');
this.challengeReceived = true;
if (hash.equals(encoding.ZERO_HASH))
if (hash.equals(consensus.ZERO_HASH))
throw new Error('Auth failure.');
const msg = this.hash(this.input.sid, type, this.publicKey);
@ -205,7 +205,7 @@ class BIP150 extends EventEmitter {
const match = this.findAuthorized(hash);
if (!match)
return encoding.ZERO_HASH;
return consensus.ZERO_HASH;
this.peerIdentity = match;

View File

@ -554,7 +554,7 @@ class TXRequest {
*/
constructor(options) {
this.hash = encoding.NULL_HASH;
this.hash = consensus.NULL_HASH;
this.indexes = [];
if (options)
@ -749,7 +749,7 @@ class TXResponse {
*/
constructor(options) {
this.hash = encoding.NULL_HASH;
this.hash = consensus.NULL_HASH;
this.txs = [];
if (options)

View File

@ -18,6 +18,7 @@ const common = require('./common');
const util = require('../utils/util');
const bip152 = require('./bip152');
const NetAddress = require('./netaddress');
const consensus = require('../protocol/consensus');
const Headers = require('../primitives/headers');
const InvItem = require('../primitives/invitem');
const MemBlock = require('../primitives/memblock');
@ -1019,7 +1020,7 @@ class GetBlocksPacket extends Packet {
for (const hash of this.locator)
bw.writeHash(hash);
bw.writeHash(this.stop || encoding.ZERO_HASH);
bw.writeHash(this.stop || consensus.ZERO_HASH);
return bw;
}
@ -1052,7 +1053,7 @@ class GetBlocksPacket extends Packet {
this.stop = br.readHash('hex');
if (this.stop === encoding.NULL_HASH)
if (this.stop === consensus.NULL_HASH)
this.stop = null;
return this;
@ -2853,7 +2854,7 @@ class AuthChallengePacket extends Packet {
this.cmd = 'authchallenge';
this.type = exports.types.AUTHCHALLENGE;
this.hash = hash || encoding.ZERO_HASH;
this.hash = hash || consensus.ZERO_HASH;
}
/**
@ -3043,7 +3044,7 @@ class AuthProposePacket extends Packet {
this.cmd = 'authpropose';
this.type = exports.types.AUTHPROPOSE;
this.hash = hash || encoding.ZERO_HASH;
this.hash = hash || consensus.ZERO_HASH;
}
/**

View File

@ -11,7 +11,6 @@ const bweb = require('bweb');
const {Lock} = require('bmutex');
const IP = require('binet');
const Validator = require('bval');
const {encoding} = require('bufio');
const hash160 = require('bcrypto/lib/hash160');
const hash256 = require('bcrypto/lib/hash256');
const ccmp = require('bcrypto/lib/ccmp');
@ -2432,7 +2431,7 @@ class RPC extends RPCBase {
this.logger.debug(tx);
// Recreate witness nonce (all zeroes).
input.witness.push(encoding.ZERO_HASH);
input.witness.push(consensus.ZERO_HASH);
input.witness.compile();
tx.refresh();
@ -2705,7 +2704,7 @@ class RPC extends RPCBase {
bits: entry.bits,
difficulty: toDifficulty(entry.bits),
chainwork: entry.chainwork.toString('hex', 64),
previousblockhash: entry.prevBlock !== encoding.NULL_HASH
previousblockhash: entry.prevBlock !== consensus.NULL_HASH
? util.revHex(entry.prevBlock)
: null,
nextblockhash: next ? util.revHex(next) : null
@ -2743,7 +2742,7 @@ class RPC extends RPCBase {
bits: entry.bits,
difficulty: toDifficulty(entry.bits),
chainwork: entry.chainwork.toString('hex', 64),
previousblockhash: entry.prevBlock !== encoding.NULL_HASH
previousblockhash: entry.prevBlock !== consensus.NULL_HASH
? util.revHex(entry.prevBlock)
: null,
nextblockhash: next ? util.revHex(next) : null

View File

@ -13,7 +13,6 @@ const bio = require('bufio');
const util = require('../utils/util');
const InvItem = require('./invitem');
const consensus = require('../protocol/consensus');
const {encoding} = bio;
/**
* Abstract Block
@ -36,8 +35,8 @@ class AbstractBlock {
constructor() {
this.version = 1;
this.prevBlock = encoding.NULL_HASH;
this.merkleRoot = encoding.NULL_HASH;
this.prevBlock = consensus.NULL_HASH;
this.merkleRoot = consensus.NULL_HASH;
this.time = 0;
this.bits = 0;
this.nonce = 0;

View File

@ -14,7 +14,7 @@ const sha256 = require('bcrypto/lib/sha256');
const hash160 = require('bcrypto/lib/hash160');
const hash256 = require('bcrypto/lib/hash256');
const Network = require('../protocol/network');
const {encoding} = bio;
const consensus = require('../protocol/consensus');
/*
* Constants
@ -96,7 +96,7 @@ class Address {
return this.hash.equals(ZERO_HASH160);
if (this.hash.length === 32)
return this.hash.equals(encoding.ZERO_HASH);
return this.hash.equals(consensus.ZERO_HASH);
for (let i = 0; i < this.hash.length; i++) {
if (this.hash[i] !== 0)

View File

@ -294,7 +294,7 @@ class Block extends AbstractBlock {
*/
createWitnessNonce() {
return Buffer.from(encoding.ZERO_HASH);
return Buffer.from(consensus.ZERO_HASH);
}
/**
@ -310,7 +310,7 @@ class Block extends AbstractBlock {
assert(nonce, 'No witness nonce present.');
leaves.push(encoding.ZERO_HASH);
leaves.push(consensus.ZERO_HASH);
for (let i = 1; i < this.txs.length; i++) {
const tx = this.txs[i];

View File

@ -13,7 +13,7 @@ const util = require('../utils/util');
const Amount = require('../btc/amount');
const Output = require('./output');
const Network = require('../protocol/network');
const {encoding} = bio;
const consensus = require('../protocol/consensus');
/**
* Coin
@ -42,7 +42,7 @@ class Coin extends Output {
this.version = 1;
this.height = -1;
this.coinbase = false;
this.hash = encoding.NULL_HASH;
this.hash = consensus.NULL_HASH;
this.index = 0;
if (options)

View File

@ -203,7 +203,7 @@ class MerkleBlock extends AbstractBlock {
const traverse = (height, pos) => {
if (bitsUsed >= flags.length * 8) {
failed = true;
return encoding.ZERO_HASH;
return consensus.ZERO_HASH;
}
const parent = (flags[bitsUsed / 8 | 0] >>> (bitsUsed % 8)) & 1;
@ -213,7 +213,7 @@ class MerkleBlock extends AbstractBlock {
if (height === 0 || !parent) {
if (hashUsed >= hashes.length) {
failed = true;
return encoding.ZERO_HASH;
return consensus.ZERO_HASH;
}
const hash = hashes[hashUsed];
@ -659,7 +659,7 @@ class MerkleBlock extends AbstractBlock {
class PartialTree {
constructor(root, matches, indexes, map) {
this.root = root ? root.toString('hex') : encoding.NULL_HASH;
this.root = root ? root.toString('hex') : consensus.NULL_HASH;
this.matches = matches || [];
this.indexes = indexes || [];
this.map = map || new Map();

View File

@ -9,7 +9,7 @@
const assert = require('assert');
const bio = require('bufio');
const util = require('../utils/util');
const {encoding} = bio;
const consensus = require('../protocol/consensus');
/**
* Outpoint
@ -28,7 +28,7 @@ class Outpoint {
*/
constructor(hash, index) {
this.hash = encoding.NULL_HASH;
this.hash = consensus.NULL_HASH;
this.index = 0xffffffff;
if (hash != null) {
@ -112,7 +112,7 @@ class Outpoint {
*/
isNull() {
return this.index === 0xffffffff && this.hash === encoding.NULL_HASH;
return this.index === 0xffffffff && this.hash === consensus.NULL_HASH;
}
/**

View File

@ -609,9 +609,9 @@ class TX {
signatureHashV1(index, prev, value, type) {
const input = this.inputs[index];
let prevouts = encoding.ZERO_HASH;
let sequences = encoding.ZERO_HASH;
let outputs = encoding.ZERO_HASH;
let prevouts = consensus.ZERO_HASH;
let sequences = consensus.ZERO_HASH;
let outputs = consensus.ZERO_HASH;
if (!(type & hashType.ANYONECANPAY)) {
if (this._hashPrevouts) {

View File

@ -226,6 +226,23 @@ exports.MAX_MULTISIG_PUBKEYS = 20;
exports.BIP16_TIME = 1333238400;
/**
* A hash of all zeroes.
* @const {Buffer}
* @default
*/
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.

View File

@ -14,7 +14,7 @@ const assert = require('assert');
const bio = require('bufio');
const util = require('../utils/util');
const TX = require('../primitives/tx');
const {encoding} = bio;
const consensus = require('../protocol/consensus');
/**
* Chain State
@ -28,7 +28,7 @@ class ChainState {
constructor() {
this.startHeight = 0;
this.startHash = encoding.NULL_HASH;
this.startHash = consensus.NULL_HASH;
this.height = 0;
this.marked = false;
}
@ -106,7 +106,7 @@ class BlockMeta {
*/
constructor(hash, height, time) {
this.hash = hash || encoding.NULL_HASH;
this.hash = hash || consensus.NULL_HASH;
this.height = height != null ? height : -1;
this.time = time || 0;
}

View File

@ -12,7 +12,6 @@ const bweb = require('bweb');
const {Lock} = require('bmutex');
const fs = require('bfile');
const Validator = require('bval');
const {encoding} = require('bufio');
const hash256 = require('bcrypto/lib/hash256');
const util = require('../utils/util');
const Amount = require('../btc/amount');
@ -24,6 +23,7 @@ const MTX = require('../primitives/mtx');
const Outpoint = require('../primitives/outpoint');
const Output = require('../primitives/output');
const TX = require('../primitives/tx');
const consensus = require('../protocol/consensus');
const pkg = require('../pkg');
const common = require('./common');
const RPCBase = bweb.RPC;
@ -1064,7 +1064,7 @@ class RPC extends RPCBase {
transactions: out,
lastblock: highest && highest.block
? util.revHex(highest.block)
: encoding.NULL_HASH
: consensus.NULL_HASH
};
}

View File

@ -16,8 +16,8 @@ const Coin = require('../primitives/coin');
const Outpoint = require('../primitives/outpoint');
const records = require('./records');
const layout = require('./layout').txdb;
const consensus = require('../protocol/consensus');
const policy = require('../protocol/policy');
const {encoding} = bio;
const {TXRecord} = records;
/**
@ -2556,7 +2556,7 @@ class BlockRecord {
*/
constructor(hash, height, time) {
this.hash = hash || encoding.NULL_HASH;
this.hash = hash || consensus.NULL_HASH;
this.height = height != null ? height : -1;
this.time = time || 0;
this.hashes = new Set();

View File

@ -60,7 +60,7 @@ class Wallet extends EventEmitter {
this.id = null;
this.watchOnly = false;
this.accountDepth = 0;
this.token = encoding.ZERO_HASH;
this.token = consensus.ZERO_HASH;
this.tokenDepth = 0;
this.master = new MasterKey();

View File

@ -1,110 +0,0 @@
'use strict';
const bcoin = require('../');
const assert = require('assert');
const bio = require('bufio');
let file = process.argv[2];
assert(typeof file === 'string', 'Please pass in a database path.');
file = file.replace(/\.ldb\/?$/, '');
const db = bcoin.ldb({
location: file,
db: 'leveldb',
compression: true,
cacheSize: 32 << 20,
createIfMissing: false,
bufferKeys: true
});
function makeKey(data) {
const height = data.readUInt32LE(1, true);
const key = Buffer.allocUnsafe(5);
key[0] = 0x48;
key.writeUInt32BE(height, 1, true);
return key;
}
async function checkVersion() {
console.log('Checking version.');
const data = await db.get('V');
if (!data)
return;
const ver = data.readUInt32LE(0, true);
if (ver !== 0)
throw Error(`DB is version ${ver}.`);
}
async function updateState() {
console.log('Updating chain state.');
const data = await db.get('R');
if (!data || data.length < 32)
throw new Error('No chain state.');
const hash = data.slice(0, 32);
let p = bio.write();
p.writeHash(hash);
p.writeU64(0);
p.writeU64(0);
p.writeU64(0);
p = p.render();
const batch = db.batch();
batch.put('R', p);
const ver = Buffer.allocUnsafe(4);
ver.writeUInt32LE(1, 0, true);
batch.put('V', ver);
await batch.write();
console.log('Updated chain state.');
}
async function updateEndian() {
const batch = db.batch();
let total = 0;
console.log('Updating endianness.');
console.log('Iterating...');
const iter = db.iterator({
gte: Buffer.from('4800000000', 'hex'),
lte: Buffer.from('48ffffffff', 'hex'),
values: true
});
while (await iter.next()) {
const {key, value} = iter;
batch.del(key);
batch.put(makeKey(key), value);
total++;
}
console.log('Migrating %d items.', total);
await batch.write();
console.log('Migrated endianness.');
}
(async () => {
await db.open();
console.log('Opened %s.', file);
await checkVersion();
await updateState();
await updateEndian();
})().then(() => {
console.log('Migration complete.');
process.exit(0);
});

View File

@ -1,274 +0,0 @@
'use strict';
const assert = require('assert');
const BDB = require('bdb');
const bio = require('bufio');
const networks = require('../lib/protocol/networks');
const OldCoins = require('./coins-old');
const Coins = require('../lib/coins/coins');
const UndoCoins = require('../lib/coins/undocoins');
const Coin = require('../lib/primitives/coin');
const Output = require('../lib/primitives/output');
const {encoding} = bio;
let file = process.argv[2];
let batch;
assert(typeof file === 'string', 'Please pass in a database path.');
file = file.replace(/\.ldb\/?$/, '');
const db = new BDB({
location: file,
db: 'leveldb',
compression: true,
cacheSize: 32 << 20,
createIfMissing: false,
bufferKeys: true
});
const options = {};
options.spv = process.argv.indexOf('--spv') !== -1;
options.prune = process.argv.indexOf('--prune') !== -1;
options.indexTX = process.argv.indexOf('--index-tx') !== -1;
options.indexAddress = process.argv.indexOf('--index-address') !== -1;
options.network = networks.main;
const index = process.argv.indexOf('--network');
if (index !== -1) {
options.network = networks[process.argv[index + 1]];
assert(options.network, 'Invalid network.');
}
async function updateVersion() {
console.log('Checking version.');
const data = await db.get('V');
if (!data)
throw new Error('No DB version found!');
let ver = data.readUInt32LE(0, true);
if (ver !== 1)
throw Error(`DB is version ${ver}.`);
ver = Buffer.allocUnsafe(4);
ver.writeUInt32LE(2, 0, true);
batch.put('V', ver);
}
async function checkTipIndex() {
const keys = await db.keys({
gte: pair('p', encoding.ZERO_HASH),
lte: pair('p', encoding.MAX_HASH)
});
if (keys.length === 0) {
console.log('No tip index found.');
console.log('Please run migrate/ensure-tip-index.js first!');
process.exit(1);
return undefined;
}
if (keys.length < 3) {
console.log('Note: please run ensure-tip-index.js if you haven\'t yet.');
return new Promise(r => setTimeout(r, 2000));
}
return undefined;
}
async function updateOptions() {
if (await db.has('O'))
return;
if (process.argv.indexOf('--network') === -1) {
console.log('Warning: no options found in chaindb.');
console.log('Make sure you selected the correct options');
console.log('which may include any of:');
console.log('`--network [name]`, `--spv`, `--witness`,');
console.log('`--prune`, `--index-tx`, and `--index-address`.');
console.log('Continuing migration in 5 seconds...');
await new Promise(r => setTimeout(r, 5000));
}
batch.put('O', defaultOptions());
}
async function updateDeployments() {
if (await db.has('v'))
return;
if (process.argv.indexOf('--network') === -1) {
console.log('Warning: no deployment table found.');
console.log('Make sure `--network` is set properly.');
console.log('Continuing migration in 5 seconds...');
await new Promise(r => setTimeout(r, 5000));
}
batch.put('v', defaultDeployments());
}
async function reserializeCoins() {
let total = 0;
const iter = db.iterator({
gte: pair('c', encoding.ZERO_HASH),
lte: pair('c', encoding.MAX_HASH),
values: true
});
while (await iter.next()) {
const {key, value} = iter;
const hash = key.toString('hex', 1, 33);
const old = OldCoins.fromRaw(value, hash);
const coins = new Coins();
coins.version = old.version;
coins.hash = old.hash;
coins.height = old.height;
coins.coinbase = old.coinbase;
for (let i = 0; i < old.outputs.length; i++) {
const coin = old.get(i);
if (!coin) {
coins.outputs.push(null);
continue;
}
const output = new Output();
output.script = coin.script;
output.value = coin.value;
if (!output.script.isUnspendable())
coins.addOutput(coin.index, output);
}
coins.cleanup();
batch.put(key, coins.toRaw());
if (++total % 100000 === 0)
console.log('Reserialized %d coins.', total);
}
console.log('Reserialized %d coins.', total);
}
async function reserializeUndo() {
let total = 0;
const iter = db.iterator({
gte: pair('u', encoding.ZERO_HASH),
lte: pair('u', encoding.MAX_HASH),
values: true
});
for (;;) {
const item = await iter.next();
if (!item)
break;
const br = bio.read(item.value);
const undo = new UndoCoins();
while (br.left()) {
undo.push(null);
injectCoin(undo.top(), Coin.fromReader(br));
}
batch.put(item.key, undo.toRaw());
if (++total % 10000 === 0)
console.log('Reserialized %d undo coins.', total);
}
console.log('Reserialized %d undo coins.', total);
}
function write(data, str, off) {
if (Buffer.isBuffer(str))
return str.copy(data, off);
return data.write(str, off, 'hex');
}
function pair(prefix, hash) {
const key = Buffer.allocUnsafe(33);
if (typeof prefix === 'string')
prefix = prefix.charCodeAt(0);
key[0] = prefix;
write(key, hash, 1);
return key;
}
function injectCoin(undo, coin) {
const output = new Output();
output.value = coin.value;
output.script = coin.script;
undo.output = output;
undo.version = coin.version;
undo.height = coin.height;
undo.coinbase = coin.coinbase;
}
function defaultOptions() {
const bw = bio.write();
let flags = 0;
if (options.spv)
flags |= 1 << 0;
flags |= 1 << 1;
if (options.prune)
flags |= 1 << 2;
if (options.indexTX)
flags |= 1 << 3;
if (options.indexAddress)
flags |= 1 << 4;
bw.writeU32(options.network.magic);
bw.writeU32(flags);
bw.writeU32(0);
return bw.render();
}
function defaultDeployments() {
const bw = bio.write();
bw.writeU8(options.network.deploys.length);
for (let i = 0; i < options.network.deploys.length; i++) {
const deployment = options.network.deploys[i];
bw.writeU8(deployment.bit);
bw.writeU32(deployment.startTime);
bw.writeU32(deployment.timeout);
}
return bw.render();
}
(async () => {
await db.open();
console.log('Opened %s.', file);
batch = db.batch();
await updateVersion();
await checkTipIndex();
await updateOptions();
await updateDeployments();
await reserializeCoins();
await reserializeUndo();
await batch.write();
})().then(() => {
console.log('Migration complete.');
process.exit(0);
});

View File

@ -16,7 +16,7 @@ if (process.argv.indexOf('-h') !== -1
}
const assert = require('assert');
const BDB = require('bdb');
const bdb = require('bdb');
const hash256 = require('bcrypto/lib/hash256');
const BN = require('bn.js');
const bio = require('bufio');
@ -27,7 +27,7 @@ const CoinEntry = require('../lib/coins/coinentry');
const UndoCoins = require('../lib/coins/undocoins');
const Block = require('../lib/primitives/block');
const LRU = require('../lib/utils/lru');
const {encoding} = bio;
const consensus = require('../lib/protocol/consensus');
const file = process.argv[2].replace(/\.ldb\/?$/, '');
const shouldPrune = process.argv.indexOf('--prune') !== -1;
@ -36,13 +36,12 @@ let hasIndex = false;
let hasPruned = false;
let hasSPV = false;
const db = new BDB({
const db = bdb.create({
location: file,
db: 'leveldb',
compression: true,
cacheSize: 32 << 20,
createIfMissing: false,
bufferKeys: true
createIfMissing: false
});
// \0\0migrate
@ -63,7 +62,7 @@ function writeJournal(batch, state, hash) {
const data = Buffer.allocUnsafe(34);
if (!hash)
hash = encoding.NULL_HASH;
hash = consensus.NULL_HASH;
data[0] = MIGRATION_ID;
data[1] = state;
@ -76,7 +75,7 @@ async function readJournal() {
const data = await db.get(JOURNAL_KEY);
if (!data)
return [STATE_VERSION, encoding.NULL_HASH];
return [STATE_VERSION, consensus.NULL_HASH];
if (data[0] !== MIGRATION_ID)
throw new Error('Bad migration id.');
@ -98,12 +97,12 @@ async function updateVersion() {
console.log('Checking version.');
const verRaw = await db.get('V');
const raw = await db.get('V');
if (!verRaw)
if (!raw)
throw new Error('No DB version found!');
const version = verRaw.readUInt32LE(0, true);
const version = raw.readUInt32LE(0, true);
if (version !== 2)
throw Error(`DB is version ${version}.`);
@ -121,14 +120,14 @@ async function updateVersion() {
await batch.write();
return [STATE_UNDO, encoding.NULL_HASH];
return [STATE_UNDO, consensus.NULL_HASH];
}
async function reserializeUndo(hash) {
let tip = await getTip();
const height = tip.height;
if (hash !== encoding.NULL_HASH)
if (hash !== consensus.NULL_HASH)
tip = await getEntry(hash);
console.log('Reserializing undo coins from tip %s.',
@ -256,16 +255,16 @@ async function reserializeUndo(hash) {
'Reserialized %d undo records (%d coins).',
total, totalCoins);
return [STATE_CLEANUP, encoding.NULL_HASH];
return [STATE_CLEANUP, consensus.NULL_HASH];
}
async function cleanupIndex() {
if (hasSPV)
return [STATE_COINS, encoding.NULL_HASH];
return [STATE_COINS, consensus.NULL_HASH];
const iter = db.iterator({
gte: pair(0x01, encoding.ZERO_HASH),
lte: pair(0x01, encoding.MAX_HASH),
gte: pair(0x01, consensus.ZERO_HASH),
lte: pair(0x01, Buffer.alloc(32, 0xff)),
keys: true
});
@ -292,23 +291,23 @@ async function cleanupIndex() {
console.log('Cleaned up %d undo records.', total);
return [STATE_COINS, encoding.NULL_HASH];
return [STATE_COINS, consensus.NULL_HASH];
}
async function reserializeCoins(hash) {
if (hasSPV)
return [STATE_ENTRY, encoding.NULL_HASH];
return [STATE_ENTRY, consensus.NULL_HASH];
const iter = db.iterator({
gte: pair('c', hash),
lte: pair('c', encoding.MAX_HASH),
lte: pair('c', Buffer.alloc(32, 0xff)),
keys: true,
values: true
});
let start = true;
if (hash !== encoding.NULL_HASH) {
if (hash !== consensus.NULL_HASH) {
const item = await iter.next();
if (!item)
start = false;
@ -369,19 +368,19 @@ async function reserializeCoins(hash) {
console.log('Reserialized %d coins.', total);
return [STATE_ENTRY, encoding.NULL_HASH];
return [STATE_ENTRY, consensus.NULL_HASH];
}
async function reserializeEntries(hash) {
const iter = db.iterator({
gte: pair('e', hash),
lte: pair('e', encoding.MAX_HASH),
lte: pair('e', Buffer.alloc(32, 0xff)),
values: true
});
let start = true;
if (hash !== encoding.NULL_HASH) {
if (hash !== consensus.NULL_HASH) {
const item = await iter.next();
if (!item)
start = false;
@ -420,7 +419,7 @@ async function reserializeEntries(hash) {
console.log('Reserialized %d entries.', total);
return [STATE_FINAL, encoding.NULL_HASH];
return [STATE_FINAL, consensus.NULL_HASH];
}
async function finalize() {
@ -433,7 +432,7 @@ async function finalize() {
batch.put('V', data);
// This has bugged me for a while.
batch.del(pair('n', encoding.ZERO_HASH));
batch.del(pair('n', consensus.ZERO_HASH));
if (shouldPrune) {
const data = await db.get('O');
@ -456,7 +455,7 @@ async function finalize() {
await db.compactRange();
return [STATE_DONE, encoding.NULL_HASH];
return [STATE_DONE, consensus.NULL_HASH];
}
async function getMeta(coin, prevout) {
@ -588,7 +587,7 @@ function entryFromRaw(data) {
entry.version = br.readU32();
entry.prevBlock = br.readHash('hex');
entry.merkleRoot = br.readHash('hex');
entry.ts = br.readU32();
entry.time = br.readU32();
entry.bits = br.readU32();
entry.nonce = br.readU32();
entry.height = br.readU32();
@ -603,7 +602,7 @@ function entryToRaw(entry, main) {
bw.writeU32(entry.version);
bw.writeHash(entry.prevBlock);
bw.writeHash(entry.merkleRoot);
bw.writeU32(entry.ts);
bw.writeU32(entry.time);
bw.writeU32(entry.bits);
bw.writeU32(entry.nonce);
bw.writeU32(entry.height);
@ -684,7 +683,7 @@ reserializeEntries;
// [state, hash] = await reserializeEntries(hash);
if (state === STATE_ENTRY)
[state, hash] = [STATE_FINAL, encoding.NULL_HASH];
[state, hash] = [STATE_FINAL, consensus.NULL_HASH];
if (state === STATE_FINAL)
[state, hash] = await finalize();

View File

@ -1,611 +0,0 @@
/*!
* coins.js - coins object for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
/* eslint-disable */
'use strict';
const assert = require('assert');
const bio = require('bufio');
const util = require('../lib/utils/util');
const Coin = require('../lib/primitives/coin');
const Output = require('../lib/primitives/output');
const {compress, decompress} = require('./compress-old');
const {encoding} = bio;
/**
* Represents the outputs for a single transaction.
* @exports Coins
* @constructor
* @param {TX|Object} tx/options - TX or options object.
* @property {Hash} hash - Transaction hash.
* @property {Number} version - Transaction version.
* @property {Number} height - Transaction height (-1 if unconfirmed).
* @property {Boolean} coinbase - Whether the containing
* transaction is a coinbase.
* @property {Coin[]} outputs - Coins.
*/
function Coins(options) {
if (!(this instanceof Coins))
return new Coins(options);
this.version = 1;
this.hash = encoding.NULL_HASH;
this.height = -1;
this.coinbase = true;
this.outputs = [];
if (options)
this.fromOptions(options);
}
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
Coins.prototype.fromOptions = function fromOptions(options) {
if (options.version != null) {
assert((options.version >>> 0) === options.version);
this.version = options.version;
}
if (options.hash) {
assert(typeof options.hash === 'string');
this.hash = options.hash;
}
if (options.height != null) {
assert(Number.isSafeInteger(options.height));
this.height = options.height;
}
if (options.coinbase != null) {
assert(typeof options.coinbase === 'boolean');
this.coinbase = options.coinbase;
}
if (options.outputs) {
assert(Array.isArray(options.outputs));
this.outputs = options.outputs;
}
return this;
};
/**
* Instantiate coins from options object.
* @param {Object} options
* @returns {Coins}
*/
Coins.fromOptions = function fromOptions(options) {
return new Coins().fromOptions(options);
};
/**
* Add a single coin to the collection.
* @param {Coin} coin
*/
Coins.prototype.add = function add(coin) {
if (this.outputs.length === 0) {
this.version = coin.version;
this.hash = coin.hash;
this.height = coin.height;
this.coinbase = coin.coinbase;
}
while (this.outputs.length <= coin.index)
this.outputs.push(null);
if (coin.script.isUnspendable()) {
this.outputs[coin.index] = null;
return;
}
this.outputs[coin.index] = CoinEntry.fromCoin(coin);
};
/**
* Test whether the collection has a coin.
* @param {Number} index
* @returns {Boolean}
*/
Coins.prototype.has = function has(index) {
if (index >= this.outputs.length)
return false;
return this.outputs[index] != null;
};
/**
* Get a coin.
* @param {Number} index
* @returns {Coin}
*/
Coins.prototype.get = function get(index) {
if (index >= this.outputs.length)
return;
const coin = this.outputs[index];
if (!coin)
return;
return coin.toCoin(this, index);
};
/**
* Remove a coin and return it.
* @param {Number} index
* @returns {Coin}
*/
Coins.prototype.spend = function spend(index) {
const coin = this.get(index);
if (!coin)
return;
this.outputs[index] = null;
return coin;
};
/**
* Count up to the last available index.
* @returns {Number}
*/
Coins.prototype.size = function size() {
let index = -1;
for (let i = this.outputs.length - 1; i >= 0; i--) {
const output = this.outputs[i];
if (output) {
index = i;
break;
}
}
return index + 1;
};
/**
* Test whether the coins are fully spent.
* @returns {Boolean}
*/
Coins.prototype.isEmpty = function isEmpty() {
return this.size() === 0;
};
/*
* Coins serialization:
* version: varint
* bits: uint32 (31-bit height | 1-bit coinbase-flag)
* spent-field: varint size | bitfield (0=unspent, 1=spent)
* outputs (repeated):
* compressed-script:
* prefix: 0x00 = varint size | raw script
* 0x01 = 20 byte pubkey hash
* 0x02 = 20 byte script hash
* 0x03 = 33 byte compressed key
* data: script data, dictated by the prefix
* value: varint
*
* The compression below sacrifices some cpu in exchange
* for reduced size, but in some cases the use of varints
* actually increases speed (varint versions and values
* for example). We do as much compression as possible
* without sacrificing too much cpu. Value compression
* is intentionally excluded for now as it seems to be
* too much of a perf hit. Maybe when v8 optimizes
* non-smi arithmetic better we can enable it.
*/
/**
* Serialize the coins object.
* @param {TX|Coins} tx
* @returns {Buffer}
*/
Coins.prototype.toRaw = function toRaw() {
const bw = bio.write();
const length = this.size();
const len = Math.ceil(length / 8);
// Return nothing if we're fully spent.
if (length === 0)
return;
// Varint version: hopefully we
// never run into `-1` versions.
bw.writeVarint(this.version);
// Create the `bits` value:
// (height | coinbase-flag).
let bits = this.height << 1;
// Append the coinbase bit.
if (this.coinbase)
bits |= 1;
if (bits < 0)
bits += 0x100000000;
// Making this a varint would actually
// make 99% of coins bigger. Varints
// are really only useful up until
// 0x10000, but since we're also
// storing the coinbase flag on the
// lo bit, varints are useless (and
// actually harmful) after height
// 32767 (0x7fff).
bw.writeU32(bits);
// Fill the spent field with zeroes to avoid
// allocating a buffer. We mark the spents
// after rendering the final buffer.
bw.writeVarint(len);
const start = bw.offset;
bw.fill(0, len);
// Write the compressed outputs.
for (let i = 0; i < length; i++) {
const output = this.outputs[i];
if (!output)
continue;
output.toWriter(bw);
}
// Render the buffer with all
// zeroes in the spent field.
const data = bw.render();
// Mark the spents in the spent field.
// This is essentially a NOP for new coins.
for (let i = 0; i < length; i++) {
const output = this.outputs[i];
if (output)
continue;
const bit = i % 8;
let oct = (i - bit) / 8;
oct += start;
data[oct] |= 1 << (7 - bit);
}
return data;
};
/**
* Parse serialized coins.
* @param {Buffer} data
* @param {Hash} hash
* @returns {Object} A "naked" coins object.
*/
Coins.prototype.fromRaw = function fromRaw(data, hash, index) {
const br = bio.read(data);
let pos = 0;
this.version = br.readVarint();
const bits = br.readU32();
this.height = bits >>> 1;
this.hash = hash;
this.coinbase = (bits & 1) !== 0;
// Mark the start of the spent field and
// seek past it to avoid reading a buffer.
const len = br.readVarint();
const start = br.offset;
br.seek(len);
while (br.left()) {
const bit = pos % 8;
let oct = (pos - bit) / 8;
oct += start;
// Read a single bit out of the spent field.
let spent = data[oct] >>> (7 - bit);
spent &= 1;
// Already spent.
if (spent) {
this.outputs.push(null);
pos++;
continue;
}
// Store the offset and size
// in the compressed coin object.
const coin = CoinEntry.fromReader(br);
this.outputs.push(coin);
pos++;
}
return this;
};
/**
* Parse a single serialized coin.
* @param {Buffer} data
* @param {Hash} hash
* @param {Number} index
* @returns {Coin}
*/
Coins.parseCoin = function parseCoin(data, hash, index) {
const br = bio.read(data);
const coin = new Coin();
let pos = 0;
coin.version = br.readVarint();
const bits = br.readU32();
coin.hash = hash;
coin.index = index;
coin.height = bits >>> 1;
coin.hash = hash;
coin.coinbase = (bits & 1) !== 0;
// Mark the start of the spent field and
// seek past it to avoid reading a buffer.
const len = br.readVarint();
const start = br.offset;
br.seek(len);
while (br.left()) {
const bit = pos % 8;
let oct = (pos - bit) / 8;
oct += start;
// Read a single bit out of the spent field.
let spent = data[oct] >>> (7 - bit);
spent &= 1;
// We found our coin.
if (pos === index) {
if (spent)
return;
decompress.script(coin.script, br);
coin.value = br.readVarint();
return coin;
}
// Already spent.
if (spent) {
pos++;
continue;
}
// Skip past the compressed coin.
skipCoin(br);
pos++;
}
};
/**
* Instantiate coins from a serialized Buffer.
* @param {Buffer} data
* @param {Hash} hash - Transaction hash.
* @returns {Coins}
*/
Coins.fromRaw = function fromRaw(data, hash) {
return new Coins().fromRaw(data, hash);
};
/**
* Inject properties from tx.
* @private
* @param {TX} tx
*/
Coins.prototype.fromTX = function fromTX(tx) {
this.version = tx.version;
this.hash = tx.hash('hex');
this.height = tx.height;
this.coinbase = tx.isCoinbase();
for (let i = 0; i < tx.outputs.length; i++) {
const output = tx.outputs[i];
if (output.script.isUnspendable()) {
this.outputs.push(null);
continue;
}
this.outputs.push(CoinEntry.fromTX(tx, i));
}
return this;
};
/**
* Instantiate a coins object from a transaction.
* @param {TX} tx
* @returns {Coins}
*/
Coins.fromTX = function fromTX(tx) {
return new Coins().fromTX(tx);
};
/**
* A compressed coin is an object which defers
* parsing of a coin. Say there is a transaction
* with 100 outputs. When a block comes in,
* there may only be _one_ input in that entire
* block which redeems an output from that
* transaction. When parsing the Coins, there
* is no sense to get _all_ of them into their
* abstract form. A compressed coin is just a
* pointer to that coin in the Coins buffer, as
* well as a size. Parsing is done only if that
* coin is being redeemed.
* @constructor
* @private
* @param {Number} offset
* @param {Number} size
* @param {Buffer} raw
*/
function CoinEntry() {
this.offset = 0;
this.size = 0;
this.raw = null;
this.output = null;
}
/**
* Parse the deferred data and return a Coin.
* @param {Coins} coins
* @param {Number} index
* @returns {Coin}
*/
CoinEntry.prototype.toCoin = function toCoin(coins, index) {
const coin = new Coin();
// Load in all necessary properties
// from the parent Coins object.
coin.version = coins.version;
coin.coinbase = coins.coinbase;
coin.height = coins.height;
coin.hash = coins.hash;
coin.index = index;
if (this.output) {
coin.script = this.output.script;
coin.value = this.output.value;
return coin;
}
const br = bio.read(this.raw);
// Seek to the coin's offset.
br.seek(this.offset);
decompress.script(coin.script, br);
coin.value = br.readVarint();
return coin;
};
/**
* Slice off the part of the buffer
* relevant to this particular coin.
*/
CoinEntry.prototype.toWriter = function toWriter(bw) {
if (this.output) {
compress.script(this.output.script, bw);
bw.writeVarint(this.output.value);
return;
}
assert(this.raw);
// If we read this coin from the db and
// didn't use it, it's still in its
// compressed form. Just write it back
// as a buffer for speed.
const raw = this.raw.slice(this.offset, this.offset + this.size);
bw.writeBytes(raw);
};
/**
* Instantiate compressed coin from reader.
* @param {BufferReader} br
* @returns {CoinEntry}
*/
CoinEntry.fromReader = function fromReader(br) {
const entry = new CoinEntry();
entry.offset = br.offset;
entry.size = skipCoin(br);
entry.raw = br.data;
return entry;
};
/**
* Instantiate compressed coin from tx.
* @param {TX} tx
* @param {Number} index
* @returns {CoinEntry}
*/
CoinEntry.fromTX = function fromTX(tx, index) {
const entry = new CoinEntry();
entry.output = tx.outputs[index];
return entry;
};
/**
* Instantiate compressed coin from coin.
* @param {Coin} coin
* @returns {CoinEntry}
*/
CoinEntry.fromCoin = function fromCoin(coin) {
const entry = new CoinEntry();
entry.output = new Output();
entry.output.script = coin.script;
entry.output.value = coin.value;
return entry;
};
/*
* Helpers
*/
function skipCoin(br) {
const start = br.offset;
// Skip past the compressed scripts.
switch (br.readU8()) {
case 0:
br.seek(br.readVarint());
break;
case 1:
case 2:
br.seek(20);
break;
case 3:
br.seek(33);
break;
default:
throw new Error('Bad prefix.');
}
// Skip past the value.
br.readVarint();
return br.offset - start;
}
/*
* Expose
*/
module.exports = Coins;

View File

@ -1,149 +0,0 @@
/*!
* coinview.js - coinview object for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
/* eslint-disable */
'use strict';
const assert = require('assert');
const Coins = require('./coins-old');
/**
* A collections of {@link Coins} objects.
* @exports CoinView
* @constructor
* @param {Object} coins - A hash-to-coins map.
* @property {Object} coins
*/
function CoinView(coins) {
if (!(this instanceof CoinView))
return new CoinView(coins);
this.coins = coins || {};
}
/**
* Add coins to the collection.
* @param {Coins} coins
*/
CoinView.prototype.add = function add(coins) {
this.coins[coins.hash] = coins;
};
/**
* Add a coin to the collection.
* @param {Coin} coin
*/
CoinView.prototype.addCoin = function addCoin(coin) {
assert(typeof coin.hash === 'string');
if (!this.coins[coin.hash])
this.coins[coin.hash] = new Coins();
this.coins[coin.hash].add(coin);
};
/**
* Add a tx to the collection.
* @param {TX} tx
*/
CoinView.prototype.addTX = function addTX(tx) {
this.add(Coins.fromTX(tx));
};
/**
* Get a coin.
* @param {Hash} hash
* @param {Number} index
* @returns {Coin}
*/
CoinView.prototype.get = function get(hash, index) {
const coins = this.coins[hash];
if (!coins)
return;
return coins.get(index);
};
/**
* Test whether the collection has a coin.
* @param {Hash} hash
* @param {Number} index
* @returns {Boolean}
*/
CoinView.prototype.has = function has(hash, index) {
const coins = this.coins[hash];
if (!coins)
return false;
return coins.has(index);
};
/**
* Remove a coin and return it.
* @param {Hash} hash
* @param {Number} index
* @returns {Coin}
*/
CoinView.prototype.spend = function spend(hash, index) {
const coins = this.coins[hash];
if (!coins)
return;
return coins.spend(index);
};
/**
* Fill transaction(s) with coins.
* @param {TX} tx
* @returns {Boolean} True if all inputs were filled.
*/
CoinView.prototype.fillCoins = function fillCoins(tx) {
let i, input, prevout;
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
prevout = input.prevout;
input.coin = this.spend(prevout.hash, prevout.index);
if (!input.coin)
return false;
}
return true;
};
/**
* Convert collection to an array.
* @returns {Coins[]}
*/
CoinView.prototype.toArray = function toArray() {
const keys = Object.keys(this.coins);
const out = [];
let i, hash;
for (i = 0; i < keys.length; i++) {
hash = keys[i];
out.push(this.coins[hash]);
}
return out;
};
/*
* Expose
*/
module.exports = CoinView;

View File

@ -1,247 +0,0 @@
/*!
* compress.js - coin compressor for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
const assert = require('assert');
const secp256k1 = require('bcrypto/lib/secp256k1');
/*
* Compression
*/
/**
* Compress a script, write directly to the buffer.
* @param {Script} script
* @param {BufferWriter} bw
*/
function compressScript(script, bw) {
// Attempt to compress the output scripts.
// We can _only_ ever compress them if
// they are serialized as minimaldata, as
// we need to recreate them when we read
// them.
// P2PKH -> 1 | key-hash
// Saves 5 bytes.
if (script.isPubkeyhash(true)) {
const data = script.code[2].data;
bw.writeU8(1);
bw.writeBytes(data);
return bw;
}
// P2SH -> 2 | script-hash
// Saves 3 bytes.
if (script.isScripthash()) {
const data = script.code[1].data;
bw.writeU8(2);
bw.writeBytes(data);
return bw;
}
// P2PK -> 3 | compressed-key
// Only works if the key is valid.
// Saves up to 34 bytes.
if (script.isPubkey(true)) {
let data = script.code[0].data;
if (secp256k1.publicKeyVerify(data)) {
data = compressKey(data);
bw.writeU8(3);
bw.writeBytes(data);
return bw;
}
}
// Raw -> 0 | varlen | script
bw.writeU8(0);
bw.writeVarBytes(script.toRaw());
return bw;
}
/**
* Decompress a script from buffer reader.
* @param {Script} script
* @param {BufferReader} br
*/
function decompressScript(script, br) {
let data;
// Decompress the script.
switch (br.readU8()) {
case 0:
data = br.readVarBytes();
script.fromRaw(data);
break;
case 1:
data = br.readBytes(20, true);
script.fromPubkeyhash(data);
break;
case 2:
data = br.readBytes(20, true);
script.fromScripthash(data);
break;
case 3:
data = br.readBytes(33, true);
// Decompress the key. If this fails,
// we have database corruption!
data = decompressKey(data);
script.fromPubkey(data);
break;
default:
throw new Error('Bad prefix.');
}
return script;
}
/**
* Compress value using an exponent. Takes advantage of
* the fact that many bitcoin values are divisible by 10.
* @see https://github.com/btcsuite/btcd/blob/master/blockchain/compress.go
* @param {Amount} value
* @returns {Number}
*/
function compressValue(value) {
if (value === 0)
return 0;
let exp = 0;
while (value % 10 === 0 && exp < 9) {
value /= 10;
exp++;
}
if (exp < 9) {
const last = value % 10;
value = (value - last) / 10;
return 1 + 10 * (9 * value + last - 1) + exp;
}
return 10 + 10 * (value - 1);
}
/**
* Decompress value.
* @param {Number} value - Compressed value.
* @returns {Amount} value
*/
function decompressValue(value) {
if (value === 0)
return 0;
value--;
let exp = value % 10;
value = (value - exp) / 10;
let n;
if (exp < 9) {
const last = value % 9;
value = (value - last) / 9;
n = value * 10 + last + 1;
} else {
n = value + 1;
}
while (exp > 0) {
n *= 10;
exp--;
}
return n;
}
/**
* Compress a public key to coins compression format.
* @param {Buffer} key
* @returns {Buffer}
*/
function compressKey(key) {
let out;
switch (key[0]) {
case 0x02:
case 0x03:
// Key is already compressed.
out = key;
break;
case 0x04:
case 0x06:
case 0x07:
// Compress the key normally.
out = secp256k1.publicKeyConvert(key, true);
// Store the original format (which
// may be a hybrid byte) in the hi
// 3 bits so we can restore it later.
// The hi bits being set also lets us
// know that this key was originally
// decompressed.
out[0] |= key[0] << 2;
break;
default:
throw new Error('Bad point format.');
}
assert(out.length === 33);
return out;
}
/**
* Decompress a public key from the coins compression format.
* @param {Buffer} key
* @returns {Buffer}
*/
function decompressKey(key) {
const format = key[0] >>> 2;
assert(key.length === 33);
// Hi bits are not set. This key
// is not meant to be decompressed.
if (format === 0)
return key;
// Decompress the key, and off the
// low bits so publicKeyConvert
// actually understands it.
key[0] &= 0x03;
const out = secp256k1.publicKeyConvert(key, false);
// Reset the hi bits so as not to
// mutate the original buffer.
key[0] |= format << 2;
// Set the original format, which
// may have been a hybrid prefix byte.
out[0] = format;
return out;
}
/*
* Expose
*/
exports.compress = {
script: compressScript,
value: compressValue,
key: compressKey
};
exports.decompress = {
script: decompressScript,
value: decompressValue,
key: decompressKey
};

View File

@ -1,148 +0,0 @@
'use strict';
const assert = require('assert');
const BDB = require('bdb');
const bio = require('bufio');
const hash256 = require('bcrypto/lib/hash256');
const BN = require('bn.js');
const util = require('../lib/utils/util');
const {encoding} = bio;
const DUMMY = Buffer.from([0]);
let file = process.argv[2];
let batch;
assert(typeof file === 'string', 'Please pass in a database path.');
file = file.replace(/\.ldb\/?$/, '');
const db = new BDB({
location: file,
db: 'leveldb',
compression: true,
cacheSize: 32 << 20,
createIfMissing: false,
bufferKeys: true
});
async function checkVersion() {
console.log('Checking version.');
const data = await db.get('V');
if (!data)
return;
const ver = data.readUInt32LE(0, true);
if (ver !== 1)
throw Error(`DB is version ${ver}.`);
}
function entryFromRaw(data) {
const p = bio.read(data, true);
const hash = hash256.digest(p.readBytes(80));
const entry = {};
p.seek(-80);
entry.hash = hash.toString('hex');
entry.version = p.readU32(); // Technically signed
entry.prevBlock = p.readHash('hex');
entry.merkleRoot = p.readHash('hex');
entry.time = p.readU32();
entry.bits = p.readU32();
entry.nonce = p.readU32();
entry.height = p.readU32();
entry.chainwork = new BN(p.readBytes(32), 'le');
return entry;
}
function getEntries() {
return db.values({
gte: pair('e', encoding.ZERO_HASH),
lte: pair('e', encoding.MAX_HASH),
parse: entryFromRaw
});
}
async function getTip(entry) {
const state = await db.get('R');
assert(state);
const tip = state.toString('hex', 0, 32);
const data = await db.get(pair('e', tip));
assert(data);
return entryFromRaw(data);
}
async function isMainChain(entry, tip) {
if (entry.hash === tip)
return true;
if (await db.get(pair('n', entry.hash)))
return true;
return false;
}
// And this insane function is why we should
// be indexing tips in the first place!
async function indexTips() {
const entries = await getEntries();
const tip = await getTip();
const tips = [];
const orphans = [];
const prevs = {};
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
const main = await isMainChain(entry, tip.hash);
if (!main) {
orphans.push(entry);
prevs[entry.prevBlock] = true;
}
}
for (let i = 0; i < orphans.length; i++) {
const orphan = orphans[i];
if (!prevs[orphan.hash])
tips.push(orphan.hash);
}
tips.push(tip.hash);
for (let i = 0; i < tips.length; i++) {
const tip = tips[i];
console.log('Indexing chain tip: %s.', util.revHex(tip));
batch.put(pair('p', tip), DUMMY);
}
}
function write(data, str, off) {
if (Buffer.isBuffer(str))
return str.copy(data, off);
return data.write(str, off, 'hex');
}
function pair(prefix, hash) {
const key = Buffer.allocUnsafe(33);
if (typeof prefix === 'string')
prefix = prefix.charCodeAt(0);
key[0] = prefix;
write(key, hash, 1);
return key;
}
(async () => {
await db.open();
console.log('Opened %s.', file);
batch = db.batch();
await checkVersion();
await indexTips();
await batch.write();
})().then(() => {
console.log('Migration complete.');
process.exit(0);
});

View File

@ -1,364 +0,0 @@
'use strict';
const assert = require('assert');
const bcoin = require('../');
const bio = require('bufio');
const walletdb = require('../lib/wallet/walletdb');
const Path = require('../lib/wallet/path');
const MasterKey = require('../lib/wallet/masterkey');
const Account = require('../lib/wallet/account');
const Wallet = require('../lib/wallet/wallet');
const KeyRing = require('../lib/primitives/keyring');
const layout = walletdb.layout;
const {encoding} = bio;
let file = process.argv[2];
let batch;
assert(typeof file === 'string', 'Please pass in a database path.');
file = file.replace(/\.ldb\/?$/, '');
const db = bcoin.ldb({
location: file,
db: 'leveldb',
compression: true,
cacheSize: 32 << 20,
createIfMissing: false,
bufferKeys: true
});
async function updateVersion() {
const bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`;
console.log('Checking version.');
const data = await db.get('V');
assert(data, 'No version.');
let ver = data.readUInt32LE(0, true);
if (ver !== 2)
throw Error(`DB is version ${ver}.`);
console.log('Backing up DB to: %s.', bak);
await db.backup(bak);
ver = Buffer.allocUnsafe(4);
ver.writeUInt32LE(3, 0, true);
batch.put('V', ver);
}
async function updatePathMap() {
let total = 0;
const iter = db.iterator({
gte: layout.p(encoding.NULL_HASH),
lte: layout.p(encoding.HIGH_HASH),
values: true
});
console.log('Migrating path map.');
while (await iter.next()) {
const {key, value} = iter;
total++;
const hash = layout.pp(key);
const oldPaths = parsePaths(value, hash);
const keys = Object.keys(oldPaths);
for (let i = 0; i < keys.length; i++) {
keys[i] = Number(keys[i]);
const key = keys[i];
const oldPath = oldPaths[key];
const path = new Path(oldPath);
if (path.data) {
if (path.encrypted) {
console.log(
'Cannot migrate encrypted import: %s (%s)',
path.data.toString('hex'),
path.toAddress().toBase58());
continue;
}
const ring = keyFromRaw(path.data);
path.data = new KeyRing(ring).toRaw();
}
batch.put(layout.P(key, hash), path.toRaw());
}
batch.put(key, serializeWallets(keys.sort()));
}
console.log('Migrated %d paths.', total);
}
async function updateAccounts() {
let total = 0;
const iter = db.iterator({
gte: layout.a(0, 0),
lte: layout.a(0xffffffff, 0xffffffff),
values: true
});
console.log('Migrating accounts.');
for (;;) {
const item = await iter.next();
if (!item)
break;
total++;
let account = accountFromRaw(item.value, item.key);
account = new Account({ network: account.network, options: {} }, account);
batch.put(item.key, account.toRaw());
if (account._old) {
batch.del(layout.i(account.wid, account._old));
const buf = Buffer.allocUnsafe(4);
buf.writeUInt32LE(account.accountIndex, 0, true);
batch.put(layout.i(account.wid, account.name), buf);
}
}
console.log('Migrated %d accounts.', total);
}
async function updateWallets() {
let total = 0;
const iter = db.iterator({
gte: layout.w(0),
lte: layout.w(0xffffffff),
values: true
});
console.log('Migrating wallets.');
for (;;) {
const item = await iter.next();
if (!item)
break;
total++;
let wallet = walletFromRaw(item.value);
wallet = new Wallet({ network: wallet.network }, wallet);
batch.put(item.key, wallet.toRaw());
if (wallet._old) {
batch.del(layout.l(wallet._old));
const buf = Buffer.allocUnsafe(4);
buf.writeUInt32LE(wallet.wid, 0, true);
batch.put(layout.l(wallet.id), buf);
}
}
console.log('Migrated %d wallets.', total);
}
async function updateTXMap() {
let total = 0;
const iter = db.iterator({
gte: layout.e(encoding.NULL_HASH),
lte: layout.e(encoding.HIGH_HASH),
values: true
});
console.log('Migrating tx map.');
for (;;) {
const item = await iter.next();
if (!item)
break;
total++;
const wallets = parseWallets(item.value);
batch.put(item.key, serializeWallets(wallets.sort()));
}
console.log('Migrated %d tx maps.', total);
}
function pathFromRaw(data) {
const path = {};
const p = bio.read(data);
path.wid = p.readU32();
path.name = p.readVarString('utf8');
path.account = p.readU32();
switch (p.readU8()) {
case 0:
path.keyType = 0;
path.branch = p.readU32();
path.index = p.readU32();
if (p.readU8() === 1)
assert(false, 'Cannot migrate custom redeem script.');
break;
case 1:
path.keyType = 1;
path.encrypted = p.readU8() === 1;
path.data = p.readVarBytes();
path.branch = -1;
path.index = -1;
break;
default:
assert(false);
break;
}
path.version = p.readI8();
path.type = p.readU8();
return path;
}
function parsePaths(data, hash) {
const p = bio.read(data);
const out = {};
while (p.left()) {
const path = pathFromRaw(p);
out[path.wid] = path;
if (hash)
path.hash = hash;
}
return out;
}
function parseWallets(data) {
const p = bio.read(data);
const wallets = [];
while (p.left())
wallets.push(p.readU32());
return wallets;
}
function serializeWallets(wallets) {
const p = bio.write();
for (let i = 0; i < wallets.length; i++) {
const wid = wallets[i];
p.writeU32(wid);
}
return p.render();
}
function readAccountKey(key) {
return {
wid: key.readUInt32BE(1, true),
index: key.readUInt32BE(5, true)
};
}
function accountFromRaw(data, dbkey) {
const account = {};
const p = bio.read(data);
dbkey = readAccountKey(dbkey);
account.wid = dbkey.wid;
account.id = 'doesntmatter';
account.network = bcoin.network.fromMagic(p.readU32());
account.name = p.readVarString('utf8');
account.initialized = p.readU8() === 1;
account.type = p.readU8();
account.m = p.readU8();
account.n = p.readU8();
account.witness = p.readU8() === 1;
account.accountIndex = p.readU32();
account.receiveDepth = p.readU32();
account.changeDepth = p.readU32();
account.accountKey = bcoin.hd.fromRaw(p.readBytes(82));
account.keys = [];
account.watchOnly = false;
account.nestedDepth = 0;
const name = account.name.replace(/[^\-\._0-9A-Za-z]+/g, '');
if (name !== account.name) {
console.log('Account name changed: %s -> %s.', account.name, name);
account._old = account.name;
account.name = name;
}
const count = p.readU8();
for (let i = 0; i < count; i++) {
const key = bcoin.hd.fromRaw(p.readBytes(82));
account.keys.push(key);
}
return account;
}
function walletFromRaw(data) {
const wallet = {};
const p = bio.read(data);
wallet.network = bcoin.network.fromMagic(p.readU32());
wallet.wid = p.readU32();
wallet.id = p.readVarString('utf8');
wallet.initialized = p.readU8() === 1;
wallet.accountDepth = p.readU32();
wallet.token = p.readBytes(32);
wallet.tokenDepth = p.readU32();
wallet.master = MasterKey.fromRaw(p.readVarBytes());
wallet.watchOnly = false;
const id = wallet.id.replace(/[^\-\._0-9A-Za-z]+/g, '');
if (id !== wallet.id) {
console.log('Wallet ID changed: %s -> %s.', wallet.id, id);
wallet._old = wallet.id;
wallet.id = id;
}
return wallet;
}
function keyFromRaw(data, network) {
const ring = {};
const p = bio.read(data);
ring.witness = p.readU8() === 1;
const key = p.readVarBytes();
if (key.length === 32) {
ring.privateKey = key;
ring.publicKey = bcoin.secp256k1.publicKeyCreate(key, true);
} else {
ring.publicKey = key;
}
const script = p.readVarBytes();
if (script.length > 0)
ring.script = bcoin.script.fromRaw(script);
return ring;
}
(async () => {
await db.open();
batch = db.batch();
console.log('Opened %s.', file);
await updateVersion();
await updatePathMap();
await updateAccounts();
await updateWallets();
await updateTXMap();
await batch.write();
})().then(() => {
console.log('Migration complete.');
process.exit(0);
});

View File

@ -1,147 +0,0 @@
'use strict';
const assert = require('assert');
const bcoin = require('../');
const bio = require('bufio');
const WalletDB = require('../lib/wallet/walletdb');
const TX = require('../lib/primitives/tx');
const Coin = require('../lib/primitives/coin');
const {encoding} = bio;
let file = process.argv[2];
let batch;
assert(typeof file === 'string', 'Please pass in a database path.');
file = file.replace(/\.ldb\/?$/, '');
const db = bcoin.ldb({
location: file,
db: 'leveldb',
compression: true,
cacheSize: 32 << 20,
createIfMissing: false,
bufferKeys: true
});
async function updateVersion() {
const bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`;
console.log('Checking version.');
const data = await db.get('V');
assert(data, 'No version.');
let ver = data.readUInt32LE(0, true);
if (ver !== 3)
throw Error(`DB is version ${ver}.`);
console.log('Backing up DB to: %s.', bak);
await db.backup(bak);
ver = Buffer.allocUnsafe(4);
ver.writeUInt32LE(4, 0, true);
batch.put('V', ver);
}
async function updateTXDB() {
let txs = {};
const keys = await db.keys({
gte: Buffer.from([0x00]),
lte: Buffer.from([0xff])
});
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (key[0] === 0x74 && key[5] === 0x74) {
let tx = await db.get(key);
tx = fromExtended(tx);
const hash = tx.hash('hex');
txs[hash] = tx;
}
if (key[0] === 0x74)
batch.del(key);
}
txs = getValues(txs);
await batch.write();
await db.close();
const walletdb = new WalletDB({
location: file,
db: 'leveldb',
resolution: true,
verify: false,
network: process.argv[3]
});
await walletdb.open();
for (let i = 0; i < txs.length; i++) {
const tx = txs[i];
await walletdb.addTX(tx);
}
await walletdb.close();
}
function fromExtended(data, saveCoins) {
const tx = new TX();
const p = bio.read(data);
tx.fromRaw(p);
tx.height = p.readU32();
tx.block = p.readHash('hex');
tx.index = p.readU32();
tx.time = p.readU32();
tx.mtime = p.readU32();
if (tx.block === encoding.NULL_HASH)
tx.block = null;
if (tx.height === 0x7fffffff)
tx.height = -1;
if (tx.index === 0x7fffffff)
tx.index = -1;
if (saveCoins) {
const coinCount = p.readVarint();
for (let i = 0; i < coinCount; i++) {
let coin = p.readVarBytes();
if (coin.length === 0)
continue;
coin = Coin.fromRaw(coin);
coin.hash = tx.inputs[i].prevout.hash;
coin.index = tx.inputs[i].prevout.index;
tx.inputs[i].coin = coin;
}
}
return tx;
}
function getValues(map) {
const items = [];
for (const key of Object.keys(map))
items.push(map[key]);
return items;
}
(async () => {
await db.open();
batch = db.batch();
console.log('Opened %s.', file);
await updateVersion();
await updateTXDB();
})().then(() => {
console.log('Migration complete.');
process.exit(0);
});

View File

@ -1,74 +0,0 @@
'use strict';
const assert = require('assert');
const bcoin = require('../');
let file = process.argv[2];
let batch;
assert(typeof file === 'string', 'Please pass in a database path.');
file = file.replace(/\.ldb\/?$/, '');
const db = bcoin.ldb({
location: file,
db: 'leveldb',
compression: true,
cacheSize: 32 << 20,
createIfMissing: false,
bufferKeys: true
});
async function updateVersion() {
const bak = `${process.env.HOME}/walletdb-bak-${Date.now()}.ldb`;
console.log('Checking version.');
const data = await db.get('V');
assert(data, 'No version.');
let ver = data.readUInt32LE(0, true);
if (ver !== 4)
throw Error(`DB is version ${ver}.`);
console.log('Backing up DB to: %s.', bak);
await db.backup(bak);
ver = Buffer.allocUnsafe(4);
ver.writeUInt32LE(5, 0, true);
batch.put('V', ver);
}
async function updateTXDB() {
const keys = await db.keys({
gte: Buffer.from([0x00]),
lte: Buffer.from([0xff])
});
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
switch (key[0]) {
case 0x62: // b
case 0x63: // c
case 0x65: // e
case 0x74: // t
batch.del(key);
break;
}
}
await batch.write();
}
(async () => {
await db.open();
batch = db.batch();
console.log('Opened %s.', file);
await updateVersion();
await updateTXDB();
await db.close();
})().then(() => {
console.log('Migration complete.');
process.exit(0);
});

View File

@ -1,9 +1,8 @@
'use strict';
const assert = require('assert');
const bcoin = require('../');
const bdb = require('bdb');
const bio = require('bufio');
const {encoding} = bio;
let file = process.argv[2];
let batch;
@ -12,13 +11,12 @@ assert(typeof file === 'string', 'Please pass in a database path.');
file = file.replace(/\.ldb\/?$/, '');
const db = bcoin.ldb({
const db = bdb.create({
location: file,
db: 'leveldb',
compression: true,
cacheSize: 32 << 20,
createIfMissing: false,
bufferKeys: true
createIfMissing: false
});
async function updateVersion() {
@ -26,30 +24,27 @@ async function updateVersion() {
console.log('Checking version.');
const data = await db.get('V');
assert(data, 'No version.');
const raw = await db.get('V');
assert(raw, 'No version.');
let ver = data.readUInt32LE(0, true);
const version = raw.readUInt32LE(0, true);
if (ver !== 5)
throw Error(`DB is version ${ver}.`);
if (version !== 5)
throw Error(`DB is version ${version}.`);
console.log('Backing up DB to: %s.', bak);
await db.backup(bak);
ver = Buffer.allocUnsafe(4);
ver.writeUInt32LE(6, 0, true);
batch.put('V', ver);
const data = Buffer.allocUnsafe(4);
data.writeUInt32LE(6, 0, true);
batch.put('V', data);
}
async function wipeTXDB() {
let total = 0;
const keys = await db.keys({
gte: Buffer.from([0x00]),
lte: Buffer.from([0xff])
});
const keys = await db.keys();
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
@ -61,7 +56,7 @@ async function wipeTXDB() {
case 0x6f: // o
case 0x68: // h
batch.del(key);
total++;
total += 1;
break;
}
}
@ -73,8 +68,8 @@ async function wipeTXDB() {
async function patchAccounts() {
const items = await db.range({
gte: Buffer.from('610000000000000000', 'hex'), // a
lte: Buffer.from('61ffffffffffffffff', 'hex') // a
gt: Buffer.from([0x61]), // a
lt: Buffer.from([0x62])
});
for (let i = 0; i < items.length; i++) {
@ -91,8 +86,8 @@ async function patchAccounts() {
async function indexPaths() {
const items = await db.range({
gte: Buffer.from('5000000000' + encoding.NULL_HASH, 'hex'), // P
lte: Buffer.from('50ffffffff' + encoding.HIGH_HASH, 'hex') // P
gt: Buffer.from([0x50]), // P
lt: Buffer.from([0x51])
});
for (let i = 0; i < items.length; i++) {
@ -107,8 +102,8 @@ async function indexPaths() {
async function patchPathMaps() {
const items = await db.range({
gte: Buffer.from('70' + encoding.NULL_HASH, 'hex'), // p
lte: Buffer.from('70' + encoding.HIGH_HASH, 'hex') // p
gt: Buffer.from([0x70]), // p
lt: Buffer.from([0x71])
});
for (let i = 0; i < items.length; i++) {
@ -261,7 +256,7 @@ async function unstate() {
await db.close();
// Do not use:
await updateLookahead();
// await updateLookahead();
await unstate();
})().then(() => {
console.log('Migration complete.');

View File

@ -1,7 +1,6 @@
'use strict';
const consensus = require('../lib/protocol/consensus');
const {encoding} = require('bufio');
const TX = require('../lib/primitives/tx');
const Block = require('../lib/primitives/block');
const Script = require('../lib/script/script');
@ -31,7 +30,7 @@ function createGenesisBlock(options) {
version: 1,
inputs: [{
prevout: {
hash: encoding.NULL_HASH,
hash: consensus.NULL_HASH,
index: 0xffffffff
},
script: Script()
@ -50,7 +49,7 @@ function createGenesisBlock(options) {
const block = new Block({
version: options.version,
prevBlock: encoding.NULL_HASH,
prevBlock: consensus.NULL_HASH,
merkleRoot: tx.hash('hex'),
time: options.time,
bits: options.bits,

View File

@ -10,7 +10,6 @@ const Block = require('../lib/primitives/block');
const MerkleBlock = require('../lib/primitives/merkleblock');
const consensus = require('../lib/protocol/consensus');
const Script = require('../lib/script/script');
const {encoding} = require('bufio');
const bip152 = require('../lib/net/bip152');
const CompactBlock = bip152.CompactBlock;
const TXRequest = bip152.TXRequest;
@ -158,7 +157,7 @@ describe('Block', function() {
it('should fail with a bad merkle root', () => {
const [block] = block300025.getBlock();
const merkleRoot = block.merkleRoot;
block.merkleRoot = encoding.NULL_HASH;
block.merkleRoot = consensus.NULL_HASH;
block.refresh();
assert(!block.verifyPOW());
const [, reason] = block.checkBody();
@ -172,7 +171,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 = encoding.NULL_HASH;
block.merkleRoot = consensus.NULL_HASH;
block.refresh();
assert(!block.verifyPOW());
const [, reason] = block.checkBody();

View File

@ -3,7 +3,6 @@
'use strict';
const {encoding} = require('bufio');
const assert = require('./util/assert');
const consensus = require('../lib/protocol/consensus');
const Address = require('../lib/primitives/address');
@ -76,7 +75,7 @@ describe('HTTP', function() {
it('should fill with funds', async () => {
const mtx = new MTX();
mtx.addOutpoint(new Outpoint(encoding.NULL_HASH, 0));
mtx.addOutpoint(new Outpoint(consensus.NULL_HASH, 0));
mtx.addOutput(addr, 50460);
mtx.addOutput(addr, 50460);
mtx.addOutput(addr, 50460);

View File

@ -9,7 +9,7 @@ const Witness = require('../lib/script/witness');
const Stack = require('../lib/script/stack');
const Opcode = require('../lib/script/opcode');
const TX = require('../lib/primitives/tx');
const {encoding} = require('bufio');
const consensus = require('../lib/protocol/consensus');
const {fromFloat} = require('../lib/utils/fixed');
const scripts = require('./data/script-tests.json');
@ -286,7 +286,7 @@ describe('Script', function() {
version: 1,
inputs: [{
prevout: {
hash: encoding.NULL_HASH,
hash: consensus.NULL_HASH,
index: 0xffffffff
},
script: [

View File

@ -692,7 +692,7 @@ describe('TX', function() {
const output = Script.fromProgram(0, key.getKeyHash());
const ctx = sigopContext(input, witness, output);
ctx.spend.inputs[0].prevout.hash = encoding.NULL_HASH;
ctx.spend.inputs[0].prevout.hash = consensus.NULL_HASH;
ctx.spend.inputs[0].prevout.index = 0xffffffff;
ctx.spend.refresh();

View File

@ -3,7 +3,6 @@
'use strict';
const {encoding} = require('bufio');
const assert = require('./util/assert');
const consensus = require('../lib/protocol/consensus');
const util = require('../lib/utils/util');
@ -679,7 +678,7 @@ describe('Wallet', function() {
// Coinbase
const t1 = new MTX();
t1.addOutpoint(new Outpoint(encoding.NULL_HASH, 0));
t1.addOutpoint(new Outpoint(consensus.NULL_HASH, 0));
t1.addOutput(await alice.receiveAddress(), 5460);
t1.addOutput(await alice.receiveAddress(), 5460);
t1.addOutput(await alice.receiveAddress(), 5460);