tx-pool: verify all signatures
This commit is contained in:
parent
86088f8ae9
commit
2e3fb9a7a3
@ -70,18 +70,26 @@ TXPool.prototype.add = function add(tx, noWrite) {
|
|||||||
|
|
||||||
if (unspent) {
|
if (unspent) {
|
||||||
// Add TX to inputs and spend money
|
// Add TX to inputs and spend money
|
||||||
tx.input(unspent.tx, unspent.index);
|
var index = tx._input(unspent.tx, unspent.index);
|
||||||
|
|
||||||
|
// Skip invalid transactions
|
||||||
|
if (!tx.verify(index))
|
||||||
|
return;
|
||||||
|
|
||||||
delete this._unspent[key];
|
delete this._unspent[key];
|
||||||
updated = true;
|
updated = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Double-spend?!
|
if (!own)
|
||||||
if (!own || this._orphans[key])
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Add orphan, if no parent transaction is yet known
|
// Add orphan, if no parent transaction is yet known
|
||||||
this._orphans[key] = { tx: tx, index: input.out.index };
|
var orphan = { tx: tx, index: input.out.index };
|
||||||
|
if (this._orphans[key])
|
||||||
|
this._orphans[key].push(orphan);
|
||||||
|
else
|
||||||
|
this._orphans[key] = [orphan];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!own) {
|
if (!own) {
|
||||||
@ -99,27 +107,28 @@ TXPool.prototype.add = function add(tx, noWrite) {
|
|||||||
var out = tx.outputs[i];
|
var out = tx.outputs[i];
|
||||||
|
|
||||||
var key = hash + '/' + i;
|
var key = hash + '/' + i;
|
||||||
var orphan = this._orphans[key];
|
var orphans = this._orphans[key];
|
||||||
|
|
||||||
// Add input to orphan
|
// Add input to orphan
|
||||||
if (orphan) {
|
if (orphans) {
|
||||||
orphan.tx.input(tx, orphan.index);
|
var some = orphans.some(function(orphan) {
|
||||||
var index = orphan.tx.inputIndex(tx, orphan.index);
|
var index = orphan.tx._input(tx, orphan.index);
|
||||||
|
|
||||||
// Verify that input script is correct, if not - add output to unspent
|
// Verify that input script is correct, if not - add output to unspent
|
||||||
// and remove orphan from storage
|
// and remove orphan from storage
|
||||||
if (!orphan.tx.verify(orphan, index)) {
|
if (!orphan.tx.verify(index)) {
|
||||||
orphan = null;
|
|
||||||
if (this._storage)
|
|
||||||
this._removeTX(orphan.tx);
|
this._removeTX(orphan.tx);
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, this);
|
||||||
|
if (!some)
|
||||||
|
orphans = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!orphan) {
|
|
||||||
this._unspent[key] = { tx: tx, index: i };
|
|
||||||
updated = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
delete this._orphans[key];
|
delete this._orphans[key];
|
||||||
|
if (!orphans)
|
||||||
|
this._unspent[key] = { tx: tx, index: i };
|
||||||
}
|
}
|
||||||
|
|
||||||
this._lastTs = Math.max(tx.ts, this._lastTs);
|
this._lastTs = Math.max(tx.ts, this._lastTs);
|
||||||
@ -143,6 +152,11 @@ TXPool.prototype._storeTX = function _storeTX(hash, tx) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TXPool.prototype._removeTX = function _removeTX(tx) {
|
TXPool.prototype._removeTX = function _removeTX(tx) {
|
||||||
|
for (var i = 0; i < tx.outputs.length; i++)
|
||||||
|
delete this._unspent[tx.hash('hex') + '/' + i];
|
||||||
|
|
||||||
|
if (!this._storage)
|
||||||
|
return;
|
||||||
var self = this;
|
var self = this;
|
||||||
this._storage.del(this._prefix + tx.hash('hex'), function(err) {
|
this._storage.del(this._prefix + tx.hash('hex'), function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
|
|||||||
@ -51,7 +51,7 @@ TX.prototype.render = function render() {
|
|||||||
return bcoin.protocol.framer.tx(this);
|
return bcoin.protocol.framer.tx(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
TX.prototype.input = function input(i, index) {
|
TX.prototype._input = function _input(i, index) {
|
||||||
if (i instanceof TX)
|
if (i instanceof TX)
|
||||||
i = { tx: i, index: index };
|
i = { tx: i, index: index };
|
||||||
else if (typeof i === 'string' || Array.isArray(i))
|
else if (typeof i === 'string' || Array.isArray(i))
|
||||||
@ -79,7 +79,7 @@ TX.prototype.input = function input(i, index) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Try modifying existing input first
|
// Try modifying existing input first
|
||||||
var index = this.inputIndex(hash, index);
|
var index = this._inputIndex(hash, index);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
var ex = this.inputs[index];
|
var ex = this.inputs[index];
|
||||||
|
|
||||||
@ -90,12 +90,13 @@ TX.prototype.input = function input(i, index) {
|
|||||||
this.inputs.push(input);
|
this.inputs.push(input);
|
||||||
if (input.out.tx)
|
if (input.out.tx)
|
||||||
this.funds.iadd(input.out.tx.outputs[input.out.index].value);
|
this.funds.iadd(input.out.tx.outputs[input.out.index].value);
|
||||||
|
index = this.inputs.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return index;
|
||||||
};
|
};
|
||||||
|
|
||||||
TX.prototype.inputIndex = function inputIndex(hash, index) {
|
TX.prototype._inputIndex = function _inputIndex(hash, index) {
|
||||||
if (hash instanceof TX)
|
if (hash instanceof TX)
|
||||||
hash = hash.hash('hex');
|
hash = hash.hash('hex');
|
||||||
for (var i = 0; i < this.inputs.length; i++) {
|
for (var i = 0; i < this.inputs.length; i++) {
|
||||||
@ -107,6 +108,11 @@ TX.prototype.inputIndex = function inputIndex(hash, index) {
|
|||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TX.prototype.input = function input(i, index) {
|
||||||
|
this._input(i, index);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
TX.prototype.out = function out(output, value) {
|
TX.prototype.out = function out(output, value) {
|
||||||
if (output instanceof bcoin.wallet)
|
if (output instanceof bcoin.wallet)
|
||||||
output = output.getAddress();
|
output = output.getAddress();
|
||||||
@ -175,9 +181,9 @@ TX.prototype.verify = function verify(index, force) {
|
|||||||
if (!force && this.ts !== 0)
|
if (!force && this.ts !== 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return this.inputs.filter(function(input, i) {
|
return this.inputs.every(function(input, i) {
|
||||||
if (index !== undefined && index !== i)
|
if (index !== undefined && index !== i)
|
||||||
return false;
|
return true;
|
||||||
|
|
||||||
if (!input.out.tx)
|
if (!input.out.tx)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -79,24 +79,25 @@ describe('Wallet', function() {
|
|||||||
|
|
||||||
// Coinbase
|
// Coinbase
|
||||||
var t1 = bcoin.tx().out(w, 50000).out(w, 1000);
|
var t1 = bcoin.tx().out(w, 50000).out(w, 1000);
|
||||||
var t2 = bcoin.tx().input(t1.hash(), 0)
|
w.sign(t1);
|
||||||
|
var t2 = bcoin.tx().input(t1, 0)
|
||||||
.out(w, 24000)
|
.out(w, 24000)
|
||||||
.out(w, 24000);
|
.out(w, 24000);
|
||||||
var t3 = bcoin.tx().input(t1.hash(), 1)
|
w.sign(t2);
|
||||||
.input(t2.hash(), 0)
|
var t3 = bcoin.tx().input(t1, 1)
|
||||||
|
.input(t2, 0)
|
||||||
.out(w, 23000);
|
.out(w, 23000);
|
||||||
var t4 = bcoin.tx().input(t2.hash(), 1)
|
w.sign(t3);
|
||||||
.input(t3.hash(), 0)
|
var t4 = bcoin.tx().input(t2, 1)
|
||||||
|
.input(t3, 0)
|
||||||
.out(w, 11000)
|
.out(w, 11000)
|
||||||
.out(w, 11000);
|
.out(w, 11000);
|
||||||
var f1 = bcoin.tx().input(t4.hash(), 1)
|
|
||||||
.out(f, 10000);
|
|
||||||
var fake = bcoin.tx().input(t1.hash(), 1);
|
|
||||||
w.sign(t1);
|
|
||||||
w.sign(t2);
|
|
||||||
w.sign(t3);
|
|
||||||
w.sign(t4);
|
w.sign(t4);
|
||||||
|
var f1 = bcoin.tx().input(t4, 1)
|
||||||
|
.out(f, 10000);
|
||||||
w.sign(f1);
|
w.sign(f1);
|
||||||
|
var fake = bcoin.tx().input(t1, 1)
|
||||||
|
.out(w, 500);
|
||||||
|
|
||||||
// Just for debugging
|
// Just for debugging
|
||||||
t1.hint = 't1';
|
t1.hint = 't1';
|
||||||
@ -104,10 +105,13 @@ describe('Wallet', function() {
|
|||||||
t3.hint = 't3';
|
t3.hint = 't3';
|
||||||
t4.hint = 't4';
|
t4.hint = 't4';
|
||||||
f1.hint = 'f1';
|
f1.hint = 'f1';
|
||||||
|
fake.hint = 'fake';
|
||||||
|
|
||||||
|
// Fake TX should temporarly change output
|
||||||
w.addTX(fake);
|
w.addTX(fake);
|
||||||
|
|
||||||
w.addTX(t4);
|
w.addTX(t4);
|
||||||
assert.equal(w.balance().toString(10), '22000');
|
assert.equal(w.balance().toString(10), '22500');
|
||||||
w.addTX(t1);
|
w.addTX(t1);
|
||||||
assert.equal(w.balance().toString(10), '73000');
|
assert.equal(w.balance().toString(10), '73000');
|
||||||
w.addTX(t2);
|
w.addTX(t2);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user