txdb: new orphan resolution.
This commit is contained in:
parent
321f4f6df6
commit
557c1044cc
@ -514,7 +514,9 @@ TXDB.prototype.verifyInputs = co(function* verifyInputs(tx) {
|
||||
|
||||
if (spent) {
|
||||
coin = yield this.getSpentCoin(spent, prevout);
|
||||
assert(coin);
|
||||
|
||||
if (!coin)
|
||||
continue;
|
||||
|
||||
if (this.options.verify && tx.height === -1) {
|
||||
input.coin = coin;
|
||||
@ -681,6 +683,66 @@ TXDB.prototype.unspendCredit = function unspendCredit(tx, i) {
|
||||
this.del(layout.d(spender.hash, spender.index));
|
||||
};
|
||||
|
||||
/**
|
||||
* Write input record.
|
||||
* @param {TX} tx
|
||||
* @param {Number} i
|
||||
*/
|
||||
|
||||
TXDB.prototype.writeInput = function writeInput(tx, i) {
|
||||
var prevout = tx.inputs[i].prevout;
|
||||
var spender = Outpoint.fromTX(tx, i);
|
||||
this.put(layout.s(prevout.hash, prevout.index), spender.toRaw());
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove input record.
|
||||
* @param {TX} tx
|
||||
* @param {Number} i
|
||||
*/
|
||||
|
||||
TXDB.prototype.removeInput = function removeInput(tx, i) {
|
||||
var prevout = tx.inputs[i].prevout;
|
||||
this.del(layout.s(prevout.hash, prevout.index));
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve orphan input.
|
||||
* @param {TX} tx
|
||||
* @param {Number} i
|
||||
* @param {Path} path
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
TXDB.prototype.resolveInput = co(function* resolveInput(tx, i, path) {
|
||||
var hash = tx.hash('hex');
|
||||
var spent = yield this.getSpent(hash, i);
|
||||
var stx, credit;
|
||||
|
||||
if (!spent)
|
||||
return false;
|
||||
|
||||
if (yield this.hasSpentCoin(spent))
|
||||
return false;
|
||||
|
||||
stx = yield this.getTX(spent.hash);
|
||||
assert(stx);
|
||||
|
||||
credit = Credit.fromTX(tx, i);
|
||||
|
||||
this.spendCredit(credit, stx, spent.index);
|
||||
|
||||
if (stx.height === -1) {
|
||||
credit.spent = true;
|
||||
this.saveCredit(credit, path);
|
||||
this.pending.coin++;
|
||||
if (tx.height !== -1)
|
||||
this.pending.confirmed += credit.coin.value;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
/**
|
||||
* Test an entire transaction to see
|
||||
* if any of its outpoints are a double-spend.
|
||||
@ -847,8 +909,10 @@ TXDB.prototype._insert = co(function* insert(tx) {
|
||||
prevout = input.prevout;
|
||||
credit = yield this.getCredit(prevout.hash, prevout.index);
|
||||
|
||||
if (!credit)
|
||||
if (!credit) {
|
||||
this.writeInput(tx, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
coin = credit.coin;
|
||||
path = yield this.getPath(coin);
|
||||
@ -880,10 +944,12 @@ TXDB.prototype._insert = co(function* insert(tx) {
|
||||
|
||||
details.setOutput(i, path);
|
||||
|
||||
if (yield this.resolveInput(tx, i, path))
|
||||
continue;
|
||||
|
||||
credit = Credit.fromTX(tx, i);
|
||||
|
||||
this.pending.coin++;
|
||||
|
||||
this.pending.unconfirmed += output.value;
|
||||
|
||||
if (tx.height !== -1)
|
||||
@ -893,25 +959,23 @@ TXDB.prototype._insert = co(function* insert(tx) {
|
||||
}
|
||||
|
||||
this.put(layout.t(hash), tx.toExtended());
|
||||
this.put(layout.m(tx.ps, hash), DUMMY);
|
||||
|
||||
if (tx.height === -1)
|
||||
this.put(layout.p(hash), DUMMY);
|
||||
else
|
||||
this.put(layout.h(tx.height, hash), DUMMY);
|
||||
|
||||
this.put(layout.m(tx.ps, hash), DUMMY);
|
||||
|
||||
for (i = 0; i < details.accounts.length; i++) {
|
||||
account = details.accounts[i];
|
||||
|
||||
this.put(layout.T(account, hash), DUMMY);
|
||||
this.put(layout.M(account, tx.ps, hash), DUMMY);
|
||||
|
||||
if (tx.height === -1)
|
||||
this.put(layout.P(account, hash), DUMMY);
|
||||
else
|
||||
this.put(layout.H(account, tx.height, hash), DUMMY);
|
||||
|
||||
this.put(layout.M(account, tx.ps, hash), DUMMY);
|
||||
}
|
||||
|
||||
this.pending.tx++;
|
||||
@ -990,6 +1054,9 @@ TXDB.prototype.confirm = co(function* confirm(tx) {
|
||||
|
||||
details.setOutput(i, path);
|
||||
|
||||
if (yield this.resolveInput(tx, i, path))
|
||||
continue;
|
||||
|
||||
credit = yield this.getCredit(hash, i);
|
||||
assert(credit);
|
||||
|
||||
@ -1105,8 +1172,10 @@ TXDB.prototype._remove = co(function* remove(tx) {
|
||||
input = tx.inputs[i];
|
||||
credit = credits[i];
|
||||
|
||||
if (!credit)
|
||||
if (!credit) {
|
||||
this.removeInput(tx, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
coin = credit.coin;
|
||||
path = yield this.getPath(coin);
|
||||
@ -1147,25 +1216,23 @@ TXDB.prototype._remove = co(function* remove(tx) {
|
||||
}
|
||||
|
||||
this.del(layout.t(hash));
|
||||
this.del(layout.m(tx.ps, hash));
|
||||
|
||||
if (tx.height === -1)
|
||||
this.del(layout.p(hash));
|
||||
else
|
||||
this.del(layout.h(tx.height, hash));
|
||||
|
||||
this.del(layout.m(tx.ps, hash));
|
||||
|
||||
for (i = 0; i < details.accounts.length; i++) {
|
||||
account = details.accounts[i];
|
||||
|
||||
this.del(layout.T(account, hash));
|
||||
this.del(layout.M(account, tx.ps, hash));
|
||||
|
||||
if (tx.height === -1)
|
||||
this.del(layout.P(account, hash));
|
||||
else
|
||||
this.del(layout.H(account, tx.height, hash));
|
||||
|
||||
this.del(layout.M(account, tx.ps, hash));
|
||||
}
|
||||
|
||||
this.pending.tx--;
|
||||
@ -2216,6 +2283,16 @@ TXDB.prototype.getSpentCoin = co(function* getSpentCoin(spent, prevout) {
|
||||
return coin;
|
||||
});
|
||||
|
||||
/**
|
||||
* Test whether the database has a spent coin.
|
||||
* @param {Outpoint} spent
|
||||
* @returns {Promise} - Returns {@link Coin}.
|
||||
*/
|
||||
|
||||
TXDB.prototype.hasSpentCoin = function hasSpentCoin(spent) {
|
||||
return this.has(layout.d(spent.hash, spent.index));
|
||||
};
|
||||
|
||||
/**
|
||||
* Update spent coin height in storage.
|
||||
* @param {TX} tx - Sending transaction.
|
||||
|
||||
@ -17,24 +17,27 @@ var KEY1 = 'xprv9s21ZrQH143K3Aj6xQBymM31Zb4BVc7wxqfUhMZrzewdDVCt'
|
||||
var KEY2 = 'xprv9s21ZrQH143K3mqiSThzPtWAabQ22Pjp3uSNnZ53A5bQ4udp'
|
||||
+ 'faKekc2m4AChLYH1XDzANhrSdxHYWUeTWjYJwFwWFyHkTMnMeAcW4JyRCZa';
|
||||
|
||||
var dummyInput = {
|
||||
prevout: {
|
||||
hash: constants.NULL_HASH,
|
||||
index: 0
|
||||
},
|
||||
coin: {
|
||||
version: 1,
|
||||
height: 0,
|
||||
value: constants.MAX_MONEY,
|
||||
script: new bcoin.script([]),
|
||||
coinbase: false,
|
||||
hash: constants.NULL_HASH,
|
||||
index: 0
|
||||
},
|
||||
script: new bcoin.script([]),
|
||||
witness: new bcoin.witness([]),
|
||||
sequence: 0xffffffff
|
||||
};
|
||||
function dummy() {
|
||||
var hash = crypto.randomBytes(32).toString('hex');
|
||||
return {
|
||||
prevout: {
|
||||
hash: hash,
|
||||
index: 0
|
||||
},
|
||||
coin: {
|
||||
version: 1,
|
||||
height: 0,
|
||||
value: constants.MAX_MONEY,
|
||||
script: new bcoin.script(),
|
||||
coinbase: false,
|
||||
hash: hash,
|
||||
index: 0
|
||||
},
|
||||
script: new bcoin.script(),
|
||||
witness: new bcoin.witness(),
|
||||
sequence: 0xffffffff
|
||||
};
|
||||
}
|
||||
|
||||
describe('Wallet', function() {
|
||||
var walletdb, wallet, ewallet, ekey, doubleSpendWallet, doubleSpend;
|
||||
@ -110,7 +113,7 @@ describe('Wallet', function() {
|
||||
}]
|
||||
});
|
||||
|
||||
src.addInput(dummyInput);
|
||||
src.addInput(dummy());
|
||||
|
||||
tx = bcoin.mtx()
|
||||
.addInput(src, 0)
|
||||
@ -162,7 +165,7 @@ describe('Wallet', function() {
|
||||
}]
|
||||
});
|
||||
|
||||
src.addInput(dummyInput);
|
||||
src.addInput(dummy());
|
||||
|
||||
tx = bcoin.mtx()
|
||||
.addInput(src, 0)
|
||||
@ -187,7 +190,7 @@ describe('Wallet', function() {
|
||||
t1 = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000)
|
||||
.addOutput(w.getAddress(), 1000);
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1.ts = utils.now();
|
||||
t1.height = 1;
|
||||
|
||||
@ -347,7 +350,7 @@ describe('Wallet', function() {
|
||||
t1 = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000)
|
||||
.addOutput(w.getAddress(), 1000);
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1.ts = utils.now();
|
||||
t1.height = 1;
|
||||
|
||||
@ -416,17 +419,20 @@ describe('Wallet', function() {
|
||||
yield walletdb.addTX(t2);
|
||||
|
||||
balance = yield w.getBalance();
|
||||
assert.equal(balance.unconfirmed, 71000);
|
||||
//assert.equal(balance.unconfirmed, 71000);
|
||||
assert.equal(balance.unconfirmed, 47000);
|
||||
|
||||
yield walletdb.addTX(t3);
|
||||
|
||||
balance = yield w.getBalance();
|
||||
assert.equal(balance.unconfirmed, 69000);
|
||||
//assert.equal(balance.unconfirmed, 69000);
|
||||
assert.equal(balance.unconfirmed, 22000);
|
||||
|
||||
yield walletdb.addTX(f1);
|
||||
|
||||
balance = yield w.getBalance();
|
||||
assert.equal(balance.unconfirmed, 58000);
|
||||
//assert.equal(balance.unconfirmed, 58000);
|
||||
assert.equal(balance.unconfirmed, 11000);
|
||||
|
||||
txs = yield w.getHistory();
|
||||
assert(txs.some(function(tx) {
|
||||
@ -478,7 +484,7 @@ describe('Wallet', function() {
|
||||
.addOutput(w1.getAddress(), 5460)
|
||||
.addOutput(w1.getAddress(), 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -520,7 +526,7 @@ describe('Wallet', function() {
|
||||
.addOutput(w1.getAddress(), 5460)
|
||||
.addOutput(w1.getAddress(), 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -578,7 +584,7 @@ describe('Wallet', function() {
|
||||
.addOutput(w1.getAddress(), 5460)
|
||||
.addOutput(w1.getAddress(), 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
// Coinbase
|
||||
@ -588,7 +594,7 @@ describe('Wallet', function() {
|
||||
.addOutput(w2.getAddress(), 5460)
|
||||
.addOutput(w2.getAddress(), 5460);
|
||||
|
||||
t2.addInput(dummyInput);
|
||||
t2.addInput(dummy());
|
||||
t2 = t2.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -707,7 +713,7 @@ describe('Wallet', function() {
|
||||
else
|
||||
utx.addOutput({ address: addr, value: 5460 * 10 });
|
||||
|
||||
utx.addInput(dummyInput);
|
||||
utx.addInput(dummy());
|
||||
utx = utx.toTX();
|
||||
|
||||
// Simulate a confirmation
|
||||
@ -816,7 +822,7 @@ describe('Wallet', function() {
|
||||
.addOutput(rec.getAddress(), 5460)
|
||||
.addOutput(rec.getAddress(), 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -878,7 +884,7 @@ describe('Wallet', function() {
|
||||
.addOutput(w.getAddress(), 5460)
|
||||
.addOutput(account.receive.getAddress(), 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -903,7 +909,7 @@ describe('Wallet', function() {
|
||||
.addOutput(account.receive.getAddress(), 5460);
|
||||
|
||||
t1.ps = 0xdeadbeef;
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -927,7 +933,7 @@ describe('Wallet', function() {
|
||||
.addOutput(w.getAddress(), 5460)
|
||||
.addOutput(w.getAddress(), 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -963,7 +969,7 @@ describe('Wallet', function() {
|
||||
.addOutput(w1.getAddress(), 5460)
|
||||
.addOutput(w1.getAddress(), 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -992,7 +998,7 @@ describe('Wallet', function() {
|
||||
.addOutput(w1.getAddress(), 5460)
|
||||
.addOutput(w1.getAddress(), 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -1065,7 +1071,7 @@ describe('Wallet', function() {
|
||||
.addOutput(key.getAddress(), 5460)
|
||||
.addOutput(key.getAddress(), 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1 = t1.toTX();
|
||||
|
||||
yield walletdb.addTX(t1);
|
||||
@ -1194,7 +1200,7 @@ describe('Wallet', function() {
|
||||
// Coinbase
|
||||
t1 = bcoin.mtx()
|
||||
.addOutput(addr, 50000);
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1.height = 1;
|
||||
|
||||
yield alice.sign(t1);
|
||||
@ -1267,7 +1273,7 @@ describe('Wallet', function() {
|
||||
// Coinbase
|
||||
t1 = bcoin.mtx()
|
||||
.addOutput(addr, 50000);
|
||||
t1.addInput(dummyInput);
|
||||
t1.addInput(dummy());
|
||||
t1.height = 1;
|
||||
|
||||
yield alice.sign(t1);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user