walletdb: use layout for walletdb and txdb.
This commit is contained in:
parent
989aa15a4c
commit
16204a4794
@ -7,6 +7,15 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var bcoin = require('./env');
|
||||||
|
var utils = require('./utils');
|
||||||
|
var assert = bcoin.utils.assert;
|
||||||
|
var constants = bcoin.protocol.constants;
|
||||||
|
var DUMMY = new Buffer([0]);
|
||||||
|
var pad32 = utils.pad32;
|
||||||
|
var BufferReader = require('./reader');
|
||||||
|
var BufferWriter = require('./writer');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Database Layout:
|
* Database Layout:
|
||||||
* t/[hash] -> extended tx
|
* t/[hash] -> extended tx
|
||||||
@ -24,14 +33,163 @@
|
|||||||
* C/[account]/[hash]/[index] -> dummy (coin by account)
|
* C/[account]/[hash]/[index] -> dummy (coin by account)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var bcoin = require('./env');
|
function Layout(wallet) {
|
||||||
var utils = require('./utils');
|
this.wallet = wallet;
|
||||||
var assert = bcoin.utils.assert;
|
}
|
||||||
var constants = bcoin.protocol.constants;
|
|
||||||
var DUMMY = new Buffer([0]);
|
Layout.prototype.prefix = function prefix(key) {
|
||||||
var pad32 = utils.pad32;
|
assert(this.wallet.wid);
|
||||||
var BufferReader = require('./reader');
|
return 't' + pad32(this.wallet.wid) + key;
|
||||||
var BufferWriter = require('./writer');
|
};
|
||||||
|
|
||||||
|
Layout.prototype.hi = function hi(ch, hash, index) {
|
||||||
|
return this.prefix(ch + hash + pad32(index));
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.hii = function hii(key) {
|
||||||
|
key = key.slice(12);
|
||||||
|
return [key.slice(0, 64), +key.slice(64)];
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.ih = function ih(ch, index, hash) {
|
||||||
|
return this.prefix(ch + pad32(index) + hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.ihh = function ihh(key) {
|
||||||
|
key = key.slice(12);
|
||||||
|
return [+key.slice(0, 10), key.slice(10)];
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.iih = function iih(ch, index, num, hash) {
|
||||||
|
return this.prefix(ch + pad32(index) + pad32(num) + hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.iihh = function iihh(key) {
|
||||||
|
key = key.slice(12);
|
||||||
|
return [+key.slice(0, 10), +key.slice(10, 20), key.slice(20)];
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.ihi = function ihi(ch, index, hash, num) {
|
||||||
|
return this.prefix(ch + pad32(index) + hash + pad32(num));
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.ihii = function ihii(key) {
|
||||||
|
key = key.slice(12);
|
||||||
|
return [+key.slice(0, 10), key.slice(10, 74), +key.slice(74)];
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.ha = function ha(ch, hash) {
|
||||||
|
return this.prefix(ch + hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.haa = function haa(key) {
|
||||||
|
key = key.slice(12);
|
||||||
|
return key;
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.t = function t(hash) {
|
||||||
|
return this.ha('t', hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.tt = function tt(key) {
|
||||||
|
return this.haa(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.c = function c(hash, index) {
|
||||||
|
return this.hi('c', hash, index);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.cc = function cc(key) {
|
||||||
|
return this.hii(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.d = function d(hash, index) {
|
||||||
|
return this.hi('d', hash, index);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.dd = function dd(key) {
|
||||||
|
return this.hii(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.s = function s(hash, index) {
|
||||||
|
return this.hi('s', hash, index);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.ss = function ss(key) {
|
||||||
|
return this.hii(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.o = function o(hash, index) {
|
||||||
|
return this.hi('o', hash, index);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.oo = function oo(key) {
|
||||||
|
return this.hii(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.p = function p(hash) {
|
||||||
|
return this.ha('p', hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.pp = function pp(key) {
|
||||||
|
return this.haa(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.m = function m(time, hash) {
|
||||||
|
return this.ih('m', time, hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.mm = function mm(key) {
|
||||||
|
return this.ihh(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.h = function h(height, hash) {
|
||||||
|
return this.ih('h', height, hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.hh = function hh(key) {
|
||||||
|
return this.ihh(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.T = function T(account, hash) {
|
||||||
|
return this.ih('T', account, hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.Tt = function Tt(key) {
|
||||||
|
return this.ihh(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.P = function P(account, hash) {
|
||||||
|
return this.ih('P', account, hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.Pp = function Pp(key) {
|
||||||
|
return this.ihh(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.M = function M(account, time, hash) {
|
||||||
|
return this.iih('M', account, time, hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.Mm = function Mm(key) {
|
||||||
|
return this.iihh(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.H = function H(account, height, hash) {
|
||||||
|
return this.iih('H', account, height, hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.Hh = function Hh(key) {
|
||||||
|
return this.iihh(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.C = function C(account, hash, index) {
|
||||||
|
return this.ihi('C', account, hash, index);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.prototype.Cc = function Cc(key) {
|
||||||
|
return this.ihii(key);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TXDB
|
* TXDB
|
||||||
@ -50,6 +208,7 @@ function TXDB(wallet) {
|
|||||||
this.logger = wallet.db.logger;
|
this.logger = wallet.db.logger;
|
||||||
this.network = wallet.db.network;
|
this.network = wallet.db.network;
|
||||||
this.options = wallet.db.options;
|
this.options = wallet.db.options;
|
||||||
|
this.key = new Layout(wallet);
|
||||||
|
|
||||||
this.locker = new bcoin.locker(this);
|
this.locker = new bcoin.locker(this);
|
||||||
this.coinCache = new bcoin.lru(10000, 1);
|
this.coinCache = new bcoin.lru(10000, 1);
|
||||||
@ -83,16 +242,6 @@ TXDB.prototype.open = function open(callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Compile wallet prefix.
|
|
||||||
* @param {String} key
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXDB.prototype.prefix = function prefix(key) {
|
|
||||||
assert(this.wallet.wid);
|
|
||||||
return 't/' + pad32(this.wallet.wid) + '/' + key;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit transaction event.
|
* Emit transaction event.
|
||||||
* @private
|
* @private
|
||||||
@ -135,7 +284,7 @@ TXDB.prototype.start = function start() {
|
|||||||
|
|
||||||
TXDB.prototype.put = function put(key, value) {
|
TXDB.prototype.put = function put(key, value) {
|
||||||
assert(this.current);
|
assert(this.current);
|
||||||
this.current.put(this.prefix(key), value);
|
this.current.put(key, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,7 +294,7 @@ TXDB.prototype.put = function put(key, value) {
|
|||||||
|
|
||||||
TXDB.prototype.del = function del(key) {
|
TXDB.prototype.del = function del(key) {
|
||||||
assert(this.current);
|
assert(this.current);
|
||||||
this.current.del(this.prefix(key));
|
this.current.del(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,7 +324,7 @@ TXDB.prototype.drop = function drop() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.fetch = function fetch(key, parse, callback) {
|
TXDB.prototype.fetch = function fetch(key, parse, callback) {
|
||||||
this.db.fetch(this.prefix(key), parse, callback);
|
this.db.fetch(key, parse, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -184,7 +333,7 @@ TXDB.prototype.fetch = function fetch(key, parse, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.get = function get(key, callback) {
|
TXDB.prototype.get = function get(key, callback) {
|
||||||
this.db.get(this.prefix(key), callback);
|
this.db.get(key, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -193,7 +342,7 @@ TXDB.prototype.get = function get(key, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.has = function has(key, callback) {
|
TXDB.prototype.has = function has(key, callback) {
|
||||||
this.db.has(this.prefix(key), callback);
|
this.db.has(key, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,10 +352,6 @@ TXDB.prototype.has = function has(key, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.iterate = function iterate(options, callback) {
|
TXDB.prototype.iterate = function iterate(options, callback) {
|
||||||
if (options.gte)
|
|
||||||
options.gte = this.prefix(options.gte);
|
|
||||||
if (options.lte)
|
|
||||||
options.lte = this.prefix(options.lte);
|
|
||||||
this.db.iterate(options, callback);
|
this.db.iterate(options, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -248,12 +393,12 @@ TXDB.prototype.getInfo = function getInfo(tx, callback) {
|
|||||||
* @param {Function} callback - Returns [Error, Buffer].
|
* @param {Function} callback - Returns [Error, Buffer].
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype._addOrphan = function _addOrphan(key, outpoint, callback) {
|
TXDB.prototype._addOrphan = function _addOrphan(hash, index, outpoint, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var p = new BufferWriter();
|
var p = new BufferWriter();
|
||||||
var k = 'o/' + key;
|
var key = this.key.o(hash, index);
|
||||||
|
|
||||||
this.get(k, function(err, data) {
|
this.get(key, function(err, data) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -262,7 +407,7 @@ TXDB.prototype._addOrphan = function _addOrphan(key, outpoint, callback) {
|
|||||||
|
|
||||||
p.writeBytes(outpoint);
|
p.writeBytes(outpoint);
|
||||||
|
|
||||||
self.put(k, p.render());
|
self.put(key, p.render());
|
||||||
|
|
||||||
return callback();
|
return callback();
|
||||||
});
|
});
|
||||||
@ -275,11 +420,11 @@ TXDB.prototype._addOrphan = function _addOrphan(key, outpoint, callback) {
|
|||||||
* @param {Function} callback - Returns [Error, {@link Orphan}].
|
* @param {Function} callback - Returns [Error, {@link Orphan}].
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype._getOrphans = function _getOrphans(key, callback) {
|
TXDB.prototype._getOrphans = function _getOrphans(hash, index, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var items = [];
|
var items = [];
|
||||||
|
|
||||||
this.fetch('o/' + key, function(data) {
|
this.fetch(this.key.o(hash, index), function(data) {
|
||||||
var p = new BufferReader(data);
|
var p = new BufferReader(data);
|
||||||
var orphans = [];
|
var orphans = [];
|
||||||
|
|
||||||
@ -416,17 +561,16 @@ TXDB.prototype._verify = function _verify(tx, info, callback) {
|
|||||||
TXDB.prototype._resolveOrphans = function _resolveOrphans(tx, index, callback) {
|
TXDB.prototype._resolveOrphans = function _resolveOrphans(tx, index, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var key = hash + '/' + pad32(index);
|
|
||||||
var coin;
|
var coin;
|
||||||
|
|
||||||
this._getOrphans(key, function(err, orphans) {
|
this._getOrphans(hash, index, function(err, orphans) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!orphans)
|
if (!orphans)
|
||||||
return callback(null, false);
|
return callback(null, false);
|
||||||
|
|
||||||
self.del('o/' + key);
|
self.del(self.key.o(hash, index));
|
||||||
|
|
||||||
coin = bcoin.coin.fromTX(tx, index);
|
coin = bcoin.coin.fromTX(tx, index);
|
||||||
|
|
||||||
@ -447,7 +591,7 @@ TXDB.prototype._resolveOrphans = function _resolveOrphans(tx, index, callback) {
|
|||||||
// Verify that input script is correct, if not - add
|
// Verify that input script is correct, if not - add
|
||||||
// output to unspent and remove orphan from storage
|
// output to unspent and remove orphan from storage
|
||||||
if (!self.options.verify || orphan.verifyInput(input.index)) {
|
if (!self.options.verify || orphan.verifyInput(input.index)) {
|
||||||
self.put('d/' + input.hash + '/' + pad32(input.index), coin.toRaw());
|
self.put(self.key.d(input.hash, input.index), coin.toRaw());
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,23 +649,23 @@ TXDB.prototype.add = function add(tx, info, callback) {
|
|||||||
hash = tx.hash('hex');
|
hash = tx.hash('hex');
|
||||||
|
|
||||||
self.start();
|
self.start();
|
||||||
self.put('t/' + hash, tx.toExtended());
|
self.put(self.key.t(hash), tx.toExtended());
|
||||||
|
|
||||||
if (tx.ts === 0)
|
if (tx.ts === 0)
|
||||||
self.put('p/' + hash, DUMMY);
|
self.put(self.key.p(hash), DUMMY);
|
||||||
else
|
else
|
||||||
self.put('h/' + pad32(tx.height) + '/' + hash, DUMMY);
|
self.put(self.key.h(tx.height, hash), DUMMY);
|
||||||
|
|
||||||
self.put('m/' + pad32(tx.ps) + '/' + hash, DUMMY);
|
self.put(self.key.m(tx.ps, hash), DUMMY);
|
||||||
|
|
||||||
for (i = 0; i < info.accounts.length; i++) {
|
for (i = 0; i < info.accounts.length; i++) {
|
||||||
account = pad32(info.accounts[i]);
|
account = info.accounts[i];
|
||||||
self.put('T/' + account + '/' + hash, DUMMY);
|
self.put(self.key.T(account, hash), DUMMY);
|
||||||
if (tx.ts === 0)
|
if (tx.ts === 0)
|
||||||
self.put('P/' + account + '/' + hash, DUMMY);
|
self.put(self.key.P(account, hash), DUMMY);
|
||||||
else
|
else
|
||||||
self.put('H/' + account + '/' + pad32(tx.height) + '/' + hash, DUMMY);
|
self.put(self.key.H(account, tx.height, hash), DUMMY);
|
||||||
self.put('M/' + account + '/' + pad32(tx.ps) + '/' + hash, DUMMY);
|
self.put(self.key.M(account, tx.ps, hash), DUMMY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume unspent money or add orphans
|
// Consume unspent money or add orphans
|
||||||
@ -539,19 +683,19 @@ TXDB.prototype.add = function add(tx, info, callback) {
|
|||||||
if (!path)
|
if (!path)
|
||||||
return next();
|
return next();
|
||||||
|
|
||||||
key = prevout.hash + '/' + pad32(prevout.index);
|
key = prevout.hash + '/' + prevout.index;
|
||||||
|
|
||||||
// s/[outpoint-key] -> [spender-hash]|[spender-input-index]
|
// s/[outpoint-key] -> [spender-hash]|[spender-input-index]
|
||||||
outpoint = bcoin.outpoint.fromTX(tx, i).toRaw();
|
outpoint = bcoin.outpoint.fromTX(tx, i).toRaw();
|
||||||
self.put('s/' + key, outpoint);
|
self.put(self.key.s(prevout.hash, prevout.index), outpoint);
|
||||||
|
|
||||||
// Add orphan, if no parent transaction is yet known
|
// Add orphan, if no parent transaction is yet known
|
||||||
if (!input.coin)
|
if (!input.coin)
|
||||||
return self._addOrphan(key, outpoint, next);
|
return self._addOrphan(prevout.hash, prevout.index, outpoint, next);
|
||||||
|
|
||||||
self.del('c/' + key);
|
self.del(self.key.c(prevout.hash, prevout.index));
|
||||||
self.del('C/' + pad32(path.account) + '/' + key);
|
self.del(self.key.C(path.account, prevout.hash, prevout.index));
|
||||||
self.put('d/' + hash + '/' + pad32(i), input.coin.toRaw());
|
self.put(self.key.d(hash, i), input.coin.toRaw());
|
||||||
self.balance.sub(input.coin);
|
self.balance.sub(input.coin);
|
||||||
|
|
||||||
self.coinCache.remove(key);
|
self.coinCache.remove(key);
|
||||||
@ -566,7 +710,7 @@ TXDB.prototype.add = function add(tx, info, callback) {
|
|||||||
// Add unspent outputs or resolve orphans
|
// Add unspent outputs or resolve orphans
|
||||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||||
var address = output.getHash('hex');
|
var address = output.getHash('hex');
|
||||||
var key = hash + '/' + pad32(i);
|
var key = hash + '/' + i;
|
||||||
var coin;
|
var coin;
|
||||||
|
|
||||||
path = info.getPath(address);
|
path = info.getPath(address);
|
||||||
@ -586,8 +730,8 @@ TXDB.prototype.add = function add(tx, info, callback) {
|
|||||||
self.balance.add(coin);
|
self.balance.add(coin);
|
||||||
coin = coin.toRaw();
|
coin = coin.toRaw();
|
||||||
|
|
||||||
self.put('c/' + key, coin);
|
self.put(self.key.c(hash, i), coin);
|
||||||
self.put('C/' + pad32(path.account) + '/' + key, DUMMY);
|
self.put(self.key.C(path.account, hash, i), DUMMY);
|
||||||
|
|
||||||
self.coinCache.set(key, coin);
|
self.coinCache.set(key, coin);
|
||||||
|
|
||||||
@ -753,7 +897,7 @@ TXDB.prototype.isDoubleSpend = function isDoubleSpend(tx, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.isSpent = function isSpent(hash, index, callback) {
|
TXDB.prototype.isSpent = function isSpent(hash, index, callback) {
|
||||||
var key = 's/' + hash + '/' + pad32(index);
|
var key = this.key.s(hash, index);
|
||||||
this.fetch(key, function(data) {
|
this.fetch(key, function(data) {
|
||||||
return bcoin.outpoint.fromRaw(data);
|
return bcoin.outpoint.fromRaw(data);
|
||||||
}, callback);
|
}, callback);
|
||||||
@ -800,20 +944,20 @@ TXDB.prototype._confirm = function _confirm(tx, info, callback) {
|
|||||||
|
|
||||||
self.start();
|
self.start();
|
||||||
|
|
||||||
self.put('t/' + hash, tx.toExtended());
|
self.put(self.key.t(hash), tx.toExtended());
|
||||||
|
|
||||||
self.del('p/' + hash);
|
self.del(self.key.p(hash));
|
||||||
self.put('h/' + pad32(tx.height) + '/' + hash, DUMMY);
|
self.put(self.key.h(tx.height, hash), DUMMY);
|
||||||
|
|
||||||
for (i = 0; i < info.accounts.length; i++) {
|
for (i = 0; i < info.accounts.length; i++) {
|
||||||
account = pad32(info.accounts[i]);
|
account = info.accounts[i];
|
||||||
self.del('P/' + account + '/' + hash);
|
self.del(self.key.P(account, hash));
|
||||||
self.put('H/' + account + '/' + pad32(tx.height) + '/' + hash, DUMMY);
|
self.put(self.key.H(account, tx.height, hash), DUMMY);
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||||
var address = output.getHash('hex');
|
var address = output.getHash('hex');
|
||||||
var key = hash + '/' + pad32(i);
|
var key = hash + '/' + i;
|
||||||
|
|
||||||
// Only update coins if this output is ours.
|
// Only update coins if this output is ours.
|
||||||
if (!info.hasPath(address))
|
if (!info.hasPath(address))
|
||||||
@ -833,7 +977,7 @@ TXDB.prototype._confirm = function _confirm(tx, info, callback) {
|
|||||||
coin.height = tx.height;
|
coin.height = tx.height;
|
||||||
coin = coin.toRaw();
|
coin = coin.toRaw();
|
||||||
|
|
||||||
self.put('c/' + key, coin);
|
self.put(self.key.c(hash, i), coin);
|
||||||
|
|
||||||
self.coinCache.set(key, coin);
|
self.coinCache.set(key, coin);
|
||||||
|
|
||||||
@ -914,23 +1058,23 @@ TXDB.prototype._remove = function remove(tx, info, callback) {
|
|||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var i, path, account, key, address, input, output, coin;
|
var i, path, account, key, address, input, output, coin;
|
||||||
|
|
||||||
this.del('t/' + hash);
|
this.del(this.key.t(hash));
|
||||||
|
|
||||||
if (tx.ts === 0)
|
if (tx.ts === 0)
|
||||||
this.del('p/' + hash);
|
this.del(this.key.p(hash));
|
||||||
else
|
else
|
||||||
this.del('h/' + pad32(tx.height) + '/' + hash);
|
this.del(this.key.h(tx.height, hash));
|
||||||
|
|
||||||
this.del('m/' + pad32(tx.ps) + '/' + hash);
|
this.del(this.key.m(tx.ps, hash));
|
||||||
|
|
||||||
for (i = 0; i < info.accounts.length; i++) {
|
for (i = 0; i < info.accounts.length; i++) {
|
||||||
account = pad32(info.accounts[i]);
|
account = info.accounts[i];
|
||||||
this.del('T/' + account + '/' + hash);
|
this.del(this.key.T(account, hash));
|
||||||
if (tx.ts === 0)
|
if (tx.ts === 0)
|
||||||
this.del('P/' + account + '/' + hash);
|
this.del(this.key.P(account, hash));
|
||||||
else
|
else
|
||||||
this.del('H/' + account + '/' + pad32(tx.height) + '/' + hash);
|
this.del(this.key.H(account, tx.height, hash));
|
||||||
this.del('M/' + account + '/' + pad32(tx.ps) + '/' + hash);
|
this.del(this.key.M(account, tx.ps, hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fillHistory(tx, function(err) {
|
this.fillHistory(tx, function(err) {
|
||||||
@ -939,7 +1083,8 @@ TXDB.prototype._remove = function remove(tx, info, callback) {
|
|||||||
|
|
||||||
for (i = 0; i < tx.inputs.length; i++) {
|
for (i = 0; i < tx.inputs.length; i++) {
|
||||||
input = tx.inputs[i];
|
input = tx.inputs[i];
|
||||||
key = input.prevout.hash + '/' + pad32(input.prevout.index);
|
key = input.prevout.hash + '/' + input.prevout.index;
|
||||||
|
var prevout = input.prevout;
|
||||||
address = input.getHash('hex');
|
address = input.getHash('hex');
|
||||||
|
|
||||||
if (tx.isCoinbase())
|
if (tx.isCoinbase())
|
||||||
@ -957,18 +1102,18 @@ TXDB.prototype._remove = function remove(tx, info, callback) {
|
|||||||
|
|
||||||
coin = input.coin.toRaw();
|
coin = input.coin.toRaw();
|
||||||
|
|
||||||
self.put('c/' + key, coin);
|
self.put(self.key.c(prevout.hash, prevout.index), coin);
|
||||||
self.put('C/' + pad32(path.account) + '/' + key, DUMMY);
|
self.put(self.key.C(path.account, prevout.hash, prevout.index), DUMMY);
|
||||||
self.del('d/' + hash + '/' + pad32(i));
|
self.del(self.key.d(hash, i));
|
||||||
self.del('s/' + key);
|
self.del(self.key.s(prevout.hash, prevout.index));
|
||||||
self.del('o/' + key);
|
self.del(self.key.o(prevout.hash, prevout.index));
|
||||||
|
|
||||||
self.coinCache.set(key, coin);
|
self.coinCache.set(key, coin);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < tx.outputs.length; i++) {
|
for (i = 0; i < tx.outputs.length; i++) {
|
||||||
output = tx.outputs[i];
|
output = tx.outputs[i];
|
||||||
key = hash + '/' + pad32(i);
|
key = hash + '/' + i;
|
||||||
address = output.getHash('hex');
|
address = output.getHash('hex');
|
||||||
|
|
||||||
path = info.getPath(address);
|
path = info.getPath(address);
|
||||||
@ -980,8 +1125,8 @@ TXDB.prototype._remove = function remove(tx, info, callback) {
|
|||||||
|
|
||||||
self.balance.sub(coin);
|
self.balance.sub(coin);
|
||||||
|
|
||||||
self.del('c/' + key);
|
self.del(self.key.c(hash, i));
|
||||||
self.del('C/' + pad32(path.account) + '/' + key);
|
self.del(self.key.C(path.account, hash, i));
|
||||||
|
|
||||||
self.coinCache.remove(key);
|
self.coinCache.remove(key);
|
||||||
}
|
}
|
||||||
@ -1060,19 +1205,19 @@ TXDB.prototype._unconfirm = function unconfirm(tx, info, callback, force) {
|
|||||||
tx.index = -1;
|
tx.index = -1;
|
||||||
tx.block = null;
|
tx.block = null;
|
||||||
|
|
||||||
this.put('t/' + hash, tx.toExtended());
|
this.put(this.key.t(hash), tx.toExtended());
|
||||||
|
|
||||||
this.put('p/' + hash, DUMMY);
|
this.put(this.key.p(hash), DUMMY);
|
||||||
this.del('h/' + pad32(height) + '/' + hash);
|
this.del(this.key.h(height, hash));
|
||||||
|
|
||||||
for (i = 0; i < info.accounts.length; i++) {
|
for (i = 0; i < info.accounts.length; i++) {
|
||||||
account = pad32(info.accounts[i]);
|
account = info.accounts[i];
|
||||||
this.put('P/' + account + '/' + hash, DUMMY);
|
this.put(this.key.P(account, hash), DUMMY);
|
||||||
this.del('H/' + account + '/' + pad32(height) + '/' + hash);
|
this.del(this.key.H(account, height, hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||||
var key = hash + '/' + pad32(i);
|
var key = hash + '/' + i;
|
||||||
self.getCoin(hash, i, function(err, coin) {
|
self.getCoin(hash, i, function(err, coin) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
@ -1086,7 +1231,7 @@ TXDB.prototype._unconfirm = function unconfirm(tx, info, callback, force) {
|
|||||||
coin.height = tx.height;
|
coin.height = tx.height;
|
||||||
coin = coin.toRaw();
|
coin = coin.toRaw();
|
||||||
|
|
||||||
self.put('c/' + key, coin);
|
self.put(self.key.c(hash, i), coin);
|
||||||
|
|
||||||
self.coinCache.set(key, coin);
|
self.coinCache.set(key, coin);
|
||||||
|
|
||||||
@ -1109,6 +1254,8 @@ TXDB.prototype._unconfirm = function unconfirm(tx, info, callback, force) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.getHistoryHashes = function getHistoryHashes(account, callback) {
|
TXDB.prototype.getHistoryHashes = function getHistoryHashes(account, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
if (typeof account === 'function') {
|
if (typeof account === 'function') {
|
||||||
callback = account;
|
callback = account;
|
||||||
account = null;
|
account = null;
|
||||||
@ -1116,16 +1263,18 @@ TXDB.prototype.getHistoryHashes = function getHistoryHashes(account, callback) {
|
|||||||
|
|
||||||
this.iterate({
|
this.iterate({
|
||||||
gte: account != null
|
gte: account != null
|
||||||
? 'T/' + pad32(account) + '/' + constants.NULL_HASH
|
? this.key.T(account, constants.NULL_HASH)
|
||||||
: 't/' + constants.NULL_HASH,
|
: this.key.t(constants.NULL_HASH),
|
||||||
lte: account != null
|
lte: account != null
|
||||||
? 'T/' + pad32(account) + '/' + constants.HIGH_HASH
|
? this.key.T(account, constants.HIGH_HASH)
|
||||||
: 't/' + constants.HIGH_HASH,
|
: this.key.t(constants.HIGH_HASH),
|
||||||
transform: function(key) {
|
transform: function(key) {
|
||||||
key = key.split('/');
|
if (account != null) {
|
||||||
if (account != null)
|
key = self.key.Tt(key);
|
||||||
return key[4];
|
return key[1];
|
||||||
return key[3];
|
}
|
||||||
|
key = self.key.tt(key);
|
||||||
|
return key[0];
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -1137,6 +1286,8 @@ TXDB.prototype.getHistoryHashes = function getHistoryHashes(account, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(account, callback) {
|
TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(account, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
if (typeof account === 'function') {
|
if (typeof account === 'function') {
|
||||||
callback = account;
|
callback = account;
|
||||||
account = null;
|
account = null;
|
||||||
@ -1144,16 +1295,18 @@ TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(account, cal
|
|||||||
|
|
||||||
this.iterate({
|
this.iterate({
|
||||||
gte: account != null
|
gte: account != null
|
||||||
? 'P/' + pad32(account) + '/' + constants.NULL_HASH
|
? this.key.P(account, constants.NULL_HASH)
|
||||||
: 'p/' + constants.NULL_HASH,
|
: this.key.p(constants.NULL_HASH),
|
||||||
lte: account != null
|
lte: account != null
|
||||||
? 'P/' + pad32(account) + '/' + constants.HIGH_HASH
|
? this.key.P(account, constants.HIGH_HASH)
|
||||||
: 'p/' + constants.HIGH_HASH,
|
: this.key.p(constants.HIGH_HASH),
|
||||||
transform: function(key) {
|
transform: function(key) {
|
||||||
key = key.split('/');
|
if (account != null) {
|
||||||
if (account != null)
|
key = self.key.Pp(key);
|
||||||
return key[4];
|
return key[1];
|
||||||
return key[3];
|
}
|
||||||
|
key = self.key.pp(key);
|
||||||
|
return key[0];
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -1165,6 +1318,8 @@ TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(account, cal
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.getCoinHashes = function getCoinHashes(account, callback) {
|
TXDB.prototype.getCoinHashes = function getCoinHashes(account, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
if (typeof account === 'function') {
|
if (typeof account === 'function') {
|
||||||
callback = account;
|
callback = account;
|
||||||
account = null;
|
account = null;
|
||||||
@ -1172,16 +1327,18 @@ TXDB.prototype.getCoinHashes = function getCoinHashes(account, callback) {
|
|||||||
|
|
||||||
this.iterate({
|
this.iterate({
|
||||||
gte: account != null
|
gte: account != null
|
||||||
? 'C/' + pad32(account) + '/' + constants.NULL_HASH + '/' + pad32(0)
|
? this.key.C(account, constants.NULL_HASH, 0)
|
||||||
: 'c/' + constants.NULL_HASH + '/' + pad32(0),
|
: this.key.c(constants.NULL_HASH, 0),
|
||||||
lte: account != null
|
lte: account != null
|
||||||
? 'C/' + pad32(account) + '/' + constants.HIGH_HASH + '/' + pad32(0xffffffff)
|
? this.key.C(account, constants.HIGH_HASH, 0xffffffff)
|
||||||
: 'c/' + constants.HIGH_HASH + '/' + pad32(0xffffffff),
|
: this.key.c(constants.HIGH_HASH, 0xffffffff),
|
||||||
transform: function(key) {
|
transform: function(key) {
|
||||||
key = key.split('/');
|
if (account != null) {
|
||||||
if (account != null)
|
key = self.key.Cc(key);
|
||||||
return [key[4], +key[5]];
|
return [key[1], key[2]];
|
||||||
return [key[3], +key[4]];
|
}
|
||||||
|
key = self.key.cc(key);
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -1198,6 +1355,8 @@ TXDB.prototype.getCoinHashes = function getCoinHashes(account, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(account, options, callback) {
|
TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(account, options, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
if (typeof account !== 'number') {
|
if (typeof account !== 'number') {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = account;
|
options = account;
|
||||||
@ -1206,18 +1365,20 @@ TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(account, opt
|
|||||||
|
|
||||||
this.iterate({
|
this.iterate({
|
||||||
gte: account != null
|
gte: account != null
|
||||||
? 'H/' + pad32(account) + '/' + pad32(options.start) + '/' + constants.NULL_HASH
|
? this.key.H(account, options.start, constants.NULL_HASH)
|
||||||
: 'h/' + pad32(options.start) + '/' + constants.NULL_HASH,
|
: this.key.h(options.start, constants.NULL_HASH),
|
||||||
lte: account != null
|
lte: account != null
|
||||||
? 'H/' + pad32(account) + '/' + pad32(options.end) + '/' + constants.HIGH_HASH
|
? this.key.H(account, options.end, constants.HIGH_HASH)
|
||||||
: 'h/' + pad32(options.end) + '/' + constants.HIGH_HASH,
|
: this.key.h(options.end, constants.HIGH_HASH),
|
||||||
limit: options.limit,
|
limit: options.limit,
|
||||||
reverse: options.reverse,
|
reverse: options.reverse,
|
||||||
transform: function(key) {
|
transform: function(key) {
|
||||||
key = key.split('/');
|
if (account != null) {
|
||||||
if (account != null)
|
key = self.key.Hh(key);
|
||||||
return key[4];
|
return key[2];
|
||||||
return key[3];
|
}
|
||||||
|
key = self.key.hh(key);
|
||||||
|
return key[1];
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -1244,6 +1405,8 @@ TXDB.prototype.getHeightHashes = function getHeightHashes(height, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.getRangeHashes = function getRangeHashes(account, options, callback) {
|
TXDB.prototype.getRangeHashes = function getRangeHashes(account, options, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
if (typeof account === 'function') {
|
if (typeof account === 'function') {
|
||||||
callback = account;
|
callback = account;
|
||||||
account = null;
|
account = null;
|
||||||
@ -1251,18 +1414,20 @@ TXDB.prototype.getRangeHashes = function getRangeHashes(account, options, callba
|
|||||||
|
|
||||||
this.iterate({
|
this.iterate({
|
||||||
gte: account != null
|
gte: account != null
|
||||||
? 'M/' + pad32(account) + '/' + pad32(options.start) + '/' + constants.NULL_HASH
|
? this.key.M(account, options.start, constants.NULL_HASH)
|
||||||
: 'm/' + pad32(options.start) + '/' + constants.NULL_HASH,
|
: this.key.m(options.start, constants.NULL_HASH),
|
||||||
lte: account != null
|
lte: account != null
|
||||||
? 'M/' + pad32(account) + '/' + pad32(options.end) + '/' + constants.HIGH_HASH
|
? this.key.M(account, options.end, constants.HIGH_HASH)
|
||||||
: 'm/' + pad32(options.end) + '/' + constants.HIGH_HASH,
|
: this.key.m(options.end, constants.HIGH_HASH),
|
||||||
limit: options.limit,
|
limit: options.limit,
|
||||||
reverse: options.reverse,
|
reverse: options.reverse,
|
||||||
transform: function(key) {
|
transform: function(key) {
|
||||||
key = key.split('/');
|
if (account != null) {
|
||||||
if (account != null)
|
key = self.key.Mm(key);
|
||||||
return key[4];
|
return key[2];
|
||||||
return key[3];
|
}
|
||||||
|
key = self.key.mm(key);
|
||||||
|
return key[1];
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -1352,8 +1517,8 @@ TXDB.prototype.getHistory = function getHistory(account, callback) {
|
|||||||
|
|
||||||
// Fast case
|
// Fast case
|
||||||
this.iterate({
|
this.iterate({
|
||||||
gte: 't/' + constants.NULL_HASH,
|
gte: this.key.t(constants.NULL_HASH),
|
||||||
lte: 't/' + constants.HIGH_HASH,
|
lte: this.key.t(constants.HIGH_HASH),
|
||||||
values: true,
|
values: true,
|
||||||
parse: function(data) {
|
parse: function(data) {
|
||||||
return bcoin.tx.fromExtended(data);
|
return bcoin.tx.fromExtended(data);
|
||||||
@ -1496,18 +1661,18 @@ TXDB.prototype.getCoins = function getCoins(account, callback) {
|
|||||||
|
|
||||||
// Fast case
|
// Fast case
|
||||||
this.iterate({
|
this.iterate({
|
||||||
gte: 'c/' + constants.NULL_HASH + '/' + pad32(0),
|
gte: this.key.c(constants.NULL_HASH, 0),
|
||||||
lte: 'c/' + constants.HIGH_HASH + '/' + pad32(0xffffffff),
|
lte: this.key.c(constants.HIGH_HASH, 0xffffffff),
|
||||||
keys: true,
|
keys: true,
|
||||||
values: true,
|
values: true,
|
||||||
parse: function(data, key) {
|
parse: function(data, key) {
|
||||||
var parts = key.split('/');
|
var parts = self.key.cc(key);
|
||||||
var hash = parts[3];
|
var hash = parts[0];
|
||||||
var index = +parts[4];
|
var index = parts[1];
|
||||||
var coin = bcoin.coin.fromRaw(data);
|
var coin = bcoin.coin.fromRaw(data);
|
||||||
coin.hash = hash;
|
coin.hash = hash;
|
||||||
coin.index = index;
|
coin.index = index;
|
||||||
key = hash + '/' + pad32(index);
|
key = hash + '/' + index;
|
||||||
self.coinCache.set(key, data);
|
self.coinCache.set(key, data);
|
||||||
return coin;
|
return coin;
|
||||||
}
|
}
|
||||||
@ -1556,6 +1721,7 @@ TXDB.prototype.getAccountCoins = function getCoins(account, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.fillHistory = function fillHistory(tx, callback) {
|
TXDB.prototype.fillHistory = function fillHistory(tx, callback) {
|
||||||
|
var self = this;
|
||||||
var hash, index, coin, input;
|
var hash, index, coin, input;
|
||||||
|
|
||||||
if (tx.isCoinbase()) {
|
if (tx.isCoinbase()) {
|
||||||
@ -1566,12 +1732,12 @@ TXDB.prototype.fillHistory = function fillHistory(tx, callback) {
|
|||||||
hash = tx.hash('hex');
|
hash = tx.hash('hex');
|
||||||
|
|
||||||
this.iterate({
|
this.iterate({
|
||||||
gte: 'd/' + hash + '/' + pad32(0),
|
gte: this.key.d(hash, 0),
|
||||||
lte: 'd/' + hash + '/' + pad32(0xffffffff),
|
lte: this.key.d(hash, 0xffffffff),
|
||||||
keys: true,
|
keys: true,
|
||||||
values: true,
|
values: true,
|
||||||
parse: function(value, key) {
|
parse: function(value, key) {
|
||||||
index = +key.split('/')[4];
|
index = self.key.dd(key)[1];
|
||||||
coin = bcoin.coin.fromRaw(value);
|
coin = bcoin.coin.fromRaw(value);
|
||||||
input = tx.inputs[index];
|
input = tx.inputs[index];
|
||||||
coin.hash = input.prevout.hash;
|
coin.hash = input.prevout.hash;
|
||||||
@ -1628,7 +1794,7 @@ TXDB.prototype.fillCoins = function fillCoins(tx, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.getTX = function getTX(hash, callback) {
|
TXDB.prototype.getTX = function getTX(hash, callback) {
|
||||||
this.fetch('t/' + hash, function(tx) {
|
this.fetch(this.key.t(hash), function(tx) {
|
||||||
return bcoin.tx.fromExtended(tx);
|
return bcoin.tx.fromExtended(tx);
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -1705,7 +1871,7 @@ TXDB.prototype.toDetails = function toDetails(tx, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.hasTX = function hasTX(hash, callback) {
|
TXDB.prototype.hasTX = function hasTX(hash, callback) {
|
||||||
this.has('t/' + hash, callback);
|
this.has(this.key.t(hash), callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1717,7 +1883,7 @@ TXDB.prototype.hasTX = function hasTX(hash, callback) {
|
|||||||
|
|
||||||
TXDB.prototype.getCoin = function getCoin(hash, index, callback) {
|
TXDB.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var key = hash + '/' + pad32(index);
|
var key = hash + '/' + index;
|
||||||
var coin = this.coinCache.get(key);
|
var coin = this.coinCache.get(key);
|
||||||
|
|
||||||
if (coin) {
|
if (coin) {
|
||||||
@ -1731,7 +1897,7 @@ TXDB.prototype.getCoin = function getCoin(hash, index, callback) {
|
|||||||
return callback(null, coin);
|
return callback(null, coin);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fetch('c/' + key, function(data) {
|
this.fetch(this.key.c(hash, index), function(data) {
|
||||||
coin = bcoin.coin.fromRaw(data);
|
coin = bcoin.coin.fromRaw(data);
|
||||||
coin.hash = hash;
|
coin.hash = hash;
|
||||||
coin.index = index;
|
coin.index = index;
|
||||||
@ -1747,12 +1913,12 @@ TXDB.prototype.getCoin = function getCoin(hash, index, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.hasCoin = function hasCoin(hash, index, callback) {
|
TXDB.prototype.hasCoin = function hasCoin(hash, index, callback) {
|
||||||
var key = hash + '/' + pad32(index);
|
var key = hash + '/' + index;
|
||||||
|
|
||||||
if (this.coinCache.has(key))
|
if (this.coinCache.has(key))
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
this.has('c/' + key, callback);
|
this.has(this.key.c(hash, index), callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1782,14 +1948,14 @@ TXDB.prototype.getBalance = function getBalance(account, callback) {
|
|||||||
balance = new Balance(this.wallet);
|
balance = new Balance(this.wallet);
|
||||||
|
|
||||||
this.iterate({
|
this.iterate({
|
||||||
gte: 'c/' + constants.NULL_HASH + '/' + pad32(0),
|
gte: this.key.c(constants.NULL_HASH, 0),
|
||||||
lte: 'c/' + constants.HIGH_HASH + '/' + pad32(0xffffffff),
|
lte: this.key.c(constants.HIGH_HASH, 0xffffffff),
|
||||||
keys: true,
|
keys: true,
|
||||||
values: true,
|
values: true,
|
||||||
parse: function(data, key) {
|
parse: function(data, key) {
|
||||||
var parts = key.split('/');
|
var parts = self.key.cc(key);
|
||||||
var hash = parts[3];
|
var hash = parts[0];
|
||||||
var index = +parts[4];
|
var index = parts[1];
|
||||||
var height = data.readUInt32LE(4, true);
|
var height = data.readUInt32LE(4, true);
|
||||||
var value = utils.read64N(data, 8);
|
var value = utils.read64N(data, 8);
|
||||||
|
|
||||||
@ -1802,7 +1968,7 @@ TXDB.prototype.getBalance = function getBalance(account, callback) {
|
|||||||
else
|
else
|
||||||
balance.confirmed += value;
|
balance.confirmed += value;
|
||||||
|
|
||||||
key = hash + '/' + pad32(index);
|
key = hash + '/' + index;
|
||||||
|
|
||||||
self.coinCache.set(key, data);
|
self.coinCache.set(key, data);
|
||||||
}
|
}
|
||||||
@ -1844,7 +2010,7 @@ TXDB.prototype.getAccountBalance = function getBalance(account, callback) {
|
|||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
utils.forEachSerial(hashes, function(hash, next) {
|
utils.forEachSerial(hashes, function(hash, next) {
|
||||||
key = hash[0] + '/' + pad32(hash[1]);
|
key = hash[0] + '/' + hash[1];
|
||||||
coin = self.coinCache.get(key);
|
coin = self.coinCache.get(key);
|
||||||
|
|
||||||
if (coin) {
|
if (coin) {
|
||||||
@ -1856,7 +2022,7 @@ TXDB.prototype.getAccountBalance = function getBalance(account, callback) {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.get('c/' + key, function(err, data) {
|
self.get(self.key.c(hash[0], hash[1]), function(err, data) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
@ -1932,7 +2098,7 @@ TXDB.prototype.zap = function zap(account, age, callback, force) {
|
|||||||
|
|
||||||
TXDB.prototype.abandon = function abandon(hash, callback, force) {
|
TXDB.prototype.abandon = function abandon(hash, callback, force) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.has('p/' + hash, function(err, result) {
|
this.has(this.key.p(hash), function(err, result) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
* t/[wid]/* -> txdb
|
* t/[wid]/* -> txdb
|
||||||
* R -> tip
|
* R -> tip
|
||||||
* b/[hash] -> wallet block
|
* b/[hash] -> wallet block
|
||||||
* t/[hash] -> tx->wid map
|
* e/[hash] -> tx->wid map
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var bcoin = require('./env');
|
var bcoin = require('./env');
|
||||||
@ -31,6 +31,43 @@ var BufferWriter = require('./writer');
|
|||||||
var TXDB = require('./txdb');
|
var TXDB = require('./txdb');
|
||||||
var keyTypes = bcoin.keyring.types;
|
var keyTypes = bcoin.keyring.types;
|
||||||
|
|
||||||
|
var layout = {
|
||||||
|
p: function(hash) {
|
||||||
|
return 'p' + hash;
|
||||||
|
},
|
||||||
|
pp: function(key) {
|
||||||
|
return key.slice(1);
|
||||||
|
},
|
||||||
|
w: function(wid) {
|
||||||
|
return 'w' + pad32(wid);
|
||||||
|
},
|
||||||
|
ww: function(key) {
|
||||||
|
return +key.slice(1);
|
||||||
|
},
|
||||||
|
l: function(id) {
|
||||||
|
return 'l' + id;
|
||||||
|
},
|
||||||
|
ll: function(key) {
|
||||||
|
return key.slice(1);
|
||||||
|
},
|
||||||
|
a: function a(wid, index) {
|
||||||
|
return 'a' + pad32(wid) + pad32(index);
|
||||||
|
},
|
||||||
|
i: function i(wid, name) {
|
||||||
|
return 'i' + pad32(wid) + name;
|
||||||
|
},
|
||||||
|
ii: function ii(key) {
|
||||||
|
return [+key.slice(1, 11), key.slice(11)];
|
||||||
|
},
|
||||||
|
R: 'R',
|
||||||
|
b: function b(hash) {
|
||||||
|
return 'b' + hash;
|
||||||
|
},
|
||||||
|
e: function e(hash) {
|
||||||
|
return 'e' + hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WalletDB
|
* WalletDB
|
||||||
* @exports WalletDB
|
* @exports WalletDB
|
||||||
@ -194,8 +231,8 @@ WalletDB.prototype.getDepth = function getDepth(callback) {
|
|||||||
// walletdb.create by simply seeking to the
|
// walletdb.create by simply seeking to the
|
||||||
// highest wallet wid.
|
// highest wallet wid.
|
||||||
iter = this.db.iterator({
|
iter = this.db.iterator({
|
||||||
gte: 'w/' + pad32(0),
|
gte: layout.w(0),
|
||||||
lte: 'w/' + pad32(0xffffffff),
|
lte: layout.w(0xffffffff),
|
||||||
reverse: true,
|
reverse: true,
|
||||||
keys: true,
|
keys: true,
|
||||||
values: false,
|
values: false,
|
||||||
@ -218,8 +255,7 @@ WalletDB.prototype.getDepth = function getDepth(callback) {
|
|||||||
if (key === undefined)
|
if (key === undefined)
|
||||||
return callback(null, 1);
|
return callback(null, 1);
|
||||||
|
|
||||||
parts = key.split('/');
|
depth = layout.ww(key);
|
||||||
depth = +parts[1];
|
|
||||||
|
|
||||||
callback(null, depth + 1);
|
callback(null, depth + 1);
|
||||||
});
|
});
|
||||||
@ -291,10 +327,10 @@ WalletDB.prototype.loadFilter = function loadFilter(callback) {
|
|||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
this.db.iterate({
|
this.db.iterate({
|
||||||
gte: 'p/' + constants.NULL_HASH,
|
gte: layout.p(constants.NULL_HASH),
|
||||||
lte: 'p/' + constants.HIGH_HASH,
|
lte: layout.p(constants.HIGH_HASH),
|
||||||
transform: function(key) {
|
transform: function(key) {
|
||||||
key = key.split('/')[1];
|
key = layout.pp(key);
|
||||||
self.filter.add(key, 'hex');
|
self.filter.add(key, 'hex');
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
@ -385,7 +421,7 @@ WalletDB.prototype.getWalletID = function getWalletID(id, callback) {
|
|||||||
if (wid)
|
if (wid)
|
||||||
return callback(null, wid);
|
return callback(null, wid);
|
||||||
|
|
||||||
this.db.fetch('l/' + id, function(data) {
|
this.db.fetch(layout.l(id), function(data) {
|
||||||
wid = data.readUInt32LE(0, true);
|
wid = data.readUInt32LE(0, true);
|
||||||
self.walletCache.set(id, wid);
|
self.walletCache.set(id, wid);
|
||||||
return wid;
|
return wid;
|
||||||
@ -457,7 +493,7 @@ WalletDB.prototype._get = function get(wid, callback) {
|
|||||||
if (wallet)
|
if (wallet)
|
||||||
return callback(null, wallet, true);
|
return callback(null, wallet, true);
|
||||||
|
|
||||||
this.db.fetch('w/' + pad32(wid), function(data) {
|
this.db.fetch(layout.w(wid), function(data) {
|
||||||
return bcoin.wallet.fromRaw(self, data);
|
return bcoin.wallet.fromRaw(self, data);
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -472,9 +508,9 @@ WalletDB.prototype.save = function save(wallet) {
|
|||||||
var batch = this.batch(wallet.wid);
|
var batch = this.batch(wallet.wid);
|
||||||
var wid = new Buffer(4);
|
var wid = new Buffer(4);
|
||||||
this.walletCache.set(wallet.id, wallet.wid);
|
this.walletCache.set(wallet.id, wallet.wid);
|
||||||
batch.put('w/' + pad32(wallet.wid), wallet.toRaw());
|
batch.put(layout.w(wallet.wid), wallet.toRaw());
|
||||||
wid.writeUInt32LE(wallet.wid, 0, true);
|
wid.writeUInt32LE(wallet.wid, 0, true);
|
||||||
batch.put('l/' + wallet.id, wid);
|
batch.put(layout.l(wallet.id), wid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -646,7 +682,7 @@ WalletDB.prototype._getAccount = function getAccount(wid, index, callback) {
|
|||||||
if (account)
|
if (account)
|
||||||
return callback(null, account);
|
return callback(null, account);
|
||||||
|
|
||||||
this.db.fetch('a/' + key, function(data) {
|
this.db.fetch(layout.a(wid, index), function(data) {
|
||||||
account = bcoin.account.fromRaw(self, data);
|
account = bcoin.account.fromRaw(self, data);
|
||||||
self.accountCache.set(key, account);
|
self.accountCache.set(key, account);
|
||||||
return account;
|
return account;
|
||||||
@ -664,11 +700,11 @@ WalletDB.prototype.getAccounts = function getAccounts(wid, callback) {
|
|||||||
var i, accounts;
|
var i, accounts;
|
||||||
|
|
||||||
this.db.iterate({
|
this.db.iterate({
|
||||||
gte: 'i/' + pad32(wid) + '/',
|
gte: layout.i(wid, ''),
|
||||||
lte: 'i/' + pad32(wid) + '/~',
|
lte: layout.i(wid, '~'),
|
||||||
values: true,
|
values: true,
|
||||||
parse: function(value, key) {
|
parse: function(value, key) {
|
||||||
var name = key.split('/')[2];
|
var name = layout.ii(key)[1];
|
||||||
var index = value.readUInt32LE(0, true);
|
var index = value.readUInt32LE(0, true);
|
||||||
map[index] = name;
|
map[index] = name;
|
||||||
}
|
}
|
||||||
@ -705,7 +741,7 @@ WalletDB.prototype.getAccountIndex = function getAccountIndex(wid, name, callbac
|
|||||||
if (typeof name === 'number')
|
if (typeof name === 'number')
|
||||||
return callback(null, name);
|
return callback(null, name);
|
||||||
|
|
||||||
this.db.get('i/' + pad32(wid) + '/' + name, function(err, index) {
|
this.db.get(layout.i(wid, name), function(err, index) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -729,8 +765,8 @@ WalletDB.prototype.saveAccount = function saveAccount(account) {
|
|||||||
|
|
||||||
index.writeUInt32LE(account.accountIndex, 0, true);
|
index.writeUInt32LE(account.accountIndex, 0, true);
|
||||||
|
|
||||||
batch.put('a/' + key, account.toRaw());
|
batch.put(layout.a(account.wid, account.accountIndex), account.toRaw());
|
||||||
batch.put('i/' + pad32(account.wid) + '/' + account.name, index);
|
batch.put(layout.i(account.wid, account.name), index);
|
||||||
|
|
||||||
this.accountCache.set(key, account);
|
this.accountCache.set(key, account);
|
||||||
};
|
};
|
||||||
@ -801,7 +837,7 @@ WalletDB.prototype.hasAccount = function hasAccount(wid, account, callback) {
|
|||||||
if (self.accountCache.has(key))
|
if (self.accountCache.has(key))
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
self.db.has('a/' + key, callback);
|
self.db.has(layout.a(wid, index), callback);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -854,7 +890,7 @@ WalletDB.prototype.saveAddress = function saveAddress(wid, addresses, callback)
|
|||||||
|
|
||||||
self.pathCache.set(hash, paths);
|
self.pathCache.set(hash, paths);
|
||||||
|
|
||||||
batch.put('p/' + hash, serializePaths(paths));
|
batch.put(layout.p(hash), serializePaths(paths));
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@ -879,7 +915,7 @@ WalletDB.prototype.getPaths = function getPaths(hash, callback) {
|
|||||||
if (paths)
|
if (paths)
|
||||||
return callback(null, paths);
|
return callback(null, paths);
|
||||||
|
|
||||||
this.db.fetch('p/' + hash, parsePaths, function(err, paths) {
|
this.db.fetch(layout.p(hash), parsePaths, function(err, paths) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -925,8 +961,8 @@ WalletDB.prototype.getAddresses = function getAddresses(wid, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.db.iterate({
|
this.db.iterate({
|
||||||
gte: 'p/' + constants.NULL_HASH,
|
gte: layout.p(constants.NULL_HASH),
|
||||||
lte: 'p/' + constants.HIGH_HASH,
|
lte: layout.p(constants.HIGH_HASH),
|
||||||
values: true,
|
values: true,
|
||||||
parse: function(value, key) {
|
parse: function(value, key) {
|
||||||
var paths = parsePaths(value);
|
var paths = parsePaths(value);
|
||||||
@ -934,7 +970,7 @@ WalletDB.prototype.getAddresses = function getAddresses(wid, callback) {
|
|||||||
if (wid && !paths[wid])
|
if (wid && !paths[wid])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
return key.split('/')[1];
|
return layout.pp(key);
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -946,10 +982,10 @@ WalletDB.prototype.getAddresses = function getAddresses(wid, callback) {
|
|||||||
|
|
||||||
WalletDB.prototype.getWallets = function getWallets(callback) {
|
WalletDB.prototype.getWallets = function getWallets(callback) {
|
||||||
this.db.iterate({
|
this.db.iterate({
|
||||||
gte: 'l/',
|
gte: layout.l(''),
|
||||||
lte: 'l/~',
|
lte: layout.l('~'),
|
||||||
transform: function(key) {
|
transform: function(key) {
|
||||||
return key.split('/')[1];
|
return layout.ll(key);
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -1126,7 +1162,7 @@ WalletDB.prototype.writeGenesis = function writeGenesis(callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.getTip = function getTip(callback) {
|
WalletDB.prototype.getTip = function getTip(callback) {
|
||||||
this.db.fetch('R', function(data) {
|
this.db.fetch(layout.R, function(data) {
|
||||||
return WalletBlock.fromTip(data);
|
return WalletBlock.fromTip(data);
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -1141,7 +1177,7 @@ WalletDB.prototype.getTip = function getTip(callback) {
|
|||||||
WalletDB.prototype.setTip = function setTip(hash, height, callback) {
|
WalletDB.prototype.setTip = function setTip(hash, height, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var block = new WalletBlock(hash, height);
|
var block = new WalletBlock(hash, height);
|
||||||
this.db.put('R', block.toTip(), function(err) {
|
this.db.put(layout.R, block.toTip(), function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -1163,15 +1199,15 @@ WalletDB.prototype.writeBlock = function writeBlock(block, matches, callback) {
|
|||||||
var batch = this.db.batch();
|
var batch = this.db.batch();
|
||||||
var i, hash, wallets;
|
var i, hash, wallets;
|
||||||
|
|
||||||
batch.put('R', block.toTip());
|
batch.put(layout.R, block.toTip());
|
||||||
|
|
||||||
if (block.hashes.length > 0) {
|
if (block.hashes.length > 0) {
|
||||||
batch.put('b/' + block.hash, block.toRaw());
|
batch.put(layout.b(block.hash), block.toRaw());
|
||||||
|
|
||||||
for (i = 0; i < block.hashes.length; i++) {
|
for (i = 0; i < block.hashes.length; i++) {
|
||||||
hash = block.hashes[i];
|
hash = block.hashes[i];
|
||||||
wallets = matches[i];
|
wallets = matches[i];
|
||||||
batch.put('t/' + hash, serializeWallets(wallets));
|
batch.put(layout.e(hash), serializeWallets(wallets));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1189,8 +1225,8 @@ WalletDB.prototype.unwriteBlock = function unwriteBlock(block, callback) {
|
|||||||
var batch = this.db.batch();
|
var batch = this.db.batch();
|
||||||
var prev = new WalletBlock(block.prevBlock, block.height - 1);
|
var prev = new WalletBlock(block.prevBlock, block.height - 1);
|
||||||
|
|
||||||
batch.put('R', prev.toTip());
|
batch.put(layout.R, prev.toTip());
|
||||||
batch.del('b/' + block.hash);
|
batch.del(layout.b(block.hash));
|
||||||
|
|
||||||
batch.write(callback);
|
batch.write(callback);
|
||||||
};
|
};
|
||||||
@ -1202,7 +1238,7 @@ WalletDB.prototype.unwriteBlock = function unwriteBlock(block, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.getBlock = function getBlock(hash, callback) {
|
WalletDB.prototype.getBlock = function getBlock(hash, callback) {
|
||||||
this.db.fetch('b/' + hash, function(err, data) {
|
this.db.fetch(layout.b(hash), function(err, data) {
|
||||||
return WalletBlock.fromRaw(hash, data);
|
return WalletBlock.fromRaw(hash, data);
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
@ -1214,7 +1250,7 @@ WalletDB.prototype.getBlock = function getBlock(hash, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.getWalletsByTX = function getWalletsByTX(hash, callback) {
|
WalletDB.prototype.getWalletsByTX = function getWalletsByTX(hash, callback) {
|
||||||
this.db.fetch('t/' + hash, parseWallets, callback);
|
this.db.fetch(layout.e(hash), parseWallets, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1004,7 +1004,7 @@ describe('Wallet', function() {
|
|||||||
it('should cleanup', function(cb) {
|
it('should cleanup', function(cb) {
|
||||||
walletdb.dump(function(err, records) {
|
walletdb.dump(function(err, records) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
// utils.log(JSON.stringify(Object.keys(records), null, 2));
|
//utils.log(JSON.stringify(Object.keys(records), null, 2));
|
||||||
constants.tx.COINBASE_MATURITY = 100;
|
constants.tx.COINBASE_MATURITY = 100;
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user