utils.cmp. tx-pool improvements.

This commit is contained in:
Christopher Jeffrey 2016-02-07 06:11:48 -08:00
parent 588d978bb9
commit 7d17dd855f
4 changed files with 121 additions and 65 deletions

View File

@ -37,16 +37,6 @@ function TXPool(wallet) {
this._received = new bn(0);
this._balance = new bn(0);
this._wallet.on('remove address', function(address) {
address = self._addresses[address.getAddress()];
if (address) {
self._balance.isub(address.balance);
self._sent.isub(address.sent);
self._received.isub(address.received);
delete self._addresses[address];
}
});
// Load TXs from storage
this._init();
}
@ -130,18 +120,16 @@ TXPool.prototype.add = function add(tx, noWrite, strict) {
if (unspent) {
// Add TX to inputs and spend money
index = tx._inputIndex(unspent.hash, unspent.index);
assert(index !== -1);
assert(tx.inputs[index] === input);
assert(tx.inputs[index].prevout.hash === unspent.hash);
assert(tx.inputs[index].prevout.index === unspent.index);
input.output = unspent;
assert(input.prevout.hash === unspent.hash);
assert(input.prevout.index === unspent.index);
// Skip invalid transactions
if (!tx.verify(index))
if (!tx.verify(i))
return;
this._addInput(tx, index);
this._addInput(tx, i);
delete this._unspent[key];
updated = true;
@ -153,7 +141,7 @@ TXPool.prototype.add = function add(tx, noWrite, strict) {
continue;
// Add orphan, if no parent transaction is yet known
orphan = { tx: tx, index: input.prevout.index };
orphan = { tx: tx, index: i };
if (this._orphans[key])
this._orphans[key].push(orphan);
else
@ -161,20 +149,19 @@ TXPool.prototype.add = function add(tx, noWrite, strict) {
}
function checkOrphan(orphan) {
var index = orphan.tx._inputIndex(tx.hash('hex'), orphan.index);
assert(index !== -1);
assert(orphan.tx.inputs[index].prevout.hash === tx.hash('hex'));
assert(orphan.tx.inputs[index].prevout.index === i);
orphan.tx.inputs[index].output = coin;
orphan.tx.inputs[orphan.index].output = coin;
assert(orphan.tx.inputs[orphan.index].prevout.hash === hash);
assert(orphan.tx.inputs[orphan.index].prevout.index === i);
// Verify that input script is correct, if not - add output to unspent
// and remove orphan from storage
if (!orphan.tx.verify(index)) {
if (!orphan.tx.verify(orphan.index)) {
this._removeTX(orphan.tx, noWrite);
return false;
}
this._addInput(orphan.tx, index);
this._addInput(orphan.tx, orphan.index);
return true;
}
@ -226,21 +213,69 @@ TXPool.prototype.getTX = function getTX(hash) {
return this._all[hash];
};
TXPool.prototype.getUnspent = function getUnspent(hash, index) {
TXPool.prototype.getCoin = function getCoin(hash, index) {
return this._unspent[hash + '/' + index];
};
TXPool.prototype.addUnspent = function addUnspent(coin) {
TXPool.prototype.addCoin = function addCoin(coin, noWrite) {
var id = coin.hash + '/' + coin.index;
if (!this._unspent[id]) {
this._unspent[id] = coin;
this._addOutput(coin);
this._lastHeight = Math.max(coin.height, this._lastHeight);
this.emit('update', this._lastTs, this._lastHeight);
// Weird workaround to get addresses to update
if (coin.height !== -1)
this.emit('confirmed', coin);
// Do not add TX two times
if (this._unspent[id]) {
// Transaction was confirmed, update it in storage
if (coin.height !== -1 && this._unspent[id].height === -1) {
this._unspent[key].height = coin.height;
this._lastHeight = Math.max(tx.height, this._lastHeight);
this.emit('update', this._lastTs, this._lastHeight, tx);
this.emit('confirmed', tx);
// this._storeCoin(coin, noWrite);
}
return;
}
// Problem here: could in some cases add
// an unspent that was already redeemed.
if (this._all[coin.hash])
return;
this._unspent[id] = coin;
this._addOutput(coin);
this._lastHeight = Math.max(coin.height, this._lastHeight);
this.emit('update', this._lastTs, this._lastHeight);
// Weird workaround to get addresses to update
if (coin.height !== -1)
this.emit('confirmed', coin);
// this._storeCoin(coin, noWrite);
};
TXPool.prototype._storeCoin = function _storeCoin(id, coin, noWrite) {
var self = this;
if (!this._storage || noWrite)
return;
this._storage.put(this._prefix + id, coin.toJSON(), function(err) {
if (err)
self.emit('error', err);
});
};
TXPool.prototype._removeCoin = function _removeCoin(id, noWrite) {
var self = this;
var key;
if (this._unspent[id]) {
this._removeOutput(this._unspent[id]);
delete this._unspent[id];
}
if (!this._storage || noWrite)
return;
this._storage.del(this._prefix + id, function(err) {
if (err)
self.emit('error', err);
});
};
TXPool.prototype._storeTX = function _storeTX(hash, tx, noWrite) {
@ -276,19 +311,6 @@ TXPool.prototype._removeTX = function _removeTX(tx, noWrite) {
});
};
TXPool.prototype.prune = function prune(pruneOrphans) {
var unspent = Object.keys(this._unspent).reduce(function(key) {
out[key.split('/')[0]] = true;
return out;
}, {});
Object.keys(this._all).forEach(function(key) {
if (!unspent[key])
delete this._all[key];
});
if (pruneOrphans)
this._orphans = {};
};
TXPool.prototype.getAll = function getAll(address) {
if (!address)
address = this._wallet;
@ -302,17 +324,15 @@ TXPool.prototype.getAll = function getAll(address) {
};
TXPool.prototype._addOutput = function _addOutput(tx, i, remove) {
if ((tx instanceof bcoin.output) || (tx instanceof bcoin.coin)) {
var output = tx;
if (!this._wallet.ownOutput(output))
return;
} else {
var output = tx.outputs[i];
var address;
var output, address;
if (!this._wallet.ownOutput(tx, i))
return;
}
if ((tx instanceof bcoin.output) || (tx instanceof bcoin.coin))
output = tx;
else
output = tx.outputs[i];
if (!this._wallet.ownOutput(output))
return;
address = output.getAddress();
@ -346,8 +366,12 @@ TXPool.prototype._removeOutput = function _removeOutput(tx, i) {
};
TXPool.prototype._addInput = function _addInput(tx, i, remove) {
var input = tx.inputs[i];
var prev, address;
var input, prev, address;
if (tx instanceof bcoin.input)
input = tx;
else
input = tx.inputs[i];
assert(input.output);
@ -418,8 +442,8 @@ TXPool.prototype.getBalance = function getBalance(address) {
if (unspent.length === 0)
return acc;
return unspent.reduce(function(acc, item) {
return acc.iadd(item.tx.outputs[item.index].value);
return unspent.reduce(function(acc, coin) {
return acc.iadd(coin.value);
}, acc);
};

View File

@ -159,7 +159,7 @@ TX.prototype._addInput = function _addInput(options, index) {
} else if (options.tx) {
coin = bcoin.coin(options.tx, options.index);
options = {
prevout: { hash: coin.hash, index: coin.index },
prevout: { hash: options.tx.hash('hex'), index: options.index },
output: coin,
script: options.script,
sequence: options.sequence

View File

@ -1333,3 +1333,36 @@ utils.sizeIntv = function sizeIntv(num) {
return 9;
};
utils.cmp = function(a, b) {
var len = Math.min(a.length, b.length);
for (i = 0; i < len; i++) {
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
if (a.length < b.length)
return -1;
if (a.length > b.length)
return 1;
return 0;
};
// https://cryptocoding.net/index.php/Coding_rules
// memcmp in constant time (can only return true or false)
// $ man 3 memcmp (see NetBSD's consttime_memequal)
utils.ccmp = function(a, b) {
var res, i;
assert(a.length === b.length);
for (i = 0; i < a.length; i++)
res = a[i] ^ b[i];
return res === 0;
};

View File

@ -646,8 +646,7 @@ Wallet.prototype.addAddress = function addAddress(address) {
if (this._addressIndex(address) !== -1)
return;
if (address._wallet)
address._wallet.removeAddress(address);
assert(!address._wallet);
address._wallet = this;