walletdb: start marking the start block.
This commit is contained in:
parent
025a5b9138
commit
8377a5082e
@ -1086,7 +1086,7 @@ Chain.prototype._replay = co(function* replay(block) {
|
||||
Chain.prototype.scan = co(function* scan(start, filter, iter) {
|
||||
var unlock = yield this.locker.lock();
|
||||
try {
|
||||
return yield this.db.scan(block, filter, iter);
|
||||
return yield this.db.scan(start, filter, iter);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ function ChainState() {
|
||||
this.startHeight = -1;
|
||||
this.startHash = constants.NULL_HASH;
|
||||
this.height = -1;
|
||||
this.marked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,6 +37,7 @@ ChainState.prototype.clone = function clone() {
|
||||
state.startHeight = this.startHeight;
|
||||
state.startHash = this.startHash;
|
||||
state.height = this.height;
|
||||
state.marked = this.marked;
|
||||
return state;
|
||||
};
|
||||
|
||||
@ -47,9 +49,15 @@ ChainState.prototype.clone = function clone() {
|
||||
|
||||
ChainState.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = new BufferReader(data);
|
||||
|
||||
this.startHeight = p.readU32();
|
||||
this.startHash = p.readHash('hex');
|
||||
this.height = p.readU32();
|
||||
this.marked = true;
|
||||
|
||||
if (p.left() > 0)
|
||||
this.marked = p.readU8() === 1;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@ -75,6 +83,7 @@ ChainState.prototype.toRaw = function toRaw(writer) {
|
||||
p.writeU32(this.startHeight);
|
||||
p.writeHash(this.startHash);
|
||||
p.writeU32(this.height);
|
||||
p.writeU8(this.marked ? 1 : 0);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
@ -504,6 +504,7 @@ TXDB.prototype.resolve = co(function* resolve(tx, block) {
|
||||
*/
|
||||
|
||||
TXDB.prototype.verifyInputs = co(function* verifyInputs(tx, block) {
|
||||
var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
|
||||
var hash = tx.hash('hex');
|
||||
var hasOrphans = false;
|
||||
var orphans = [];
|
||||
@ -527,7 +528,7 @@ TXDB.prototype.verifyInputs = co(function* verifyInputs(tx, block) {
|
||||
if (coin) {
|
||||
if (this.options.verify && tx.height === -1) {
|
||||
input.coin = coin;
|
||||
if (!(yield tx.verifyInputAsync(i)))
|
||||
if (!(yield tx.verifyInputAsync(i, flags)))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -547,7 +548,7 @@ TXDB.prototype.verifyInputs = co(function* verifyInputs(tx, block) {
|
||||
if (coin) {
|
||||
if (this.options.verify && tx.height === -1) {
|
||||
input.coin = coin;
|
||||
if (!(yield tx.verifyInputAsync(i)))
|
||||
if (!(yield tx.verifyInputAsync(i, flags)))
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
@ -618,6 +619,7 @@ TXDB.prototype.verifyInputs = co(function* verifyInputs(tx, block) {
|
||||
*/
|
||||
|
||||
TXDB.prototype.resolveOutputs = co(function* resolveOutputs(tx, block, resolved) {
|
||||
var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
|
||||
var hash = tx.hash('hex');
|
||||
var i, j, input, output, key;
|
||||
var orphans, orphan, coin, valid;
|
||||
@ -661,7 +663,7 @@ TXDB.prototype.resolveOutputs = co(function* resolveOutputs(tx, block, resolved)
|
||||
// We can finally verify this input.
|
||||
if (this.options.verify && orphan.tx.height === -1) {
|
||||
input.coin = coin;
|
||||
valid = yield orphan.tx.verifyInputAsync(orphan.index);
|
||||
valid = yield orphan.tx.verifyInputAsync(orphan.index, flags);
|
||||
}
|
||||
|
||||
// If it's valid and fully resolved,
|
||||
|
||||
@ -1541,7 +1541,7 @@ WalletDB.prototype.init = co(function* init() {
|
||||
'Initializing WalletDB chain state at %s (%d).',
|
||||
utils.revHex(tip.hash), tip.height);
|
||||
|
||||
yield this.resetState(tip);
|
||||
yield this.resetState(tip, false);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -1564,7 +1564,7 @@ WalletDB.prototype.getState = co(function* getState() {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
WalletDB.prototype.resetState = co(function* resetState(tip) {
|
||||
WalletDB.prototype.resetState = co(function* resetState(tip, marked) {
|
||||
var batch = this.db.batch();
|
||||
var state = this.state.clone();
|
||||
var iter, item;
|
||||
@ -1592,6 +1592,7 @@ WalletDB.prototype.resetState = co(function* resetState(tip) {
|
||||
state.startHeight = tip.height;
|
||||
state.startHash = tip.hash;
|
||||
state.height = tip.height;
|
||||
state.marked = marked;
|
||||
|
||||
batch.put(layout.h(tip.height), tip.toHash());
|
||||
batch.put(layout.R, state.toRaw());
|
||||
@ -1646,6 +1647,22 @@ WalletDB.prototype.syncState = co(function* syncState(tip) {
|
||||
this.state = state;
|
||||
});
|
||||
|
||||
/**
|
||||
* Mark the start block once a confirmed tx is seen.
|
||||
* @param {BlockMeta} tip
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
WalletDB.prototype.maybeMark = co(function* maybeMark(tip) {
|
||||
if (this.state.marked)
|
||||
return;
|
||||
|
||||
this.logger.info('Marking WalletDB start block at %s (%d).',
|
||||
utils.revHex(tip.hash), tip.height);
|
||||
|
||||
yield this.resetState(tip, true);
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a block->wallet map.
|
||||
* @param {Number} height
|
||||
@ -1770,14 +1787,14 @@ WalletDB.prototype.getTip = co(function* getTip() {
|
||||
*/
|
||||
|
||||
WalletDB.prototype.rollback = co(function* rollback(height) {
|
||||
var tip;
|
||||
var tip, marked;
|
||||
|
||||
if (height > this.state.height)
|
||||
throw new Error('WDB: Cannot rollback to the future.');
|
||||
|
||||
if (height === this.state.height) {
|
||||
this.logger.debug('Rolled back to same height (%d).', height);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
this.logger.info(
|
||||
@ -1789,7 +1806,7 @@ WalletDB.prototype.rollback = co(function* rollback(height) {
|
||||
if (tip) {
|
||||
yield this.revert(tip.height);
|
||||
yield this.syncState(tip);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
tip = new BlockMeta();
|
||||
@ -1797,6 +1814,7 @@ WalletDB.prototype.rollback = co(function* rollback(height) {
|
||||
if (height >= this.state.startHeight) {
|
||||
tip.height = this.state.startHeight;
|
||||
tip.hash = this.state.startHash;
|
||||
marked = this.state.marked;
|
||||
|
||||
this.logger.warning(
|
||||
'Rolling back WalletDB to start block (%d).',
|
||||
@ -1804,12 +1822,15 @@ WalletDB.prototype.rollback = co(function* rollback(height) {
|
||||
} else {
|
||||
tip.height = 0;
|
||||
tip.hash = this.network.genesis.hash;
|
||||
marked = false;
|
||||
|
||||
this.logger.warning('Rolling back WalletDB to genesis block.');
|
||||
}
|
||||
|
||||
yield this.revert(tip.height);
|
||||
yield this.resetState(tip);
|
||||
yield this.resetState(tip, marked);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
/**
|
||||
@ -1899,6 +1920,7 @@ WalletDB.prototype._addBlock = co(function* addBlock(entry, txs) {
|
||||
throw new Error('WDB: Bad connection (height mismatch).');
|
||||
}
|
||||
|
||||
// Sync the state to the new tip.
|
||||
yield this.syncState(tip);
|
||||
|
||||
if (this.options.useCheckpoints) {
|
||||
@ -1962,6 +1984,7 @@ WalletDB.prototype._removeBlock = co(function* removeBlock(entry) {
|
||||
if (!prev)
|
||||
throw new Error('WDB: Bad disconnection (no previous block).');
|
||||
|
||||
// Get the map of txids->wids.
|
||||
block = yield this.getBlockMap(tip.height);
|
||||
|
||||
if (!block) {
|
||||
@ -1974,6 +1997,7 @@ WalletDB.prototype._removeBlock = co(function* removeBlock(entry) {
|
||||
yield this._unconfirm(tx);
|
||||
}
|
||||
|
||||
// Sync the state to the previous tip.
|
||||
yield this.syncState(prev);
|
||||
|
||||
this.logger.warning('Disconnected wallet block %s (tx=%d).',
|
||||
@ -2036,6 +2060,13 @@ WalletDB.prototype._insert = co(function* insert(tx, block) {
|
||||
'Incoming transaction for %d wallets in WalletDB (%s).',
|
||||
wids.length, tx.rhash);
|
||||
|
||||
// If this is our first transaction
|
||||
// in a block, set the start block here.
|
||||
if (block)
|
||||
yield this.maybeMark(block);
|
||||
|
||||
// Insert the transaction
|
||||
// into every matching wallet.
|
||||
for (i = 0; i < wids.length; i++) {
|
||||
wid = wids[i];
|
||||
wallet = yield this.get(wid);
|
||||
@ -2101,7 +2132,13 @@ WalletDB.prototype._resetChain = co(function* resetChain(entry) {
|
||||
if (entry.height > this.state.height)
|
||||
throw new Error('WDB: Bad reset height.');
|
||||
|
||||
yield this.scan(entry.height);
|
||||
// Try to rollback.
|
||||
if (yield this.rollback(entry.height))
|
||||
return;
|
||||
|
||||
// If we rolled back to the
|
||||
// start block, we need a rescan.
|
||||
yield this.scan();
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
@ -85,6 +85,7 @@ describe('Chain', function() {
|
||||
it('should mine a block', cob(function* () {
|
||||
var block = yield miner.mineBlock();
|
||||
assert(block);
|
||||
yield chain.add(block);
|
||||
}));
|
||||
|
||||
it('should mine competing chains', cob(function* () {
|
||||
@ -121,15 +122,15 @@ describe('Chain', function() {
|
||||
yield co.timeout(100);
|
||||
|
||||
balance = yield wallet.getBalance();
|
||||
assert.equal(balance.unconfirmed, 500 * 1e8);
|
||||
assert.equal(balance.confirmed, 500 * 1e8);
|
||||
assert.equal(balance.unconfirmed, 550 * 1e8);
|
||||
assert.equal(balance.confirmed, 550 * 1e8);
|
||||
}));
|
||||
|
||||
it('should handle a reorg', cob(function* () {
|
||||
var entry, block, forked;
|
||||
|
||||
assert.equal(walletdb.state.height, chain.height);
|
||||
assert.equal(chain.height, 10);
|
||||
assert.equal(chain.height, 11);
|
||||
|
||||
entry = yield chain.db.get(tip2.hash);
|
||||
assert(entry);
|
||||
@ -158,8 +159,8 @@ describe('Chain', function() {
|
||||
yield co.timeout(100);
|
||||
|
||||
balance = yield wallet.getBalance();
|
||||
assert.equal(balance.unconfirmed, 1050 * 1e8);
|
||||
assert.equal(balance.confirmed, 550 * 1e8);
|
||||
assert.equal(balance.unconfirmed, 1100 * 1e8);
|
||||
assert.equal(balance.confirmed, 600 * 1e8);
|
||||
}));
|
||||
|
||||
it('should check main chain', cob(function* () {
|
||||
@ -221,8 +222,8 @@ describe('Chain', function() {
|
||||
yield co.timeout(100);
|
||||
|
||||
balance = yield wallet.getBalance();
|
||||
assert.equal(balance.unconfirmed, 1200 * 1e8);
|
||||
assert.equal(balance.confirmed, 700 * 1e8);
|
||||
assert.equal(balance.unconfirmed, 1250 * 1e8);
|
||||
assert.equal(balance.confirmed, 750 * 1e8);
|
||||
|
||||
assert(wallet.account.receiveDepth >= 8);
|
||||
assert(wallet.account.changeDepth >= 7);
|
||||
@ -230,7 +231,7 @@ describe('Chain', function() {
|
||||
assert.equal(walletdb.state.height, chain.height);
|
||||
|
||||
txs = yield wallet.getHistory();
|
||||
assert.equal(txs.length, 44);
|
||||
assert.equal(txs.length, 45);
|
||||
}));
|
||||
|
||||
it('should get tips and remove chains', cob(function* () {
|
||||
@ -255,7 +256,7 @@ describe('Chain', function() {
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
assert.equal(total, 25);
|
||||
assert.equal(total, 26);
|
||||
}));
|
||||
|
||||
it('should activate csv', cob(function* () {
|
||||
@ -265,7 +266,7 @@ describe('Chain', function() {
|
||||
state = yield chain.getState(prev, 'csv');
|
||||
assert(state === 0);
|
||||
|
||||
for (i = 0; i < 418; i++) {
|
||||
for (i = 0; i < 417; i++) {
|
||||
block = yield miner.mineBlock();
|
||||
yield chain.add(block);
|
||||
switch (chain.height) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user