refactor: chain. txdb. wallet.
This commit is contained in:
parent
63a9dc61f6
commit
c2e1e4bfc9
@ -117,8 +117,4 @@ var runBench = co(function* runBench() {
|
|||||||
end(1);
|
end(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
runBench().then(process.exit).catch(function(err) {
|
runBench().then(process.exit);
|
||||||
utils.nextTick(function() {
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@ -52,7 +52,6 @@ known-peers: ./known-peers
|
|||||||
# Miner
|
# Miner
|
||||||
# payout-address: 1111111111111111111114oLvT2
|
# payout-address: 1111111111111111111114oLvT2
|
||||||
# coinbase-flags: mined by bcoin
|
# coinbase-flags: mined by bcoin
|
||||||
# parallel: false
|
|
||||||
|
|
||||||
# HTTP
|
# HTTP
|
||||||
# ssl-cert: @/ssl/cert.crt
|
# ssl-cert: @/ssl/cert.crt
|
||||||
|
|||||||
@ -1008,7 +1008,9 @@ Chain.prototype.isBusy = function isBusy() {
|
|||||||
|
|
||||||
Chain.prototype.add = co(function* add(block) {
|
Chain.prototype.add = co(function* add(block) {
|
||||||
var unlock = yield this.locker.lock(block);
|
var unlock = yield this.locker.lock(block);
|
||||||
|
|
||||||
this.currentBlock = block.hash('hex');
|
this.currentBlock = block.hash('hex');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return yield this._add(block);
|
return yield this._add(block);
|
||||||
} finally {
|
} finally {
|
||||||
@ -1232,7 +1234,7 @@ Chain.prototype._add = co(function* add(block) {
|
|||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Chain.prototype._isSlow = function _isSlow() {
|
Chain.prototype.isSlow = function isSlow() {
|
||||||
if (this.options.spv)
|
if (this.options.spv)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1265,7 +1267,7 @@ Chain.prototype.finish = function finish(block, entry) {
|
|||||||
// Keep track of total blocks handled.
|
// Keep track of total blocks handled.
|
||||||
this.total += 1;
|
this.total += 1;
|
||||||
|
|
||||||
if (!this._isSlow())
|
if (!this.isSlow())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Report memory for debugging.
|
// Report memory for debugging.
|
||||||
@ -1777,8 +1779,7 @@ Chain.prototype.getState = co(function* getState(prev, id) {
|
|||||||
var timeStart, timeTimeout, compute, height;
|
var timeStart, timeTimeout, compute, height;
|
||||||
var i, entry, count, state, block, medianTime;
|
var i, entry, count, state, block, medianTime;
|
||||||
|
|
||||||
if (!deployment)
|
assert(deployment);
|
||||||
return constants.thresholdStates.FAILED;
|
|
||||||
|
|
||||||
timeStart = deployment.startTime;
|
timeStart = deployment.startTime;
|
||||||
timeTimeout = deployment.timeout;
|
timeTimeout = deployment.timeout;
|
||||||
@ -1791,11 +1792,10 @@ Chain.prototype.getState = co(function* getState(prev, id) {
|
|||||||
height = prev.height - ((prev.height + 1) % period);
|
height = prev.height - ((prev.height + 1) % period);
|
||||||
prev = yield prev.getAncestorByHeight(height);
|
prev = yield prev.getAncestorByHeight(height);
|
||||||
|
|
||||||
if (!prev)
|
if (prev) {
|
||||||
return constants.thresholdStates.FAILED;
|
assert(prev.height === height);
|
||||||
|
assert(((prev.height + 1) % period) === 0);
|
||||||
assert(prev.height === height);
|
}
|
||||||
assert(((prev.height + 1) % period) === 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = prev;
|
entry = prev;
|
||||||
@ -1811,6 +1811,7 @@ Chain.prototype.getState = co(function* getState(prev, id) {
|
|||||||
|
|
||||||
if (medianTime < timeStart) {
|
if (medianTime < timeStart) {
|
||||||
state = constants.thresholdStates.DEFINED;
|
state = constants.thresholdStates.DEFINED;
|
||||||
|
stateCache[entry.hash] = state;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1830,58 +1831,50 @@ Chain.prototype.getState = co(function* getState(prev, id) {
|
|||||||
|
|
||||||
if (medianTime >= timeTimeout) {
|
if (medianTime >= timeTimeout) {
|
||||||
state = constants.thresholdStates.FAILED;
|
state = constants.thresholdStates.FAILED;
|
||||||
stateCache[entry.hash] = state;
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (medianTime >= timeStart) {
|
if (medianTime >= timeStart) {
|
||||||
state = constants.thresholdStates.STARTED;
|
state = constants.thresholdStates.STARTED;
|
||||||
stateCache[entry.hash] = state;
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stateCache[entry.hash] = state;
|
break;
|
||||||
continue;
|
|
||||||
case constants.thresholdStates.STARTED:
|
case constants.thresholdStates.STARTED:
|
||||||
medianTime = yield entry.getMedianTimeAsync();
|
medianTime = yield entry.getMedianTimeAsync();
|
||||||
|
|
||||||
if (medianTime >= timeTimeout) {
|
if (medianTime >= timeTimeout) {
|
||||||
state = constants.thresholdStates.FAILED;
|
state = constants.thresholdStates.FAILED;
|
||||||
stateCache[entry.hash] = state;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
|
||||||
count = 0;
|
|
||||||
block = entry;
|
block = entry;
|
||||||
|
count = 0;
|
||||||
|
|
||||||
while (block) {
|
for (i = 0; i < period; i++) {
|
||||||
if (i++ >= period)
|
if (block.hasBit(deployment))
|
||||||
break;
|
|
||||||
|
|
||||||
if (hasBit(block, deployment))
|
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
block = yield block.getPrevious();
|
block = yield block.getPrevious();
|
||||||
|
assert(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count >= threshold)
|
if (count >= threshold)
|
||||||
state = constants.thresholdStates.LOCKED_IN;
|
state = constants.thresholdStates.LOCKED_IN;
|
||||||
|
|
||||||
stateCache[entry.hash] = state;
|
|
||||||
break;
|
break;
|
||||||
case constants.thresholdStates.LOCKED_IN:
|
case constants.thresholdStates.LOCKED_IN:
|
||||||
state = constants.thresholdStates.ACTIVE;
|
state = constants.thresholdStates.ACTIVE;
|
||||||
stateCache[entry.hash] = state;
|
|
||||||
break;
|
break;
|
||||||
case constants.thresholdStates.FAILED:
|
case constants.thresholdStates.FAILED:
|
||||||
case constants.thresholdStates.ACTIVE:
|
case constants.thresholdStates.ACTIVE:
|
||||||
stateCache[entry.hash] = state;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false, 'Bad state.');
|
assert(false, 'Bad state.');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stateCache[entry.hash] = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
@ -1984,7 +1977,7 @@ Chain.prototype.getLocks = co(function* getLocks(prev, tx, flags) {
|
|||||||
var i, input, entry;
|
var i, input, entry;
|
||||||
|
|
||||||
if (tx.isCoinbase() || tx.version < 2 || !hasFlag)
|
if (tx.isCoinbase() || tx.version < 2 || !hasFlag)
|
||||||
return [minHeight, minTime];
|
return new LockTimes(minHeight, minTime);
|
||||||
|
|
||||||
for (i = 0; i < tx.inputs.length; i++) {
|
for (i = 0; i < tx.inputs.length; i++) {
|
||||||
input = tx.inputs[i];
|
input = tx.inputs[i];
|
||||||
@ -1992,9 +1985,9 @@ Chain.prototype.getLocks = co(function* getLocks(prev, tx, flags) {
|
|||||||
if (input.sequence & disableFlag)
|
if (input.sequence & disableFlag)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
coinHeight = input.coin.height === -1
|
coinHeight = input.coin.height !== -1
|
||||||
? this.height + 1
|
? input.coin.height
|
||||||
: input.coin.height;
|
: this.height + 1;
|
||||||
|
|
||||||
if ((input.sequence & typeFlag) === 0) {
|
if ((input.sequence & typeFlag) === 0) {
|
||||||
coinHeight += (input.sequence & mask) - 1;
|
coinHeight += (input.sequence & mask) - 1;
|
||||||
@ -2010,7 +2003,7 @@ Chain.prototype.getLocks = co(function* getLocks(prev, tx, flags) {
|
|||||||
minTime = Math.max(minTime, coinTime);
|
minTime = Math.max(minTime, coinTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [minHeight, minTime];
|
return new LockTimes(minHeight, minTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2048,9 +2041,7 @@ Chain.prototype.evalLocks = co(function* evalLocks(prev, minHeight, minTime) {
|
|||||||
|
|
||||||
Chain.prototype.checkLocks = co(function* checkLocks(prev, tx, flags) {
|
Chain.prototype.checkLocks = co(function* checkLocks(prev, tx, flags) {
|
||||||
var times = yield this.getLocks(prev, tx, flags);
|
var times = yield this.getLocks(prev, tx, flags);
|
||||||
var minHeight = times[0];
|
return yield this.evalLocks(prev, times.height, times.time);
|
||||||
var minTime = times[1];
|
|
||||||
return yield this.evalLocks(prev, minHeight, minTime);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2135,14 +2126,12 @@ DeploymentState.prototype.hasWitness = function hasWitness() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helpers
|
* LockTimes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function hasBit(entry, deployment) {
|
function LockTimes(height, time) {
|
||||||
var bits = entry.version & constants.versionbits.TOP_MASK;
|
this.height = height;
|
||||||
var topBits = constants.versionbits.TOP_BITS;
|
this.time = time;
|
||||||
var mask = 1 << deployment.bit;
|
|
||||||
return bits === topBits && (entry.version & mask) !== 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -417,7 +417,8 @@ ChainEntry.prototype.isSuperMajorityAsync = co(function* isSuperMajorityAsync(ve
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the entry is potentially an ancestor of a checkpoint.
|
* Test whether the entry is potentially
|
||||||
|
* an ancestor of a checkpoint.
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -429,6 +430,19 @@ ChainEntry.prototype.isHistorical = function isHistorical() {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the entry contains a version bit.
|
||||||
|
* @param {Object} deployment
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
ChainEntry.prototype.hasBit = function hasBit(deployment) {
|
||||||
|
var bits = this.version & constants.versionbits.TOP_MASK;
|
||||||
|
var topBits = constants.versionbits.TOP_BITS;
|
||||||
|
var mask = 1 << deployment.bit;
|
||||||
|
return bits === topBits && (this.version & mask) !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
ChainEntry.prototype.__defineGetter__('rhash', function() {
|
ChainEntry.prototype.__defineGetter__('rhash', function() {
|
||||||
return utils.revHex(this.hash);
|
return utils.revHex(this.hash);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -304,21 +304,23 @@ LowlevelUp.prototype.has = co(function* has(key) {
|
|||||||
|
|
||||||
LowlevelUp.prototype.iterate = co(function* iterate(options) {
|
LowlevelUp.prototype.iterate = co(function* iterate(options) {
|
||||||
var items = [];
|
var items = [];
|
||||||
var iter, kv, result;
|
var parse = options.parse;
|
||||||
|
var iter, result, data;
|
||||||
|
|
||||||
assert(typeof options.parse === 'function', 'Parse must be a function.');
|
assert(typeof parse === 'function', 'Parse must be a function.');
|
||||||
|
|
||||||
iter = this.iterator(options);
|
iter = this.iterator(options);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
kv = yield iter.next();
|
result = yield iter.next();
|
||||||
if (!kv)
|
|
||||||
|
if (!result)
|
||||||
return items;
|
return items;
|
||||||
|
|
||||||
result = options.parse(kv[0], kv[1]);
|
data = parse(result.key, result.value);
|
||||||
|
|
||||||
if (result)
|
if (data)
|
||||||
items.push(result);
|
items.push(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
@ -453,7 +455,7 @@ Iterator.prototype.next = function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve([key, value]);
|
resolve(new KeyValue(key, value));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -473,6 +475,11 @@ Iterator.prototype.end = function end() {
|
|||||||
* Helpers
|
* Helpers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
function KeyValue(key, value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
function isNotFound(err) {
|
function isNotFound(err) {
|
||||||
if (!err)
|
if (!err)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -115,7 +115,7 @@ Miner.prototype._init = function _init() {
|
|||||||
|
|
||||||
if (bcoin.useWorkers) {
|
if (bcoin.useWorkers) {
|
||||||
this.workerPool = new bcoin.workers({
|
this.workerPool = new bcoin.workers({
|
||||||
size: this.options.parallel ? 2 : 1,
|
size: 1,
|
||||||
timeout: -1
|
timeout: -1
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -268,7 +268,6 @@ Miner.prototype.createBlock = co(function* createBlock(tip) {
|
|||||||
address: this.address,
|
address: this.address,
|
||||||
coinbaseFlags: this.coinbaseFlags,
|
coinbaseFlags: this.coinbaseFlags,
|
||||||
witness: this.chain.segwitActive,
|
witness: this.chain.segwitActive,
|
||||||
parallel: this.options.parallel,
|
|
||||||
network: this.network
|
network: this.network
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -339,6 +339,13 @@ Peer.prototype._bip151 = co(function* _bip151() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.error(err, true);
|
this.error(err, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(this.bip151.completed);
|
||||||
|
|
||||||
|
if (this.bip151.handshake) {
|
||||||
|
this.logger.info('BIP151 handshake complete (%s).', this.hostname);
|
||||||
|
this.logger.info('Connection is encrypted (%s).', this.hostname);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -347,17 +354,7 @@ Peer.prototype._bip151 = co(function* _bip151() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Peer.prototype._bip150 = co(function* _bip150() {
|
Peer.prototype._bip150 = co(function* _bip150() {
|
||||||
if (!this.bip151)
|
if (!this.bip151 || !this.bip150)
|
||||||
return;
|
|
||||||
|
|
||||||
assert(this.bip151.completed);
|
|
||||||
|
|
||||||
if (this.bip151.handshake) {
|
|
||||||
this.logger.info('BIP151 handshake complete (%s).', this.hostname);
|
|
||||||
this.logger.info('Connection is encrypted (%s).', this.hostname);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.bip150)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(!this.bip150.completed);
|
assert(!this.bip150.completed);
|
||||||
@ -2090,7 +2087,6 @@ Peer.prototype._handleCmpctBlock = co(function* _handleCmpctBlock(packet) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort of a lock too.
|
|
||||||
this.compactBlocks[hash] = block;
|
this.compactBlocks[hash] = block;
|
||||||
|
|
||||||
result = block.fillMempool(this.mempool);
|
result = block.fillMempool(this.mempool);
|
||||||
|
|||||||
@ -124,8 +124,7 @@ function Fullnode(options) {
|
|||||||
mempool: this.mempool,
|
mempool: this.mempool,
|
||||||
fees: this.fees,
|
fees: this.fees,
|
||||||
address: this.options.payoutAddress,
|
address: this.options.payoutAddress,
|
||||||
coinbaseFlags: this.options.coinbaseFlags,
|
coinbaseFlags: this.options.coinbaseFlags
|
||||||
parallel: this.options.parallel
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wallet database needs access to fees.
|
// Wallet database needs access to fees.
|
||||||
|
|||||||
@ -844,6 +844,12 @@ MTX.prototype.template = function template(ring) {
|
|||||||
var total = 0;
|
var total = 0;
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
|
if (Array.isArray(ring)) {
|
||||||
|
for (i = 0; i < ring.length; i++)
|
||||||
|
total += this.template(ring[i]);
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < this.inputs.length; i++) {
|
for (i = 0; i < this.inputs.length; i++) {
|
||||||
if (!ring.ownInput(this, i))
|
if (!ring.ownInput(this, i))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -592,13 +592,13 @@ Account.prototype.setDepth = co(function* setDepth(receiveDepth, changeDepth) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rings.length === 0)
|
if (rings.length === 0)
|
||||||
return [];
|
return;
|
||||||
|
|
||||||
yield this.saveAddress(rings);
|
yield this.saveAddress(rings);
|
||||||
|
|
||||||
this.save();
|
this.save();
|
||||||
|
|
||||||
return [receive, change];
|
return receive;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -380,19 +380,19 @@ TXDB.prototype.getInfo = function getInfo(tx) {
|
|||||||
* to orphan list. Stored by its required coin ID.
|
* to orphan list. Stored by its required coin ID.
|
||||||
* @private
|
* @private
|
||||||
* @param {Outpoint} prevout - Required coin hash & index.
|
* @param {Outpoint} prevout - Required coin hash & index.
|
||||||
* @param {Buffer} spender - Spender input hash and index.
|
* @param {Buffer} input - Spender input hash and index.
|
||||||
* @param {Function} callback - Returns [Error, Buffer].
|
* @param {Function} callback - Returns [Error, Buffer].
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.addOrphan = co(function* addOrphan(prevout, spender) {
|
TXDB.prototype.addOrphan = co(function* addOrphan(prevout, input) {
|
||||||
var p = new BufferWriter();
|
|
||||||
var key = layout.o(prevout.hash, prevout.index);
|
var key = layout.o(prevout.hash, prevout.index);
|
||||||
var data = yield this.get(key);
|
var data = yield this.get(key);
|
||||||
|
var p = new BufferWriter();
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
p.writeBytes(data);
|
p.writeBytes(data);
|
||||||
|
|
||||||
p.writeBytes(spender);
|
p.writeBytes(input);
|
||||||
|
|
||||||
this.put(key, p.render());
|
this.put(key, p.render());
|
||||||
});
|
});
|
||||||
@ -406,24 +406,24 @@ TXDB.prototype.addOrphan = co(function* addOrphan(prevout, spender) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.getOrphans = co(function* getOrphans(hash, index) {
|
TXDB.prototype.getOrphans = co(function* getOrphans(hash, index) {
|
||||||
|
var key = layout.o(hash, index);
|
||||||
|
var data = yield this.get(key);
|
||||||
var items = [];
|
var items = [];
|
||||||
var i, data, orphans, orphan, tx, p;
|
var i, inputs, input, tx, p;
|
||||||
|
|
||||||
data = yield this.get(layout.o(hash, index));
|
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
p = new BufferReader(data);
|
p = new BufferReader(data);
|
||||||
orphans = [];
|
inputs = [];
|
||||||
|
|
||||||
while (p.left())
|
while (p.left())
|
||||||
orphans.push(bcoin.outpoint.fromRaw(p));
|
inputs.push(bcoin.outpoint.fromRaw(p));
|
||||||
|
|
||||||
for (i = 0; i < orphans.length; i++) {
|
for (i = 0; i < inputs.length; i++) {
|
||||||
orphan = orphans[i];
|
input = inputs[i];
|
||||||
tx = yield this.getTX(orphan.hash);
|
tx = yield this.getTX(input.hash);
|
||||||
items.push([orphan, tx]);
|
items.push(new Orphan(input, tx));
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
@ -439,7 +439,7 @@ TXDB.prototype.getOrphans = co(function* getOrphans(hash, index) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.verify = co(function* verify(tx, info) {
|
TXDB.prototype.verify = co(function* verify(tx, info) {
|
||||||
var i, input, prevout, address, coin, spent, rtx, rinfo, result;
|
var i, input, prevout, address, coin, spent, conflict;
|
||||||
|
|
||||||
for (i = 0; i < tx.inputs.length; i++) {
|
for (i = 0; i < tx.inputs.length; i++) {
|
||||||
input = tx.inputs[i];
|
input = tx.inputs[i];
|
||||||
@ -462,7 +462,7 @@ TXDB.prototype.verify = co(function* verify(tx, info) {
|
|||||||
|
|
||||||
// Skip invalid transactions
|
// Skip invalid transactions
|
||||||
if (this.options.verify) {
|
if (this.options.verify) {
|
||||||
if (!tx.verifyInput(i))
|
if (!(yield tx.verifyInputAsync(i)))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,25 +487,23 @@ TXDB.prototype.verify = co(function* verify(tx, info) {
|
|||||||
|
|
||||||
// Skip invalid transactions
|
// Skip invalid transactions
|
||||||
if (this.options.verify) {
|
if (this.options.verify) {
|
||||||
if (!tx.verifyInput(i))
|
if (!(yield tx.verifyInputAsync(i)))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.warning('Removing conflicting tx: %s.',
|
this.logger.warning('Removing conflicting tx: %s.',
|
||||||
utils.revHex(spent.hash));
|
utils.revHex(spent.hash));
|
||||||
|
|
||||||
result = yield this.removeConflict(spent.hash, tx);
|
// Remove the older double spender.
|
||||||
|
conflict = yield this.removeConflict(spent.hash, tx);
|
||||||
|
|
||||||
// Spender was not removed, the current
|
// Spender was not removed, the current
|
||||||
// transaction is not elligible to be added.
|
// transaction is not elligible to be added.
|
||||||
if (!result)
|
if (!conflict)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
rtx = result[0];
|
|
||||||
rinfo = result[1];
|
|
||||||
|
|
||||||
// Emit the _removed_ transaction.
|
// Emit the _removed_ transaction.
|
||||||
this.emit('conflict', rtx, rinfo);
|
this.emit('conflict', conflict.tx, conflict.info);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -521,7 +519,7 @@ TXDB.prototype.verify = co(function* verify(tx, info) {
|
|||||||
|
|
||||||
TXDB.prototype.resolveOrphans = co(function* resolveOrphans(tx, index) {
|
TXDB.prototype.resolveOrphans = co(function* resolveOrphans(tx, index) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var i, orphans, coin, item, input, orphan;
|
var i, orphans, coin, input, orphan, key;
|
||||||
|
|
||||||
orphans = yield this.getOrphans(hash, index);
|
orphans = yield this.getOrphans(hash, index);
|
||||||
|
|
||||||
@ -534,27 +532,28 @@ TXDB.prototype.resolveOrphans = co(function* resolveOrphans(tx, index) {
|
|||||||
|
|
||||||
// Add input to orphan
|
// Add input to orphan
|
||||||
for (i = 0; i < orphans.length; i++) {
|
for (i = 0; i < orphans.length; i++) {
|
||||||
item = orphans[i];
|
orphan = orphans[i];
|
||||||
input = item[0];
|
input = orphan.input;
|
||||||
orphan = item[1];
|
tx = orphan.tx;
|
||||||
|
|
||||||
// Probably removed by some other means.
|
// Probably removed by some other means.
|
||||||
if (!orphan)
|
if (!tx)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
orphan.inputs[input.index].coin = coin;
|
tx.inputs[input.index].coin = coin;
|
||||||
|
|
||||||
assert(orphan.inputs[input.index].prevout.hash === hash);
|
assert(tx.inputs[input.index].prevout.hash === hash);
|
||||||
assert(orphan.inputs[input.index].prevout.index === index);
|
assert(tx.inputs[input.index].prevout.index === index);
|
||||||
|
|
||||||
// Verify that input script is correct, if not - add
|
// Verify that input script is correct, if not - add
|
||||||
// output to unspent and remove orphan from storage
|
// output to unspent and remove orphan from storage
|
||||||
if (!this.options.verify || (yield orphan.verifyInputAsync(input.index))) {
|
if (!this.options.verify || (yield tx.verifyInputAsync(input.index))) {
|
||||||
this.put(layout.d(input.hash, input.index), coin.toRaw());
|
key = layout.d(input.hash, input.index);
|
||||||
|
this.put(key, coin.toRaw());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield this.lazyRemove(orphan);
|
yield this.lazyRemove(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just going to be added again outside.
|
// Just going to be added again outside.
|
||||||
@ -621,11 +620,14 @@ TXDB.prototype._add = co(function* add(tx, info) {
|
|||||||
|
|
||||||
for (i = 0; i < info.accounts.length; i++) {
|
for (i = 0; i < info.accounts.length; i++) {
|
||||||
account = info.accounts[i];
|
account = info.accounts[i];
|
||||||
|
|
||||||
this.put(layout.T(account, hash), DUMMY);
|
this.put(layout.T(account, hash), DUMMY);
|
||||||
|
|
||||||
if (tx.ts === 0)
|
if (tx.ts === 0)
|
||||||
this.put(layout.P(account, hash), DUMMY);
|
this.put(layout.P(account, hash), DUMMY);
|
||||||
else
|
else
|
||||||
this.put(layout.H(account, tx.height, hash), DUMMY);
|
this.put(layout.H(account, tx.height, hash), DUMMY);
|
||||||
|
|
||||||
this.put(layout.M(account, tx.ps, hash), DUMMY);
|
this.put(layout.M(account, tx.ps, hash), DUMMY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,7 +648,7 @@ TXDB.prototype._add = co(function* add(tx, info) {
|
|||||||
|
|
||||||
key = prevout.hash + prevout.index;
|
key = prevout.hash + prevout.index;
|
||||||
|
|
||||||
// s/[outpoint-key] -> [spender-hash]|[spender-input-index]
|
// s[outpoint-key] -> [spender-hash]|[spender-input-index]
|
||||||
spender = bcoin.outpoint.fromTX(tx, i).toRaw();
|
spender = bcoin.outpoint.fromTX(tx, i).toRaw();
|
||||||
this.put(layout.s(prevout.hash, prevout.index), spender);
|
this.put(layout.s(prevout.hash, prevout.index), spender);
|
||||||
|
|
||||||
@ -757,7 +759,7 @@ TXDB.prototype.removeConflict = co(function* removeConflict(hash, ref) {
|
|||||||
|
|
||||||
info = yield this.removeRecursive(tx);
|
info = yield this.removeRecursive(tx);
|
||||||
|
|
||||||
return [tx, info];
|
return new Conflict(tx, info);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -774,6 +776,7 @@ TXDB.prototype.removeRecursive = co(function* removeRecursive(tx) {
|
|||||||
|
|
||||||
for (i = 0; i < tx.outputs.length; i++) {
|
for (i = 0; i < tx.outputs.length; i++) {
|
||||||
spent = yield this.isSpent(hash, i);
|
spent = yield this.isSpent(hash, i);
|
||||||
|
|
||||||
if (!spent)
|
if (!spent)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1019,11 +1022,14 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
|
|||||||
|
|
||||||
for (i = 0; i < info.accounts.length; i++) {
|
for (i = 0; i < info.accounts.length; i++) {
|
||||||
account = info.accounts[i];
|
account = info.accounts[i];
|
||||||
|
|
||||||
this.del(layout.T(account, hash));
|
this.del(layout.T(account, hash));
|
||||||
|
|
||||||
if (tx.ts === 0)
|
if (tx.ts === 0)
|
||||||
this.del(layout.P(account, hash));
|
this.del(layout.P(account, hash));
|
||||||
else
|
else
|
||||||
this.del(layout.H(account, tx.height, hash));
|
this.del(layout.H(account, tx.height, hash));
|
||||||
|
|
||||||
this.del(layout.M(account, tx.ps, hash));
|
this.del(layout.M(account, tx.ps, hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2092,6 +2098,16 @@ function sortCoins(coins) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Conflict(tx, info) {
|
||||||
|
this.tx = tx;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Orphan(input, tx) {
|
||||||
|
this.input = input;
|
||||||
|
this.tx = tx;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -56,7 +56,6 @@ function Wallet(db, options) {
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
this.network = db.network;
|
this.network = db.network;
|
||||||
this.logger = db.logger;
|
this.logger = db.logger;
|
||||||
this.workerPool = db.workerPool;
|
|
||||||
this.writeLock = new bcoin.locker(this);
|
this.writeLock = new bcoin.locker(this);
|
||||||
this.fundLock = new bcoin.locker(this);
|
this.fundLock = new bcoin.locker(this);
|
||||||
|
|
||||||
@ -1220,8 +1219,7 @@ Wallet.prototype._syncOutputDepth = co(function* syncOutputDepth(info) {
|
|||||||
var receive = [];
|
var receive = [];
|
||||||
var accounts = {};
|
var accounts = {};
|
||||||
var i, j, path, paths, account;
|
var i, j, path, paths, account;
|
||||||
var receiveDepth, changeDepth;
|
var receiveDepth, changeDepth, ring;
|
||||||
var ret, rcv, chng;
|
|
||||||
|
|
||||||
this.start();
|
this.start();
|
||||||
|
|
||||||
@ -1265,22 +1263,19 @@ Wallet.prototype._syncOutputDepth = co(function* syncOutputDepth(info) {
|
|||||||
if (!account)
|
if (!account)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = yield account.setDepth(receiveDepth, changeDepth);
|
ring = yield account.setDepth(receiveDepth, changeDepth);
|
||||||
|
|
||||||
rcv = ret[0];
|
if (ring)
|
||||||
chng = ret[1];
|
receive.push(ring);
|
||||||
|
|
||||||
if (rcv)
|
|
||||||
receive.push(rcv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
yield this.commit();
|
||||||
|
|
||||||
if (receive.length > 0) {
|
if (receive.length > 0) {
|
||||||
this.db.emit('address', this.id, receive);
|
this.db.emit('address', this.id, receive);
|
||||||
this.emit('address', receive);
|
this.emit('address', receive);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield this.commit();
|
|
||||||
|
|
||||||
return receive;
|
return receive;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1349,17 +1344,8 @@ Wallet.prototype.getRedeem = co(function* getRedeem(hash) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.template = co(function* template(tx) {
|
Wallet.prototype.template = co(function* template(tx) {
|
||||||
var total = 0;
|
var rings = yield this.deriveInputs(tx);
|
||||||
var i, rings, ring;
|
return tx.template(rings);
|
||||||
|
|
||||||
rings = yield this.deriveInputs(tx);
|
|
||||||
|
|
||||||
for (i = 0; i < rings.length; i++) {
|
|
||||||
ring = rings[i];
|
|
||||||
total += tx.template(ring);
|
|
||||||
}
|
|
||||||
|
|
||||||
return total;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1372,7 +1358,7 @@ Wallet.prototype.template = co(function* template(tx) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.sign = co(function* sign(tx, options) {
|
Wallet.prototype.sign = co(function* sign(tx, options) {
|
||||||
var master, rings;
|
var rings;
|
||||||
|
|
||||||
if (!options)
|
if (!options)
|
||||||
options = {};
|
options = {};
|
||||||
@ -1380,36 +1366,13 @@ Wallet.prototype.sign = co(function* sign(tx, options) {
|
|||||||
if (typeof options === 'string' || Buffer.isBuffer(options))
|
if (typeof options === 'string' || Buffer.isBuffer(options))
|
||||||
options = { passphrase: options };
|
options = { passphrase: options };
|
||||||
|
|
||||||
master = yield this.unlock(options.passphrase, options.timeout);
|
yield this.unlock(options.passphrase, options.timeout);
|
||||||
|
|
||||||
rings = yield this.deriveInputs(tx);
|
rings = yield this.deriveInputs(tx);
|
||||||
|
|
||||||
return yield this.signAsync(rings, tx);
|
return yield tx.signAsync(rings);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Sign a transaction asynchronously.
|
|
||||||
* @param {KeyRing[]} rings
|
|
||||||
* @param {MTX} tx
|
|
||||||
* @param {Function} callback - Returns [Error, Number] (total number
|
|
||||||
* of inputs scripts built and signed).
|
|
||||||
*/
|
|
||||||
|
|
||||||
Wallet.prototype.signAsync = function signAsync(rings, tx) {
|
|
||||||
var result;
|
|
||||||
|
|
||||||
if (!this.workerPool) {
|
|
||||||
try {
|
|
||||||
result = tx.sign(rings);
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
return Promise.resolve(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.workerPool.sign(tx, rings, null);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill transaction with coins (accesses db).
|
* Fill transaction with coins (accesses db).
|
||||||
* @param {TX} tx
|
* @param {TX} tx
|
||||||
|
|||||||
@ -128,7 +128,6 @@ function WalletDB(options) {
|
|||||||
this.logger = options.logger || bcoin.defaultLogger;
|
this.logger = options.logger || bcoin.defaultLogger;
|
||||||
this.batches = {};
|
this.batches = {};
|
||||||
this.wallets = {};
|
this.wallets = {};
|
||||||
this.workerPool = null;
|
|
||||||
|
|
||||||
this.tip = this.network.genesis.hash;
|
this.tip = this.network.genesis.hash;
|
||||||
this.height = 0;
|
this.height = 0;
|
||||||
@ -163,9 +162,6 @@ function WalletDB(options) {
|
|||||||
bufferKeys: !utils.isBrowser
|
bufferKeys: !utils.isBrowser
|
||||||
});
|
});
|
||||||
|
|
||||||
if (bcoin.useWorkers)
|
|
||||||
this.workerPool = new bcoin.workers();
|
|
||||||
|
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,13 +180,7 @@ WalletDB.layout = layout;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype._init = function _init() {
|
WalletDB.prototype._init = function _init() {
|
||||||
var self = this;
|
;
|
||||||
|
|
||||||
if (bcoin.useWorkers) {
|
|
||||||
this.workerPool.on('error', function(err) {
|
|
||||||
self.emit('error', err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,7 +239,7 @@ WalletDB.prototype.backup = function backup(path) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.getDepth = co(function* getDepth() {
|
WalletDB.prototype.getDepth = co(function* getDepth() {
|
||||||
var kv, iter, depth;
|
var result, iter, depth;
|
||||||
|
|
||||||
// This may seem like a strange way to do
|
// This may seem like a strange way to do
|
||||||
// this, but updating a global state when
|
// this, but updating a global state when
|
||||||
@ -266,14 +256,14 @@ WalletDB.prototype.getDepth = co(function* getDepth() {
|
|||||||
reverse: true
|
reverse: true
|
||||||
});
|
});
|
||||||
|
|
||||||
kv = yield iter.next();
|
result = yield iter.next();
|
||||||
|
|
||||||
if (!kv)
|
if (!result)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
yield iter.end();
|
yield iter.end();
|
||||||
|
|
||||||
depth = layout.ww(kv[0]);
|
depth = layout.ww(result.key);
|
||||||
|
|
||||||
return depth + 1;
|
return depth + 1;
|
||||||
});
|
});
|
||||||
@ -1546,11 +1536,15 @@ PathInfo.prototype.fromTX = function fromTX(tx, table) {
|
|||||||
for (i = 0; i < hashes.length; i++) {
|
for (i = 0; i < hashes.length; i++) {
|
||||||
hash = hashes[i];
|
hash = hashes[i];
|
||||||
paths = table[hash];
|
paths = table[hash];
|
||||||
|
|
||||||
for (j = 0; j < paths.length; j++) {
|
for (j = 0; j < paths.length; j++) {
|
||||||
path = paths[j];
|
path = paths[j];
|
||||||
|
|
||||||
if (path.wid !== this.wid)
|
if (path.wid !== this.wid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
this.pathMap[hash] = path;
|
this.pathMap[hash] = path;
|
||||||
|
|
||||||
if (!uniq[path.account]) {
|
if (!uniq[path.account]) {
|
||||||
uniq[path.account] = true;
|
uniq[path.account] = true;
|
||||||
this.accounts.push(path.account);
|
this.accounts.push(path.account);
|
||||||
@ -1563,10 +1557,13 @@ PathInfo.prototype.fromTX = function fromTX(tx, table) {
|
|||||||
for (i = 0; i < hashes.length; i++) {
|
for (i = 0; i < hashes.length; i++) {
|
||||||
hash = hashes[i];
|
hash = hashes[i];
|
||||||
paths = table[hash];
|
paths = table[hash];
|
||||||
|
|
||||||
for (j = 0; j < paths.length; j++) {
|
for (j = 0; j < paths.length; j++) {
|
||||||
path = paths[j];
|
path = paths[j];
|
||||||
|
|
||||||
if (path.wid !== this.wid)
|
if (path.wid !== this.wid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
this.paths.push(path);
|
this.paths.push(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user