txdb: add block entries.

This commit is contained in:
Christopher Jeffrey 2016-11-04 12:04:55 -07:00
parent 704d9e1783
commit 86e1e35f9a
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
7 changed files with 151 additions and 40 deletions

View File

@ -320,6 +320,12 @@ CLI.prototype.getDetails = co(function* getDetails() {
this.log(details);
});
CLI.prototype.getWalletBlock = co(function* getWalletBlock() {
var height = this.argv[0] | 0;
var details = yield this.wallet.getBlock(height);
this.log(details);
});
CLI.prototype.retoken = co(function* retoken() {
var result = yield this.wallet.retoken();
this.log(result);
@ -480,6 +486,8 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
return yield this.zapWallet();
case 'tx':
return yield this.getDetails();
case 'block':
return yield this.getWalletBlock();
case 'view':
return yield this.viewTX();
case 'import':
@ -518,6 +526,7 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
this.log(' $ sign [tx-hex]: Sign transaction.');
this.log(' $ zap [age?]: Zap pending wallet TXs.');
this.log(' $ tx [hash]: View transaction details.');
this.log(' $ block [height]: View wallet block.');
this.log(' $ view [tx-hex]: Parse and view transaction.');
this.log(' $ import [wif|hex]: Import private or public key.');
this.log(' $ watch [address]: Import an address.');

View File

@ -433,7 +433,7 @@ HTTPClient.prototype.none = function none() {
* Request the raw wallet JSON (will create wallet if it does not exist).
* @private
* @param {Object} options - See {@link Wallet}.
* @returns {Promise} - Returns Object.
* @returns {Promise}
*/
HTTPClient.prototype.createWallet = function createWallet(options) {
@ -444,7 +444,7 @@ HTTPClient.prototype.createWallet = function createWallet(options) {
* Get the raw wallet JSON.
* @private
* @param {WalletID} id
* @returns {Promise} - Returns Object.
* @returns {Promise}
*/
HTTPClient.prototype.getWallet = function getWallet(id) {
@ -454,7 +454,7 @@ HTTPClient.prototype.getWallet = function getWallet(id) {
/**
* Get wallet transaction history.
* @param {WalletID} id
* @returns {Promise} - Returns {@link TX}[].
* @returns {Promise}
*/
HTTPClient.prototype.getHistory = function getHistory(id, account) {
@ -465,7 +465,7 @@ HTTPClient.prototype.getHistory = function getHistory(id, account) {
/**
* Get wallet coins.
* @param {WalletID} id
* @returns {Promise} - Returns {@link Coin}[].
* @returns {Promise}
*/
HTTPClient.prototype.getCoins = function getCoins(id, account) {
@ -476,7 +476,7 @@ HTTPClient.prototype.getCoins = function getCoins(id, account) {
/**
* Get all unconfirmed transactions.
* @param {WalletID} id
* @returns {Promise} - Returns {@link TX}[].
* @returns {Promise}
*/
HTTPClient.prototype.getPending = function getPending(id, account) {
@ -487,7 +487,7 @@ HTTPClient.prototype.getPending = function getPending(id, account) {
/**
* Calculate wallet balance.
* @param {WalletID} id
* @returns {Promise} - Returns {@link Balance}.
* @returns {Promise}
*/
HTTPClient.prototype.getBalance = function getBalance(id, account) {
@ -499,7 +499,7 @@ HTTPClient.prototype.getBalance = function getBalance(id, account) {
* Get last N wallet transactions.
* @param {WalletID} id
* @param {Number} limit - Max number of transactions.
* @returns {Promise} - Returns {@link TX}[].
* @returns {Promise}
*/
HTTPClient.prototype.getLast = function getLast(id, account, limit) {
@ -515,7 +515,7 @@ HTTPClient.prototype.getLast = function getLast(id, account, limit) {
* @param {Number} options.end - End time.
* @param {Number?} options.limit - Max number of records.
* @param {Boolean?} options.reverse - Reverse order.
* @returns {Promise} - Returns {@link TX}[].
* @returns {Promise}
*/
HTTPClient.prototype.getRange = function getRange(id, account, options) {
@ -534,20 +534,31 @@ HTTPClient.prototype.getRange = function getRange(id, account, options) {
* is available in the wallet history).
* @param {WalletID} id
* @param {Hash} hash
* @returns {Promise} - Returns {@link TX}[].
* @returns {Promise}
*/
HTTPClient.prototype.getWalletTX = function getWalletTX(id, hash) {
return this._get('/wallet/' + id + '/tx/' + hash);
};
/**
* Get wallet block.
* @param {WalletID} id
* @param {Number} height
* @returns {Promise}
*/
HTTPClient.prototype.getWalletBlock = function getWalletBlock(id, height) {
return this._get('/wallet/' + id + '/block/' + height);
};
/**
* Get unspent coin (only possible if the transaction
* is available in the wallet history).
* @param {WalletID} id
* @param {Hash} hash
* @param {Number} index
* @returns {Promise} - Returns {@link Coin}[].
* @returns {Promise}
*/
HTTPClient.prototype.getWalletCoin = function getWalletCoin(id, account, hash, index) {
@ -562,7 +573,7 @@ HTTPClient.prototype.getWalletCoin = function getWalletCoin(id, account, hash, i
* @param {Object} options
* @param {Base58Address} options.address
* @param {Amount} options.value
* @returns {Promise} - Returns {@link TX}.
* @returns {Promise}
*/
HTTPClient.prototype.send = function send(id, options) {
@ -611,7 +622,7 @@ HTTPClient.prototype.setPassphrase = function setPassphrase(id, old, new_) {
* Create a transaction, fill.
* @param {WalletID} id
* @param {Object} options
* @returns {Promise} - Returns {@link TX}.
* @returns {Promise}
*/
HTTPClient.prototype.createTX = function createTX(id, options) {
@ -636,7 +647,7 @@ HTTPClient.prototype.createTX = function createTX(id, options) {
* @param {WalletID} id
* @param {TX} tx
* @param {Object} options
* @returns {Promise} - Returns {@link TX}.
* @returns {Promise}
*/
HTTPClient.prototype.sign = function sign(id, tx, options) {
@ -654,7 +665,7 @@ HTTPClient.prototype.sign = function sign(id, tx, options) {
/**
* Fill a transaction with coins.
* @param {TX} tx
* @returns {Promise} - Returns {@link TX}.
* @returns {Promise}
*/
HTTPClient.prototype.fillCoins = function fillCoins(id, tx) {
@ -895,7 +906,7 @@ HTTPClient.prototype.createAccount = function createAccount(id, options) {
* Create address.
* @param {WalletID} id
* @param {Object} options
* @returns {Promise} - Returns Array.
* @returns {Promise}
*/
HTTPClient.prototype.createAddress = function createAddress(id, options) {
@ -916,7 +927,7 @@ HTTPClient.prototype.createAddress = function createAddress(id, options) {
* Create address.
* @param {WalletID} id
* @param {Object} options
* @returns {Promise} - Returns Array.
* @returns {Promise}
*/
HTTPClient.prototype.createNested = function createNested(id, options) {

View File

@ -917,6 +917,21 @@ HTTPServer.prototype._init = function _init() {
send(200, { success: true });
}));
// Get Block Record
this.get('/wallet/:id/block/:height', con(function* (req, res, send, next) {
var height = req.options.height;
var block;
enforce(height != null, 'Height is required.');
block = yield req.wallet.getBlock(height);
if (!block)
return send(404);
send(200, block.toJSON());
}));
// Add key
this.put('/wallet/:id/shared-key', con(function* (req, res, send, next) {
var options = req.options;

View File

@ -198,6 +198,14 @@ HTTPWallet.prototype.getTX = function getTX(hash) {
return this.client.getWalletTX(this.id, hash);
};
/**
* @see Wallet#getBlock
*/
HTTPWallet.prototype.getBlock = function getBlock(height) {
return this.client.getWalletBlock(this.id, height);
};
/**
* @see Wallet#getCoin
*/

View File

@ -981,37 +981,38 @@ TXDB.prototype.removeBlockMap = co(function* removeBlockMap(tx, height) {
*/
TXDB.prototype.getBlock = co(function* getBlock(height) {
var data = yield this.db.get(layout.b(height));
var data = yield this.get(layout.b(height));
if (!data)
return;
return BlockRecord.fromRaw(data);
});
/**
* Append to the global block record.
* @param {TX} tx
* @param {Number} height
* @param {BlockMeta} entry
* @returns {Promise}
*/
TXDB.prototype.addBlock = co(function* addBlock(tx, entry) {
var hash = tx.hash('hex');
var block = yield this.getBlock(entry.height);
var height = tx.height;
var block = yield this.getBlock(height);
if (!block)
block = new BlockRecord(entry.hash, entry.height, entry.ts);
block = new BlockRecord(tx.block, tx.height, tx.ts);
if (block.hashes.indexOf(hash) !== -1)
if (!block.add(hash))
return;
block.hashes.push(hash);
this.put(layout.b(entry.height), block.toRaw());
this.put(layout.b(height), block.toRaw());
});
/**
* Remove from the global block record.
* @param {TX}
* @param {TX} tx
* @param {Number} height
* @returns {Promise}
*/
@ -1019,18 +1020,13 @@ TXDB.prototype.addBlock = co(function* addBlock(tx, entry) {
TXDB.prototype.removeBlock = co(function* removeBlock(tx, height) {
var hash = tx.hash('hex');
var block = yield this.getBlock(height);
var index;
if (!block)
return;
index = block.hashes.indexOf(hash);
if (index === -1)
if (!block.remove(hash))
return;
block.hashes.splice(index, 1);
if (block.hashes.length === 0) {
this.del(layout.b(height));
return;
@ -1043,6 +1039,7 @@ TXDB.prototype.removeBlock = co(function* removeBlock(tx, height) {
* Add transaction, potentially runs
* `confirm()` and `removeConflicts()`.
* @param {TX} tx
* @param {BlockMeta} block
* @returns {Promise}
*/
@ -1127,6 +1124,7 @@ TXDB.prototype._add = co(function* add(tx, block) {
* Insert transaction.
* @private
* @param {TX} tx
* @param {BlockMeta} block
* @returns {Promise}
*/
@ -1267,8 +1265,10 @@ TXDB.prototype.insert = co(function* insert(tx, block) {
this.put(layout.H(account, tx.height, hash), DUMMY);
}
if (tx.height !== -1)
if (tx.height !== -1) {
yield this.addBlockMap(tx, tx.height);
yield this.addBlock(tx, block);
}
// Update the transaction counter and
// commit the new state. This state will
@ -1296,6 +1296,7 @@ TXDB.prototype.insert = co(function* insert(tx, block) {
* Attempt to confirm a transaction.
* @private
* @param {TX} tx
* @param {BlockMeta} block
* @returns {Promise}
*/
@ -1333,6 +1334,7 @@ TXDB.prototype.confirm = co(function* confirm(hash, block) {
* Attempt to confirm a transaction.
* @private
* @param {TX} tx
* @param {BlockMeta} block
* @returns {Promise}
*/
@ -1437,8 +1439,10 @@ TXDB.prototype._confirm = co(function* confirm(tx, block) {
this.put(layout.H(account, tx.height, hash), DUMMY);
}
if (tx.height !== -1)
if (tx.height !== -1) {
yield this.addBlockMap(tx, tx.height);
yield this.addBlock(tx, block);
}
// Commit the new state. The balance has updated.
this.put(layout.R, this.pending.commit());
@ -1567,8 +1571,10 @@ TXDB.prototype.erase = co(function* erase(tx) {
this.del(layout.H(account, tx.height, hash));
}
if (tx.height !== -1)
if (tx.height !== -1) {
yield this.removeBlockMap(tx, tx.height);
yield this.removeBlock(tx, tx.height);
}
// Update the transaction counter
// and commit new state due to
@ -1740,6 +1746,7 @@ TXDB.prototype.disconnect = co(function* disconnect(tx) {
}
yield this.removeBlockMap(tx, height);
yield this.removeBlock(tx, height);
// We need to update the now-removed
// block properties and reindex due
@ -3359,8 +3366,54 @@ function BlockRecord(hash, height, ts) {
this.height = height != null ? height : -1;
this.ts = ts || 0;
this.hashes = [];
this.index = {};
}
/**
* Add transaction to block record.
* @param {Hash} hash
* @returns {Boolean}
*/
BlockRecord.prototype.add = function add(hash) {
if (this.index[hash])
return false;
this.index[hash] = true;
this.hashes.push(hash);
return true;
};
/**
* Remove transaction from block record.
* @param {Hash} hash
* @returns {Boolean}
*/
BlockRecord.prototype.remove = function remove(hash) {
var index;
if (!this.index[hash])
return false;
delete this.index[hash];
// Fast case
if (this.hashes[this.hashes.length - 1] === hash) {
this.hashes.pop();
return true;
}
index = this.hashes.indexOf(hash);
assert(index !== -1);
this.hashes.splice(index, 1);
return true;
};
/**
* Instantiate wallet block from serialized tip data.
* @private
@ -3369,12 +3422,17 @@ function BlockRecord(hash, height, ts) {
BlockRecord.prototype.fromRaw = function fromRaw(data) {
var p = new BufferReader(data);
var hash;
this.hash = p.readHash('hex');
this.height = p.readU32();
this.ts = p.readU32();
while (p.left())
this.hashes.push(p.readHash('hex'));
while (p.left()) {
hash = p.readHash('hex');
this.index[hash] = true;
this.hashes.push(hash);
}
return this;
};

View File

@ -1984,6 +1984,16 @@ Wallet.prototype.getTX = function getTX(hash) {
return this.txdb.getTX(hash);
};
/**
* Get a block from the wallet.
* @param {Number} height
* @returns {Promise} - Returns {@link BlockRecord}.
*/
Wallet.prototype.getBlock = function getBlock(height) {
return this.txdb.getBlock(height);
};
/**
* Add a transaction to the wallets TX history.
* @param {TX} tx

View File

@ -476,7 +476,7 @@ WalletDB.prototype.wipe = co(function* wipe() {
this.logger.warning('Wiping WalletDB TXDB...');
this.logger.warning('I hope you know what you\'re doing.');
iter = db.iterator({
iter = this.db.iterator({
gte: new Buffer([0x00]),
lte: new Buffer([0xff])
});
@ -2002,15 +2002,15 @@ WalletDB.prototype.addTX = co(function* addTX(tx) {
block = yield this.getBlock(tx.height);
if (!block)
throw new Error('WDB: Inserting confirmed transaction.');
throw new Error('WDB: Cannot insert tx from unknown chain.');
if (tx.block !== block.hash)
throw new Error('WDB: Inserting confirmed transaction.');
throw new Error('WDB: Cannot insert tx from alternate chain.');
this.logger.warning('WalletDB is inserting confirmed transaction.');
}
return yield this._insert(tx);
return yield this._insert(tx, block);
} finally {
unlock();
}