Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 116 additions & 20 deletions lib/mempool/mempool.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,29 @@ class Mempool extends EventEmitter {
this.tip = this.network.genesis.hash;
this.nextState = this.chain.state;

this.waiting = new BufferMap();
this.orphans = new BufferMap();
this.map = new BufferMap();
this.spents = new BufferMap();
this.claims = new BufferMap();
this.airdrops = new BufferMap();
this.airdropIndex = new Map();
this.claimNames = new BufferMap();
// "The" mempool
this.map = new BufferMap(); // hash -> MempoolEntry
this.claims = new BufferMap(); // hash -> ClaimEntry
this.airdrops = new BufferMap(); // hash -> AirdropEntry

// Orphans and missing parents
this.waiting = new BufferMap(); // parent hash -> BufferSet[spender hashes]
this.orphans = new BufferMap(); // orphan tx hash -> Orphan

// Prevent double-spends
this.spents = new BufferMap(); // prevout key -> MempoolEntry of spender
this.claimNames = new BufferMap(); // namehash -> ClaimEntry
this.airdropIndex = new Map(); // airdrop position -> AirdropEntry

// Track namestates to validate incoming covenants
this.contracts = new ContractState(this.network);

// Recently rejected txs by hash
this.rejects = new RollingFilter(120000, 0.000001);

// Extensions of blockchain indexes by tx hash for API
this.coinIndex = new CoinIndex();
this.txIndex = new TXIndex();

this.contracts = new ContractState(this.network);
}

/**
Expand Down Expand Up @@ -193,13 +202,6 @@ class Mempool extends EventEmitter {
*/

async _addBlock(block, txs, view) {
if (this.map.size === 0
&& this.claims.size === 0
&& this.airdrops.size === 0) {
this.tip = block.hash;
return;
}

const entries = [];
const cb = txs[0];

Expand Down Expand Up @@ -382,6 +384,17 @@ class Mempool extends EventEmitter {
if (this.hasEntry(hash))
continue;

// Some covenants can only be used once per name per block.
// If the TX we want to re-insert into the mempool conflicts
// with another TX already in the mempool because of this rule,
// the solution is to evict the NEWER TX (the TX already in the
// mempool) and then insert the OLDER TX (from the disconnected block).
// Since the newer TX spends the output of the older TX, evicting the
// older TX but keeping the newer TX would leave the mempool in an
// invalid state, and the miner would produce invalid blocks.
if (this.contracts.hasNames(tx))
this.removeNamestateUpdates(tx);

try {
await this.insertTX(tx, -1);
total += 1;
Expand Down Expand Up @@ -777,6 +790,28 @@ class Mempool extends EventEmitter {
return Coin.fromTX(entry.tx, index, -1);
}

/**
* Check whether coin is still unspent.
* @param {Hash} hash
* @param {Number} index
* @returns {boolean}
*/

hasCoin(hash, index) {
const entry = this.map.get(hash);

if (!entry)
return false;

if (this.isSpent(hash, index))
return false;

if (index >= entry.tx.outputs.length)
return false;

return true;
}

/**
* Check to see if a coin has been spent. This differs from
* {@link ChainDB#isSpent} in that it actually maintains a
Expand Down Expand Up @@ -1829,6 +1864,37 @@ class Mempool extends EventEmitter {
}
}

/**
* Recursively remove child transactions where linked names are updated
* @private
* @param {TX} tx
*/

removeNamestateUpdates(tx) {
const names = new BufferSet();
rules.addNames(tx, names);
const hash = tx.hash();

for (let i = 0; i < tx.outputs.length; i++) {
const spender = this.getSpent(hash, i);

// No child in mempool spending this output
if (!spender)
continue;

// Child is not linked by name.
// Covenant rules don't prevent it from
// staying in the mempool.
if (!rules.hasNames(spender.tx, names))
continue;

// Bye-bye, try again later!
// (After parent is re-confirmed)
this.removeSpenders(spender);
this.removeEntry(spender);
}
}

/**
* Count the highest number of
* ancestors a transaction may have.
Expand Down Expand Up @@ -2360,6 +2426,8 @@ class Mempool extends EventEmitter {

/**
* Get coin viewpoint (lock).
* Note: this does not return the historical
* view of coins from the indexers
* @method
* @param {TX} tx
* @returns {Promise} - Returns {@link CoinView}.
Expand All @@ -2368,12 +2436,40 @@ class Mempool extends EventEmitter {
async getSpentView(tx) {
const unlock = await this.locker.lock();
try {
return await this.getCoinView(tx);
return await this._getSpentView(tx);
} finally {
unlock();
}
}

/**
* Get coin viewpoint
* @param {TX} tx
* @returns {Promise} - Returns {@link CoinView}
*/

async _getSpentView(tx) {
const view = new CoinView();

for (const {prevout} of tx.inputs) {
const {hash, index} = prevout;
const tx = this.getTX(hash);

if (tx) {
if (index < tx.outputs.length)
view.addIndex(tx, index, -1);
continue;
}

const coin = await this.chain.readCoin(prevout);

if (coin)
view.addEntry(prevout, coin);
}

return view;
}

/**
* Get coin viewpoint (no lock).
* @method
Expand All @@ -2389,7 +2485,7 @@ class Mempool extends EventEmitter {
const tx = this.getTX(hash);

if (tx) {
if (index < tx.outputs.length)
if (this.hasCoin(hash, index))
view.addIndex(tx, index, -1);
continue;
}
Expand Down Expand Up @@ -3046,7 +3142,7 @@ class Orphan {
* Create an orphan.
* @constructor
* @param {TX} tx
* @param {Hash[]} missing
* @param {Number} missing
* @param {Number} id
*/

Expand Down
21 changes: 11 additions & 10 deletions lib/protocol/networks.js
Original file line number Diff line number Diff line change
Expand Up @@ -785,18 +785,19 @@ regtest.txStart = 0;

regtest.names = {
auctionStart: 0,
rolloutInterval: 1000,
rolloutInterval: 2,
lockupPeriod: 2,
renewalWindow: 400,
renewalPeriod: 500,
renewalMaturity: 1,
renewalWindow: 5000,
renewalPeriod: 2500,
renewalMaturity: 50,
claimPeriod: 250000,
biddingPeriod: 50,
revealPeriod: 50,
treeInterval: 50,
transferLockup: 50,
revocationDelay: 50,
auctionMaturity: 50 + 50 + 50,
alexaLockupPeriod: 500000,
claimFrequency: 0,
biddingPeriod: 5,
revealPeriod: 10,
treeInterval: 5,
transferLockup: 10,
auctionMaturity: 5 + 10 + 50,
noRollout: false,
noReserved: false
};
Expand Down
1 change: 1 addition & 0 deletions lib/wallet/walletdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class WalletDB extends EventEmitter {
this.client.on('connect', async () => {
try {
await this.syncNode();
this.emit('sync done');
} catch (e) {
this.emit('error', e);
}
Expand Down
Loading