|
|
|
|
@ -47,6 +47,7 @@ var layout = {
|
|
|
|
|
pre: function prefix(key) {
|
|
|
|
|
return key.readUInt32BE(1, true);
|
|
|
|
|
},
|
|
|
|
|
R: new Buffer([0x52]),
|
|
|
|
|
hi: function hi(ch, hash, index) {
|
|
|
|
|
var key = new Buffer(37);
|
|
|
|
|
key[0] = ch;
|
|
|
|
|
@ -211,10 +212,13 @@ function TXDB(wallet) {
|
|
|
|
|
this.logger = wallet.db.logger;
|
|
|
|
|
this.network = wallet.db.network;
|
|
|
|
|
this.options = wallet.db.options;
|
|
|
|
|
this.locked = {};
|
|
|
|
|
|
|
|
|
|
this.coinCache = new LRU(10000);
|
|
|
|
|
|
|
|
|
|
this.locked = {};
|
|
|
|
|
this.state = null;
|
|
|
|
|
this.balance = null;
|
|
|
|
|
this.pending = null;
|
|
|
|
|
this.events = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -230,8 +234,21 @@ TXDB.layout = layout;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.open = co(function* open() {
|
|
|
|
|
this.balance = yield this.getBalance();
|
|
|
|
|
this.logger.info('TXDB loaded for %s.', this.wallet.id);
|
|
|
|
|
var state = yield this.getState();
|
|
|
|
|
|
|
|
|
|
if (state) {
|
|
|
|
|
this.state = state;
|
|
|
|
|
this.logger.info('TXDB loaded for %s.', this.wallet.id);
|
|
|
|
|
} else {
|
|
|
|
|
this.state = new TXDBState(this.wallet.wid, this.wallet.id);
|
|
|
|
|
this.logger.info('TXDB created for %s.', this.wallet.id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.balance = this.state.balance;
|
|
|
|
|
|
|
|
|
|
this.logger.info('TXDB State: tx=%d coin=%s.',
|
|
|
|
|
this.state.tx, this.state.coin);
|
|
|
|
|
|
|
|
|
|
this.logger.info(
|
|
|
|
|
'Balance: unconfirmed=%s confirmed=%s total=%s.',
|
|
|
|
|
utils.btc(this.balance.unconfirmed),
|
|
|
|
|
@ -239,17 +256,83 @@ TXDB.prototype.open = co(function* open() {
|
|
|
|
|
utils.btc(this.balance.total));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Start batch.
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.start = function start() {
|
|
|
|
|
this.pending = this.state.clone();
|
|
|
|
|
return this.wallet.start();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Drop batch.
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.drop = function drop() {
|
|
|
|
|
this.pending = null;
|
|
|
|
|
this.events.length = 0;
|
|
|
|
|
return this.wallet.drop();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Clear batch.
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.clear = function clear() {
|
|
|
|
|
this.pending = this.state.clone();
|
|
|
|
|
this.events.length = 0;
|
|
|
|
|
return this.wallet.clear();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Save batch.
|
|
|
|
|
* @returns {Promise}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.commit = co(function* commit() {
|
|
|
|
|
var i, item;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
yield this.wallet.commit();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
this.pending = null;
|
|
|
|
|
this.events.length = 0;
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Overwrite the entire state
|
|
|
|
|
// with our new committed state.
|
|
|
|
|
if (this.pending.committed) {
|
|
|
|
|
this.state = this.pending;
|
|
|
|
|
this.balance = this.state.balance;
|
|
|
|
|
|
|
|
|
|
// Emit buffered events now that
|
|
|
|
|
// we know everything is written.
|
|
|
|
|
for (i = 0; i < this.events.length; i++) {
|
|
|
|
|
item = this.events[i];
|
|
|
|
|
this.walletdb.emit(item[0], this.wallet.id, item[1], item[2]);
|
|
|
|
|
this.wallet.emit(item[0], item[1], item[2]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.pending = null;
|
|
|
|
|
this.events.length = 0;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Emit transaction event.
|
|
|
|
|
* @private
|
|
|
|
|
* @param {String} event
|
|
|
|
|
* @param {TX} tx
|
|
|
|
|
* @param {Object} data
|
|
|
|
|
* @param {PathInfo} info
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.emit = function emit(event, tx, info) {
|
|
|
|
|
this.walletdb.emit(event, info.id, tx, info);
|
|
|
|
|
this.wallet.emit(event, tx, info);
|
|
|
|
|
TXDB.prototype.emit = function emit(event, data, info) {
|
|
|
|
|
this.events.push([event, data, info]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -502,7 +585,7 @@ TXDB.prototype.verify = co(function* verify(tx, info) {
|
|
|
|
|
// remove other transactions on behalf of
|
|
|
|
|
// a non-eligible tx.
|
|
|
|
|
if (!conflict) {
|
|
|
|
|
this.wallet.clear();
|
|
|
|
|
this.clear();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -569,7 +652,7 @@ TXDB.prototype.resolveOrphans = co(function* resolveOrphans(tx, index) {
|
|
|
|
|
// We had orphans, but they were invalid. The
|
|
|
|
|
// balance will be (incorrectly) added outside.
|
|
|
|
|
// Subtract to compensate.
|
|
|
|
|
this.balance.sub(coin);
|
|
|
|
|
this.pending.sub(coin);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
@ -585,16 +668,16 @@ TXDB.prototype.add = co(function* add(tx) {
|
|
|
|
|
var info = yield this.getPathInfo(tx);
|
|
|
|
|
var result;
|
|
|
|
|
|
|
|
|
|
this.wallet.start();
|
|
|
|
|
this.start();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
result = yield this._add(tx, info);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
this.wallet.drop();
|
|
|
|
|
this.drop();
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield this.wallet.commit();
|
|
|
|
|
yield this.commit();
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
});
|
|
|
|
|
@ -681,7 +764,7 @@ TXDB.prototype._add = co(function* add(tx, info) {
|
|
|
|
|
this.del(layout.c(prevout.hash, prevout.index));
|
|
|
|
|
this.del(layout.C(path.account, prevout.hash, prevout.index));
|
|
|
|
|
this.put(layout.d(hash, i), input.coin.toRaw());
|
|
|
|
|
this.balance.sub(input.coin);
|
|
|
|
|
this.pending.sub(input.coin);
|
|
|
|
|
|
|
|
|
|
this.coinCache.remove(key);
|
|
|
|
|
}
|
|
|
|
|
@ -709,7 +792,7 @@ TXDB.prototype._add = co(function* add(tx, info) {
|
|
|
|
|
|
|
|
|
|
coin = Coin.fromTX(tx, i);
|
|
|
|
|
|
|
|
|
|
this.balance.add(coin);
|
|
|
|
|
this.pending.add(coin);
|
|
|
|
|
|
|
|
|
|
coin = coin.toRaw();
|
|
|
|
|
|
|
|
|
|
@ -727,6 +810,11 @@ TXDB.prototype._add = co(function* add(tx, info) {
|
|
|
|
|
if (tx.ts !== 0)
|
|
|
|
|
this.emit('confirmed', tx, info);
|
|
|
|
|
|
|
|
|
|
this.emit('balance', this.pending.balance, info);
|
|
|
|
|
|
|
|
|
|
this.pending.tx++;
|
|
|
|
|
this.put(layout.R, this.pending.commit());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@ -926,7 +1014,7 @@ TXDB.prototype.confirm = co(function* confirm(tx, info) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.balance.confirm(coin.value);
|
|
|
|
|
this.pending.confirm(coin.value);
|
|
|
|
|
|
|
|
|
|
coin.height = tx.height;
|
|
|
|
|
coin = coin.toRaw();
|
|
|
|
|
@ -938,6 +1026,9 @@ TXDB.prototype.confirm = co(function* confirm(tx, info) {
|
|
|
|
|
|
|
|
|
|
this.emit('tx', tx, info);
|
|
|
|
|
this.emit('confirmed', tx, info);
|
|
|
|
|
this.emit('balance', this.pending.balance, info);
|
|
|
|
|
|
|
|
|
|
this.put(layout.R, this.pending.commit());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
@ -951,16 +1042,16 @@ TXDB.prototype.confirm = co(function* confirm(tx, info) {
|
|
|
|
|
TXDB.prototype.remove = co(function* remove(hash) {
|
|
|
|
|
var result;
|
|
|
|
|
|
|
|
|
|
this.wallet.start();
|
|
|
|
|
this.start();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
result = yield this._remove(hash);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
this.wallet.drop();
|
|
|
|
|
this.drop();
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield this.wallet.commit();
|
|
|
|
|
yield this.commit();
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
});
|
|
|
|
|
@ -1055,7 +1146,7 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
|
|
|
|
|
if (!path)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
this.balance.add(input.coin);
|
|
|
|
|
this.pending.add(input.coin);
|
|
|
|
|
|
|
|
|
|
coin = input.coin.toRaw();
|
|
|
|
|
|
|
|
|
|
@ -1081,7 +1172,7 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
|
|
|
|
|
|
|
|
|
|
coin = Coin.fromTX(tx, i);
|
|
|
|
|
|
|
|
|
|
this.balance.sub(coin);
|
|
|
|
|
this.pending.sub(coin);
|
|
|
|
|
|
|
|
|
|
this.del(layout.c(hash, i));
|
|
|
|
|
this.del(layout.C(path.account, hash, i));
|
|
|
|
|
@ -1090,6 +1181,10 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.emit('remove tx', tx, info);
|
|
|
|
|
this.emit('balance', this.pending.balance, info);
|
|
|
|
|
|
|
|
|
|
this.pending.tx--;
|
|
|
|
|
this.put(layout.R, this.pending.commit());
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
});
|
|
|
|
|
@ -1103,16 +1198,16 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
|
|
|
|
|
TXDB.prototype.unconfirm = co(function* unconfirm(hash) {
|
|
|
|
|
var result;
|
|
|
|
|
|
|
|
|
|
this.wallet.start();
|
|
|
|
|
this.start();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
result = yield this._unconfirm(hash);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
this.wallet.drop();
|
|
|
|
|
this.drop();
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield this.wallet.commit();
|
|
|
|
|
yield this.commit();
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
});
|
|
|
|
|
@ -1183,7 +1278,7 @@ TXDB.prototype.__unconfirm = co(function* unconfirm(tx, info) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.balance.unconfirm(coin.value);
|
|
|
|
|
this.pending.unconfirm(coin.value);
|
|
|
|
|
|
|
|
|
|
coin.height = tx.height;
|
|
|
|
|
coin = coin.toRaw();
|
|
|
|
|
@ -1194,6 +1289,9 @@ TXDB.prototype.__unconfirm = co(function* unconfirm(tx, info) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.emit('unconfirmed', tx, info);
|
|
|
|
|
this.emit('balance', this.pending.balance, info);
|
|
|
|
|
|
|
|
|
|
this.put(layout.R, this.pending.commit());
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
});
|
|
|
|
|
@ -1303,6 +1401,23 @@ TXDB.prototype.getLocked = function getLocked() {
|
|
|
|
|
return outpoints;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get hashes of all transactions in the database.
|
|
|
|
|
* @param {Number?} account
|
|
|
|
|
* @returns {Promise} - Returns {@link Hash}[].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getAccountHistoryHashes = function getHistoryHashes(account) {
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.T(account, constants.NULL_HASH),
|
|
|
|
|
lte: layout.T(account, constants.HIGH_HASH),
|
|
|
|
|
parse: function(key) {
|
|
|
|
|
key = layout.Tt(key);
|
|
|
|
|
return key[1];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get hashes of all transactions in the database.
|
|
|
|
|
* @param {Number?} account
|
|
|
|
|
@ -1310,16 +1425,8 @@ TXDB.prototype.getLocked = function getLocked() {
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getHistoryHashes = function getHistoryHashes(account) {
|
|
|
|
|
if (account != null) {
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.T(account, constants.NULL_HASH),
|
|
|
|
|
lte: layout.T(account, constants.HIGH_HASH),
|
|
|
|
|
parse: function(key) {
|
|
|
|
|
key = layout.Tt(key);
|
|
|
|
|
return key[1];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (account != null)
|
|
|
|
|
return this.getAccountHistoryHashes(account);
|
|
|
|
|
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.t(constants.NULL_HASH),
|
|
|
|
|
@ -1334,17 +1441,26 @@ TXDB.prototype.getHistoryHashes = function getHistoryHashes(account) {
|
|
|
|
|
* @returns {Promise} - Returns {@link Hash}[].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(account) {
|
|
|
|
|
if (account != null) {
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.P(account, constants.NULL_HASH),
|
|
|
|
|
lte: layout.P(account, constants.HIGH_HASH),
|
|
|
|
|
parse: function(key) {
|
|
|
|
|
key = layout.Pp(key);
|
|
|
|
|
return key[1];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
TXDB.prototype.getAccountPendingHashes = function getAccountPendingHashes(account) {
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.P(account, constants.NULL_HASH),
|
|
|
|
|
lte: layout.P(account, constants.HIGH_HASH),
|
|
|
|
|
parse: function(key) {
|
|
|
|
|
key = layout.Pp(key);
|
|
|
|
|
return key[1];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get hashes of all unconfirmed transactions in the database.
|
|
|
|
|
* @param {Number?} account
|
|
|
|
|
* @returns {Promise} - Returns {@link Hash}[].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getPendingHashes = function getPendingHashes(account) {
|
|
|
|
|
if (account != null)
|
|
|
|
|
return this.getAccountPendingHashes(account);
|
|
|
|
|
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.p(constants.NULL_HASH),
|
|
|
|
|
@ -1353,6 +1469,23 @@ TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(account) {
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get all coin hashes in the database.
|
|
|
|
|
* @param {Number?} account
|
|
|
|
|
* @returns {Promise} - Returns {@link Hash}[].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getAccountOutpoints = function getAccountOutpoints(account) {
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.C(account, constants.NULL_HASH, 0),
|
|
|
|
|
lte: layout.C(account, constants.HIGH_HASH, 0xffffffff),
|
|
|
|
|
parse: function(key) {
|
|
|
|
|
key = layout.Cc(key);
|
|
|
|
|
return new Outpoint(key[1], key[2]);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get all coin hashes in the database.
|
|
|
|
|
* @param {Number?} account
|
|
|
|
|
@ -1360,16 +1493,8 @@ TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(account) {
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getOutpoints = function getOutpoints(account) {
|
|
|
|
|
if (account != null) {
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.C(account, constants.NULL_HASH, 0),
|
|
|
|
|
lte: layout.C(account, constants.HIGH_HASH, 0xffffffff),
|
|
|
|
|
parse: function(key) {
|
|
|
|
|
key = layout.Cc(key);
|
|
|
|
|
return new Outpoint(key[1], key[2]);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (account != null)
|
|
|
|
|
return this.getAccountOutpoints(account);
|
|
|
|
|
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.c(constants.NULL_HASH, 0),
|
|
|
|
|
@ -1438,6 +1563,33 @@ TXDB.prototype.getHeightHashes = function getHeightHashes(height) {
|
|
|
|
|
return this.getHeightRangeHashes({ start: height, end: height });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get TX hashes by timestamp range.
|
|
|
|
|
* @param {Number?} account
|
|
|
|
|
* @param {Object} options
|
|
|
|
|
* @param {Number} options.start - Start height.
|
|
|
|
|
* @param {Number} options.end - End height.
|
|
|
|
|
* @param {Number?} options.limit - Max number of records.
|
|
|
|
|
* @param {Boolean?} options.reverse - Reverse order.
|
|
|
|
|
* @returns {Promise} - Returns {@link Hash}[].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getAccountRangeHashes = function getAccountRangeHashes(account, options) {
|
|
|
|
|
var start = options.start || 0;
|
|
|
|
|
var end = options.end || 0xffffffff;
|
|
|
|
|
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.M(account, start, constants.NULL_HASH),
|
|
|
|
|
lte: layout.M(account, end, constants.HIGH_HASH),
|
|
|
|
|
limit: options.limit,
|
|
|
|
|
reverse: options.reverse,
|
|
|
|
|
parse: function(key) {
|
|
|
|
|
key = layout.Mm(key);
|
|
|
|
|
return key[2];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get TX hashes by timestamp range.
|
|
|
|
|
* @param {Number?} account
|
|
|
|
|
@ -1457,22 +1609,12 @@ TXDB.prototype.getRangeHashes = function getRangeHashes(account, options) {
|
|
|
|
|
account = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (account != null)
|
|
|
|
|
return this.getAccountRangeHashes(account, options);
|
|
|
|
|
|
|
|
|
|
start = options.start || 0;
|
|
|
|
|
end = options.end || 0xffffffff;
|
|
|
|
|
|
|
|
|
|
if (account != null) {
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.M(account, start, constants.NULL_HASH),
|
|
|
|
|
lte: layout.M(account, end, constants.HIGH_HASH),
|
|
|
|
|
limit: options.limit,
|
|
|
|
|
reverse: options.reverse,
|
|
|
|
|
parse: function(key) {
|
|
|
|
|
key = layout.Mm(key);
|
|
|
|
|
return key[2];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.keys({
|
|
|
|
|
gte: layout.m(start, constants.NULL_HASH),
|
|
|
|
|
lte: layout.m(end, constants.HIGH_HASH),
|
|
|
|
|
@ -1586,11 +1728,11 @@ TXDB.prototype.getAccountHistory = co(function* getAccountHistory(account) {
|
|
|
|
|
* @returns {Promise} - Returns {@link TX}[].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getUnconfirmed = co(function* getUnconfirmed(account) {
|
|
|
|
|
TXDB.prototype.getPending = co(function* getPending(account) {
|
|
|
|
|
var txs = [];
|
|
|
|
|
var i, hashes, hash, tx;
|
|
|
|
|
|
|
|
|
|
hashes = yield this.getUnconfirmedHashes(account);
|
|
|
|
|
hashes = yield this.getPendingHashes(account);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < hashes.length; i++) {
|
|
|
|
|
hash = hashes[i];
|
|
|
|
|
@ -1717,6 +1859,20 @@ TXDB.prototype.fillCoins = co(function* fillCoins(tx) {
|
|
|
|
|
return tx;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get TXDB state.
|
|
|
|
|
* @returns {Promise}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getState = co(function* getState() {
|
|
|
|
|
var data = yield this.get(layout.R);
|
|
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
return TXDBState.fromRaw(this.wallet.wid, this.wallet.id, data);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get transaction.
|
|
|
|
|
* @param {Hash} hash
|
|
|
|
|
@ -1894,19 +2050,23 @@ TXDB.prototype.hasCoin = function hasCoin(hash, index) {
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getBalance = co(function* getBalance(account) {
|
|
|
|
|
var self = this;
|
|
|
|
|
var balance;
|
|
|
|
|
|
|
|
|
|
// Slow case
|
|
|
|
|
if (account != null)
|
|
|
|
|
return yield this.getAccountBalance(account);
|
|
|
|
|
|
|
|
|
|
// Really fast case
|
|
|
|
|
if (this.balance)
|
|
|
|
|
return this.balance;
|
|
|
|
|
|
|
|
|
|
// Fast case
|
|
|
|
|
balance = new Balance(this.wallet);
|
|
|
|
|
return this.balance;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculate balance.
|
|
|
|
|
* @param {Number?} account
|
|
|
|
|
* @returns {Promise} - Returns {@link Balance}.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getWalletBalance = co(function* getWalletBalance(account) {
|
|
|
|
|
var self = this;
|
|
|
|
|
var balance = new Balance(this.wallet.wid, this.wallet.id, -1);
|
|
|
|
|
|
|
|
|
|
yield this.range({
|
|
|
|
|
gte: layout.c(constants.NULL_HASH, 0x00000000),
|
|
|
|
|
@ -1932,7 +2092,7 @@ TXDB.prototype.getBalance = co(function* getBalance(account) {
|
|
|
|
|
|
|
|
|
|
TXDB.prototype.getAccountBalance = co(function* getBalance(account) {
|
|
|
|
|
var prevout = yield this.getOutpoints(account);
|
|
|
|
|
var balance = new Balance(this.wallet);
|
|
|
|
|
var balance = new Balance(this.wallet.wid, this.wallet.id, account);
|
|
|
|
|
var i, ckey, key, coin, op, data;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < prevout.length; i++) {
|
|
|
|
|
@ -1988,7 +2148,7 @@ TXDB.prototype.zap = co(function* zap(account, age) {
|
|
|
|
|
|
|
|
|
|
assert(now - tx.ps >= age);
|
|
|
|
|
|
|
|
|
|
this.wallet.start();
|
|
|
|
|
this.start();
|
|
|
|
|
|
|
|
|
|
this.logger.debug('Zapping TX: %s (%s)',
|
|
|
|
|
hash, this.wallet.id);
|
|
|
|
|
@ -1996,13 +2156,13 @@ TXDB.prototype.zap = co(function* zap(account, age) {
|
|
|
|
|
try {
|
|
|
|
|
yield this._remove(hash);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
this.wallet.drop();
|
|
|
|
|
this.drop();
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hashes.push(hash);
|
|
|
|
|
|
|
|
|
|
yield this.wallet.commit();
|
|
|
|
|
yield this.commit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hashes;
|
|
|
|
|
@ -2025,17 +2185,33 @@ TXDB.prototype.abandon = co(function* abandon(hash) {
|
|
|
|
|
* Balance
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
function Balance(wallet) {
|
|
|
|
|
function Balance(wid, id, account) {
|
|
|
|
|
if (!(this instanceof Balance))
|
|
|
|
|
return new Balance(wallet);
|
|
|
|
|
return new Balance(wid, id, account);
|
|
|
|
|
|
|
|
|
|
this.wid = wallet.wid;
|
|
|
|
|
this.id = wallet.id;
|
|
|
|
|
this.wid = wid;
|
|
|
|
|
this.id = id;
|
|
|
|
|
this.account = account;
|
|
|
|
|
this.unconfirmed = 0;
|
|
|
|
|
this.confirmed = 0;
|
|
|
|
|
this.total = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Balance.prototype.clone = function clone() {
|
|
|
|
|
var balance = new Balance(this.wid, this.id, this.account);
|
|
|
|
|
balance.unconfirmed = this.unconfirmed;
|
|
|
|
|
balance.confirmed = this.confirmed;
|
|
|
|
|
balance.total = this.total;
|
|
|
|
|
return balance;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Balance.prototype.equal = function equal(balance) {
|
|
|
|
|
return this.wid === balance.wid
|
|
|
|
|
&& this.total === balance.total
|
|
|
|
|
&& this.confirmed === balance.confirmed
|
|
|
|
|
&& this.unconfirmed === balance.unconfirmed;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Balance.prototype.add = function add(coin) {
|
|
|
|
|
this.total += coin.value;
|
|
|
|
|
if (coin.height === -1)
|
|
|
|
|
@ -2076,10 +2252,36 @@ Balance.prototype.addRaw = function addRaw(data) {
|
|
|
|
|
this.confirmed += value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Balance.prototype.toRaw = function toRaw(writer) {
|
|
|
|
|
var p = new BufferWriter(writer);
|
|
|
|
|
|
|
|
|
|
p.writeU64(this.unconfirmed);
|
|
|
|
|
p.writeU64(this.confirmed);
|
|
|
|
|
|
|
|
|
|
if (!writer)
|
|
|
|
|
p = p.render();
|
|
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Balance.prototype.fromRaw = function fromRaw(data) {
|
|
|
|
|
var p = new BufferReader(data);
|
|
|
|
|
this.unconfirmed = p.readU53();
|
|
|
|
|
this.confirmed = p.readU53();
|
|
|
|
|
this.total += this.unconfirmed
|
|
|
|
|
this.total += this.confirmed;
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Balance.fromRaw = function fromRaw(wid, id, data) {
|
|
|
|
|
return new Balance(wid, id, -1).fromRaw(data);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Balance.prototype.toJSON = function toJSON() {
|
|
|
|
|
return {
|
|
|
|
|
wid: this.wid,
|
|
|
|
|
id: this.id,
|
|
|
|
|
account: this.account,
|
|
|
|
|
unconfirmed: utils.btc(this.unconfirmed),
|
|
|
|
|
confirmed: utils.btc(this.confirmed),
|
|
|
|
|
total: utils.btc(this.total)
|
|
|
|
|
@ -2094,6 +2296,85 @@ Balance.prototype.toString = function toString() {
|
|
|
|
|
+ '>';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Chain State
|
|
|
|
|
* @constructor
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
function TXDBState(wid, id) {
|
|
|
|
|
this.wid = wid;
|
|
|
|
|
this.id = id;
|
|
|
|
|
this.tx = 0;
|
|
|
|
|
this.coin = 0;
|
|
|
|
|
this.balance = new Balance(wid, id, -1);
|
|
|
|
|
this.committed = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TXDBState.prototype.clone = function clone() {
|
|
|
|
|
var state = new TXDBState();
|
|
|
|
|
state.wid = this.wid;
|
|
|
|
|
state.id = this.id;
|
|
|
|
|
state.tx = this.tx;
|
|
|
|
|
state.coin = this.coin;
|
|
|
|
|
state.balance = this.balance.clone();
|
|
|
|
|
return state;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TXDBState.prototype.commit = function commit() {
|
|
|
|
|
this.committed = true;
|
|
|
|
|
return this.toRaw();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TXDBState.prototype.toRaw = function toRaw() {
|
|
|
|
|
var p = new BufferWriter();
|
|
|
|
|
p.writeU64(this.tx);
|
|
|
|
|
p.writeU64(this.coin);
|
|
|
|
|
this.balance.toRaw(p);
|
|
|
|
|
return p.render();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TXDBState.prototype.fromRaw = function fromRaw(data) {
|
|
|
|
|
var p = new BufferReader(data);
|
|
|
|
|
this.tx = p.readU53();
|
|
|
|
|
this.coin = p.readU53();
|
|
|
|
|
this.balance.fromRaw(p);
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TXDBState.fromRaw = function fromRaw(wid, id, data) {
|
|
|
|
|
return new TXDBState(wid, id).fromRaw(data);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TXDBState.prototype.add = function add(coin) {
|
|
|
|
|
this.coin++;
|
|
|
|
|
return this.balance.add(coin);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TXDBState.prototype.sub = function sub(coin) {
|
|
|
|
|
this.coin--;
|
|
|
|
|
return this.balance.sub(coin);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TXDBState.prototype.confirm = function confirm(value) {
|
|
|
|
|
return this.balance.confirm(value);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TXDBState.prototype.unconfirm = function unconfirm(value) {
|
|
|
|
|
return this.balance.unconfirm(value);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TXDBState.prototype.toJSON = function toJSON() {
|
|
|
|
|
return {
|
|
|
|
|
wid: this.wid,
|
|
|
|
|
id: this.id,
|
|
|
|
|
tx: this.tx,
|
|
|
|
|
coin: this.coin,
|
|
|
|
|
unconfirmed: utils.btc(this.balance.unconfirmed),
|
|
|
|
|
confirmed: utils.btc(this.balance.confirmed),
|
|
|
|
|
total: utils.btc(this.balance.total)
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Helpers
|
|
|
|
|
*/
|
|
|
|
|
|