Skip to content

Commit

Permalink
mempool
Browse files Browse the repository at this point in the history
  • Loading branch information
zenywallet committed Jun 14, 2018
1 parent f237053 commit 0986231
Show file tree
Hide file tree
Showing 3 changed files with 295 additions and 8 deletions.
81 changes: 77 additions & 4 deletions ApiServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var bodyParser = require('body-parser');

function ApiServer(opts, libs) {
var db = libs.db;
var mempool = libs.mempool;
var app;

this.start = function() {
Expand All @@ -14,16 +15,88 @@ function ApiServer(opts, libs) {

async function get_addr(address) {
var utxos = await db.getUnspent(address);
var unconfs = mempool.unconfs(address);
var balance = 0;
for(var i in utxos) {
var utxo = utxos[i];
balance += utxo.value;
var unconf = 0;
var unconf_out = 0;
var unconf_in = 0;
var utxo_count = 0;

var txids = {};
if(utxos.length > 0) {
for(var i in utxos) {
var utxo = utxos[i];
balance += utxo.value;
txids[utxo.txid] = 1;
utxo_count++;
}
}

if(unconfs.txouts) {
var mempool_txouts = unconfs.txouts;
mempool_txouts = mempool_txouts.filter(function(txout) {
return !txids[txout.txid];
});
for(var i in mempool_txouts) {
var txout = mempool_txouts[i];
unconf_in += txout.value;
txids[txout.txid] = 1;
utxo_count++;
}
}

if(unconfs.spents) {
var mempool_spents = unconfs.spents;
mempool_spents = mempool_spents.filter(function(spent) {
return txids[spent.txid];
});
for(var i in mempool_spents) {
var spent = mempool_spents[i];
unconf_out -= spent.value;
utxo_count--;
}
}
return {balance: balance};

unconf = unconf_in + unconf_out;

return {balance: balance, unconf: unconf, unconf_out: unconf_out, unconf_in: unconf_in, utxo_count: utxo_count};
}

async function get_utxos(address) {
var utxos = await db.getUnspent(address);
var unconfs = mempool.unconfs(address);

if(unconfs.txouts) {
var txids = {};
for(var i in utxos) {
var utxo = utxos[i];
txids[utxo.txid] = 1;
}

var mempool_txouts = unconfs.txouts;
mempool_txouts = mempool_txouts.filter(function(txout) {
return !txids[txout.txid];
});
for(var i in mempool_txouts) {
var txout = mempool_txouts[i];
txids[txout.txid] = 1;
}

utxos = utxos.concat(mempool_txouts);
}

if(unconfs.spents) {
var mempool_spent_txids = {};
for(var i in unconfs.spents) {
var spent = unconfs.spents[i];
mempool_spent_txids[spent.txid] = 1;
}

utxos = utxos.filter(function(utxo) {
return !mempool_spent_txids[utxo.txid];
});
}

return utxos;
}

Expand Down
203 changes: 203 additions & 0 deletions MemPool.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
function MemPool(opts, libs) {
var bitcoin = libs.bitcoin;
var rpc = libs.rpc;
var db = libs.db;
var network = libs.network;

var rawmempool_rawtxs = {};
var rawmempool_rawtxobjs = {};
var rawmempool_txs = {};
var rawmempool_spents = {};
var rawmempool_txouts = {};
var rawmempool_addr_txouts = {};
var rawmempool_addr_spents = {};
var rawmempool_addr_warning = {};

var rawmempool_addr_txouts_cache = {};
var rawmempool_addr_spents_cache = {};
var rawmempool_addr_warning_cache = {};

this.unconfs = function(address) {
var txouts = rawmempool_addr_txouts_cache[address];
var spents = rawmempool_addr_spents_cache[address];
return {txouts: txouts, spents: spents};
}

function pushex(obj, key, value) {
if(!obj[key]) {
obj[key] = [value];
} else {
obj[key].push(value);
}
}

var update_flag = false;
var reset_flag = false;
this.update = async function(reset) {
if(update_flag) {
if(reset) {
reset_flag = true;
}
return;
}
update_flag = true;

var mempool = await rpc.getRawMemPool();

if(reset || reset_flag) {
rest_flag = false;

rawmempool_rawtxs_tmp = {};
for(var i in mempool) {
var txid = mempool[i];
if(rawmempool_rawtxs[txid]) {
rawmempool_rawtxs_tmp[txid] = rawmempool_rawtxs[txid];
}
}
rawmempool_rawtxs = rawmempool_rawtxs_tmp;
rawmempool_rawtxobjs_tmp = {};
for(var i in mempool) {
var txid = mempool[i];
if(rawmempool_rawtxobjs[txid]) {
rawmempool_rawtxobjs_tmp[txid] = rawmempool_rawtxobjs[txid];
}
}
rawmempool_rawtxobjs = rawmempool_rawtxobjs_tmp;
rawmempool_txs = {};
rawmempool_txouts = {};
rawmempool_spents = {};
rawmempool_addr_txouts = {};
rawmempool_addr_spents = {};
rawmempool_addr_warning = {};
}

for(var i in mempool) {
var txid = mempool[i];
if(rawmempool_txs[txid]) {
continue;
}

var rawtx = rawmempool_rawtxs[txid];
if(!rawtx) {
var rawtx = await rpc.getRawTransaction(txid); // Do not call multiple
if(!rawtx) {
continue;
}
rawmempool_rawtxs[txid] = rawtx;
}
}

await Promise.all(mempool.map(async function(txid) {
if(rawmempool_txs[txid]) {
return;
}

var tx = rawmempool_rawtxobjs[txid];
if(!tx) {
var rawtx = rawmempool_rawtxs[txid];
if(!rawtx) {
return;
}
tx = new bitcoin.Transaction.fromHex(rawtx);
rawmempool_rawtxobjs[txid] = tx;
}

tx.outs.map(function(output, n) {
var amount = output.value;
var out_txid_n = txid + '-' + n;
var txout_data = {txid: txid, n: n, value: amount};

var n_outs = {};
var address = null;
try {
address = bitcoin.address.fromOutputScript(output.script, network);
} catch(ex) {}

if(address) {
n_outs[address] = amount;
pushex(rawmempool_addr_txouts, address, txout_data);
} else {
var chunks;
chunks = bitcoin.script.decompile(output.script);
var find_count = 0;
for(var k in chunks) {
var chunk = chunks[k];
if(Buffer.isBuffer(chunk) && chunk.length !== 1) {
address = null;
try {
address = bitcoin.ECPair.fromPublicKeyBuffer(chunk, network).getAddress();
} catch(ex) {}

if(address) {
n_outs[address] = amount;
pushex(rawmempool_addr_txouts, address, txout_data);
find_count++;
}
}
}
if(find_count > 1) {
rawmempool_addr_warning[address] = 1;
}
if(!address) {
address = '#' + txid + '-' + n;
n_outs[address] = amount;
pushex(rawmempool_addr_txouts, address, txout_data);

var asm = bitcoin.script.toASM(chunks);
console.log("\rINFO: Unknown address asm=" + asm);
}
}
rawmempool_txouts[out_txid_n] = n_outs;
});

await Promise.all(tx.ins.map(async function(input) {
var in_txid = Buffer.from(input.hash).reverse().toString('hex');
var n = input.index;
var in_txid_n = in_txid + '-' + n;
if(n != 0xffffffff) {
var txout = await db.getTxout(in_txid, n);
if(txout) {
rawmempool_spents[in_txid_n] = 1;
for(var i in txout.addresses) {
var address = txout.addresses[i];
pushex(rawmempool_addr_spents, address, {txid: in_txid, n: n, value: txout.value});
}
} else {
var txout = await db.getTxout(input.hash.toString('hex'), n);
if(txout) {
console.log(txout);
abort();
}
var r_spent = rawmempool_spents[in_txid_n];
if(!r_spent) {
var txout_value = rawmempool_txouts[in_txid_n];
if(txout_value) {
for(var addr in txout_value) {
pushex(rawmempool_addr_spents, addr, txout_value[addr]);
}
rawmempool_spents[in_txid_n] = 1;
console.log("\rINFO: mempool spent=" + in_txid_n);
} else {
console.log("\rINFO: mempool vout not found " + in_txid_n);
}
}
}
}
}));

rawmempool_txs[txid] = 1;
}));
rawmempool_addr_txouts_cache = Object.assign({}, rawmempool_addr_txouts);
rawmempool_addr_spents_cache = Object.assign({}, rawmempool_addr_spents);
rawmempool_addr_warning_cache = Object.assign({}, rawmempool_addr_warning);

if(process.stdout.clearLine) {
process.stdout.clearLine();
process.stdout.write("\rmempool: count=" + Object.keys(rawmempool_txs).length);
}

update_flag = false;
}
}

module.exports = MemPool;
19 changes: 15 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ var opts = require('config');
var Rpc = require('./Rpc');
var bitcoin = require('bitcoinjs-lib');
var Db = require('./Db');
var MemPool = require('./MemPool');
var ApiServer = require('./ApiServer');
var rpc = new Rpc(opts);
rpc.cb = function(cmd, err, res) {
Expand All @@ -18,8 +19,6 @@ rpc.cb = function(cmd, err, res) {
return res;
}
var db = new Db(opts);
var apiserver = new ApiServer(opts, {db: db});

bitcoin.networks['bitzeny'] = {
messagePrefix: '\u0018Bitzeny Signed Message:\n',
bech32: 'sz',
Expand All @@ -32,6 +31,9 @@ bitcoin.networks['bitzeny'] = {
wif: 0x80
};
var network = bitcoin.networks['bitzeny'];
var mempool = new MemPool(opts, {bitcoin: bitcoin, rpc: rpc, db: db, network: network});
var apiserver = new ApiServer(opts, {db: db, mempool: mempool});


var aborting = false;
async function abort() {
Expand Down Expand Up @@ -240,6 +242,7 @@ async function block_check() {
}

async function block_sync(suppress) {
var new_block = false;
var hash = await rpc.getBlockHash(height > 0 ? ++height : 0);

while(hash && !aborting) {
Expand Down Expand Up @@ -283,20 +286,23 @@ async function block_sync(suppress) {
);

if(!suppress) {
console.log(timestamp() + ' #' + height + ' ' + hash + ' ' + timestamp(time));
console.log("\r" + timestamp() + ' #' + height + ' ' + hash + ' ' + timestamp(time));
}
prev_hash = hash;
} else {
block_check();
}

hash = await rpc.getBlockHash(++height);
new_block = true;
}


if(!hash && height > 0) {
height--;
}

return new_block;
}

;(async function() {
Expand All @@ -319,7 +325,12 @@ async function block_sync(suppress) {
async function worker() {
try {
await block_check();
await block_sync();
var new_block = await block_sync();
if(new_block) {
mempool.update(true);
} else {
mempool.update();
}

if(aborting) {
await abort();
Expand Down

0 comments on commit 0986231

Please sign in to comment.