utils.cmp. tx-pool improvements.
This commit is contained in:
parent
588d978bb9
commit
7d17dd855f
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user