fix address streamed data

This commit is contained in:
Manuel Araoz 2014-02-14 16:35:32 -03:00
parent b3ffb86a40
commit 5c9c7aeb5c
5 changed files with 484 additions and 423 deletions

View File

@ -41,7 +41,6 @@ module.exports.broadcastBlock = function(block) {
}; };
module.exports.broadcastAddressTx = function(address, tx) { module.exports.broadcastAddressTx = function(address, tx) {
console.log('bcatx = '+address+' '+tx);
if (ios) ios.sockets. in (address).emit(address, tx); if (ios) ios.sockets. in (address).emit(address, tx);
}; };

View File

@ -5,6 +5,7 @@ require('classtool');
function spec(b) { function spec(b) {
var superclass = b.superclass || require('events').EventEmitter;
var TIMESTAMP_PREFIX = 'bts-'; // b-ts-<ts> => <hash> var TIMESTAMP_PREFIX = 'bts-'; // b-ts-<ts> => <hash>
var PREV_PREFIX = 'bpr-'; // b-prev-<hash> => <prev_hash> var PREV_PREFIX = 'bpr-'; // b-prev-<hash> => <prev_hash>
var NEXT_PREFIX = 'bne-'; // b-next-<hash> => <next_hash> var NEXT_PREFIX = 'bne-'; // b-next-<hash> => <next_hash>
@ -22,7 +23,9 @@ function spec(b) {
var Rpc = b.rpc || require('./Rpc').class(); var Rpc = b.rpc || require('./Rpc').class();
var BlockDb = function() { var BlockDb = function() {
BlockDb.super(this, arguments);
}; };
BlockDb.superclass = superclass;
BlockDb.prototype.close = function(cb) { BlockDb.prototype.close = function(cb) {
db.close(cb); db.close(cb);
@ -42,6 +45,7 @@ function spec(b) {
// the block prev to the new block, nor TIP pointer // the block prev to the new block, nor TIP pointer
// //
BlockDb.prototype.add = function(b, cb) { BlockDb.prototype.add = function(b, cb) {
var self = this;
var time_key = TIMESTAMP_PREFIX + var time_key = TIMESTAMP_PREFIX +
( b.time || Math.round(new Date().getTime() / 1000) ); ( b.time || Math.round(new Date().getTime() / 1000) );
@ -49,7 +53,12 @@ function spec(b) {
.put(time_key, b.hash) .put(time_key, b.hash)
.put(MAIN_PREFIX + b.hash, 1) .put(MAIN_PREFIX + b.hash, 1)
.put(PREV_PREFIX + b.hash, b.previousblockhash) .put(PREV_PREFIX + b.hash, b.previousblockhash)
.write(cb); .write(function(err){
if (!err) {
self.emit('new_block', {blockid: b.hash});
}
cb(err);
});
}; };
BlockDb.prototype.getTip = function(cb) { BlockDb.prototype.getTip = function(cb) {

View File

@ -6,7 +6,6 @@ function spec() {
var CoinConst = require('bitcore/const'); var CoinConst = require('bitcore/const');
var coinUtil = require('bitcore/util/util'); var coinUtil = require('bitcore/util/util');
var Sync = require('./Sync').class(); var Sync = require('./Sync').class();
var Script = require('bitcore/Script').class();
var Peer = require('bitcore/Peer').class(); var Peer = require('bitcore/Peer').class();
var config = require('../config/config'); var config = require('../config/config');
var networks = require('bitcore/networks'); var networks = require('bitcore/networks');
@ -60,24 +59,12 @@ function spec() {
}; };
PeerSync.prototype.handleTx = function(info) { PeerSync.prototype.handleTx = function(info) {
var self =this;
var tx = info.message.tx.getStandardizedObject(); var tx = info.message.tx.getStandardizedObject();
tx.outs = info.message.tx.outs;
tx.ins = info.message.tx.ins;
console.log('[p2p_sync] Handle tx: ' + tx.hash); console.log('[p2p_sync] Handle tx: ' + tx.hash);
tx.time = tx.time || Math.round(new Date().getTime() / 1000); tx.time = tx.time || Math.round(new Date().getTime() / 1000);
var to=0;
info.message.tx.outs.forEach( function(o) {
var s = new Script(o.s);
var addrs = self.sync.getAddrStr(s);
// support only for p2pubkey p2pubkeyhash and p2sh
if (addrs.length === 1) {
tx.out[to].addrStr = addrs[0];
tx.out[to].n = to;
}
to++;
});
this.sync.storeTxs([tx], function(err) { this.sync.storeTxs([tx], function(err) {
if (err) { if (err) {
console.log('[p2p_sync] Error in handle TX: ' + JSON.stringify(err)); console.log('[p2p_sync] Error in handle TX: ' + JSON.stringify(err));

View File

@ -6,28 +6,24 @@ require('classtool');
function spec() { function spec() {
var sockets = require('../app/controllers/socket.js'); var sockets = require('../app/controllers/socket.js');
var BlockDb = require('./BlockDb').class(); var BlockDb = require('./BlockDb').class();
var bitutil = require('bitcore/util/util');
// This is 0.1.2 => c++ version of base57-native
var base58 = require('base58-native');
var encodedData = require('bitcore/util/EncodedData').class({base58: base58});
var versionedData = require('bitcore/util/VersionedData').class({superclass: encodedData});
var Address = require('bitcore/Address').class({superclass: versionedData});
var TransactionDb = require('./TransactionDb').class(); var TransactionDb = require('./TransactionDb').class();
var config = require('../config/config'); var config = require('../config/config');
var networks = require('bitcore/networks'); var networks = require('bitcore/networks');
var Script = require('bitcore/Script').class();
var async = require('async'); var async = require('async');
function Sync() { function Sync() {}
}
Sync.prototype.init = function(opts, cb) { Sync.prototype.init = function(opts, cb) {
var self = this; var self = this;
self.opts = opts; self.opts = opts;
this.bDb = new BlockDb(opts); this.bDb = new BlockDb(opts);
this.txDb = new TransactionDb(opts); this.txDb = new TransactionDb(opts);
this.txDb.on('tx_for_address', this.handleTxForAddress.bind(this));
this.txDb.on('new_tx', this.handleNewTx.bind(this));
this.bDb.on('new_block', this.handleNewBlock.bind(this));
this.network = config.network === 'testnet' ? networks.testnet : networks.livenet; this.network = config.network === 'testnet' ? networks.testnet : networks.livenet;
return cb(); return cb();
}; };
@ -43,8 +39,13 @@ function spec() {
Sync.prototype.destroy = function(next) { Sync.prototype.destroy = function(next) {
var self = this; var self = this;
async.series([ async.series([
function(b) { self.bDb.drop(b); },
function(b) { self.txDb.drop(b); }, function(b) {
self.bDb.drop(b);
},
function(b) {
self.txDb.drop(b);
},
], next); ], next);
}; };
@ -88,9 +89,9 @@ function spec() {
var self = this; var self = this;
var oldTip, oldNext, needReorg = false; var oldTip, oldNext, needReorg = false;
var newPrev = b.previousblockhash; var newPrev = b.previousblockhash;
var updatedAddrs;
async.series([ async.series([
function(c) { function(c) {
self.bDb.has(b.hash, function(err, val) { self.bDb.has(b.hash, function(err, val) {
return c(err || return c(err ||
@ -107,8 +108,7 @@ function spec() {
}); });
}, },
function(c) { function(c) {
self.txDb.createFromBlock(b, function(err, addrs) { self.txDb.createFromBlock(b, function(err) {
updatedAddrs = addrs;
return c(err); return c(err);
}); });
}, },
@ -144,9 +144,9 @@ function spec() {
return c(err); return c(err);
}); });
}); });
}], }
],
function(err) { function(err) {
if (!err) self._handleBroadcast(b.hash, null, updatedAddrs);
if (err && err.toString().match(/WARN/)) { if (err && err.toString().match(/WARN/)) {
err = null; err = null;
} }
@ -162,6 +162,7 @@ function spec() {
var orphanizeFrom; var orphanizeFrom;
async.series([ async.series([
function(c) { function(c) {
self.bDb.isMain(newPrev, function(err, val) { self.bDb.isMain(newPrev, function(err, val) {
if (!val) return c(); if (!val) return c();
@ -211,7 +212,9 @@ function spec() {
hashInterator = fromHash; hashInterator = fromHash;
async.whilst( async.whilst(
function() { return hashInterator; }, function() {
return hashInterator;
},
function(c) { function(c) {
self.setBlockMain(hashInterator, false, function(err) { self.setBlockMain(hashInterator, false, function(err) {
if (err) return cb(err); if (err) return cb(err);
@ -244,7 +247,9 @@ function spec() {
}); });
}); });
}, },
function() { return hashInterator && !isMain; }, function() {
return hashInterator && !isMain;
},
function(err) { function(err) {
console.log('\tFound yBlock:', hashInterator); console.log('\tFound yBlock:', hashInterator);
return cb(err, hashInterator, lastHash); return cb(err, hashInterator, lastHash);
@ -252,79 +257,39 @@ function spec() {
); );
}; };
Sync.prototype._handleBroadcast = function(hash, updatedTxs, updatedAddrs) { Sync.prototype._handleBroadcast = function() {
var self = this; var self = this;
console.log('broadcast:' + self.opts.shouldBroadcast);
};
if (self.opts.shouldBroadcast) {
if (hash) {
sockets.broadcastBlock(hash);
}
if (updatedTxs) { Sync.prototype.handleTxForAddress = function(data) {
updatedTxs.forEach(function(tx) { if (this.opts.shouldBroadcast) {
sockets.broadcastTx(tx); sockets.broadcastAddressTx(data.address, data.txid);
});
} }
};
if (updatedAddrs ) { Sync.prototype.handleNewTx = function(data) {
updatedAddrs.forEach(function(addr, txs){ if (this.opts.shouldBroadcast) {
txs.forEach(function(addr, t){ sockets.broadcastTx(data.txid);
sockets.broadcastAddressTx(addr, t);
});
});
} }
};
Sync.prototype.handleNewBlock = function(data) {
if (this.opts.shouldBroadcast) {
sockets.broadcastBlock(data.blockid);
} }
}; };
Sync.prototype.storeTxs = function(txs, cb) { Sync.prototype.storeTxs = function(txs, cb) {
var self = this; var self = this;
self.txDb.createFromArray(txs, null, function(err) {
self.txDb.createFromArray(txs, null, function(err, updatedAddrs) {
if (err) return cb(err); if (err) return cb(err);
self._handleBroadcast(null, txs, updatedAddrs);
return cb(err); return cb(err);
}); });
}; };
// TODO. replace with
// Script.prototype.getAddrStrs if that one get merged in bitcore
Sync.prototype.getAddrStr = function(s) {
var self = this;
var addrStrs = [];
var type = s.classify();
var addr;
switch(type) {
case Script.TX_PUBKEY:
var chunk = s.captureOne();
addr = new Address(self.network.addressPubkey, bitutil.sha256ripe160(chunk));
addrStrs = [ addr.toString() ];
break;
case Script.TX_PUBKEYHASH:
addr = new Address(self.network.addressPubkey, s.captureOne());
addrStrs = [ addr.toString() ];
break;
case Script.TX_SCRIPTHASH:
addr = new Address(self.network.addressScript, s.captureOne());
addrStrs = [ addr.toString() ];
break;
case Script.TX_MULTISIG:
var chunks = s.capture();
chunks.forEach(function(chunk) {
var a = new Address(self.network.addressPubkey, bitutil.sha256ripe160(chunk));
addrStrs.push(a.toString());
});
break;
case Script.TX_UNKNOWN:
break;
}
return addrStrs;
};
return Sync; return Sync;
} }
module.defineClass(spec); module.defineClass(spec);

View File

@ -5,6 +5,7 @@ require('classtool');
function spec(b) { function spec(b) {
var superclass = b.superclass || require('events').EventEmitter;
// blockHash -> txid mapping // blockHash -> txid mapping
var IN_BLK_PREFIX = 'txb-'; //txb-<txid>-<block> => 1/0 (connected or not) var IN_BLK_PREFIX = 'txb-'; //txb-<txid>-<block> => 1/0 (connected or not)
@ -32,9 +33,27 @@ function spec(b) {
config = require('../config/config'), config = require('../config/config'),
assert = require('assert'); assert = require('assert');
var db = b.db || levelup(config.leveldb + '/txs'); var db = b.db || levelup(config.leveldb + '/txs');
var Script = require('bitcore/Script').class();
// This is 0.1.2 => c++ version of base57-native
var base58 = require('base58-native');
var encodedData = require('bitcore/util/EncodedData').class({
// TODO: check why c++ implementation differs
//base58: base58
});
var versionedData = require('bitcore/util/VersionedData').class({
superclass: encodedData
});
var Address = require('bitcore/Address').class({
superclass: versionedData
});
var bitutil = require('bitcore/util/util');
var networks = require('bitcore/networks');
var TransactionDb = function() { var TransactionDb = function() {
TransactionDb.super(this, arguments);
this.network = config.network === 'testnet' ? networks.testnet : networks.livenet;
}; };
TransactionDb.superclass = superclass;
TransactionDb.prototype.close = function(cb) { TransactionDb.prototype.close = function(cb) {
db.close(cb); db.close(cb);
@ -81,8 +100,7 @@ function spec(b) {
txid: txid, txid: txid,
index: parseInt(index), index: parseInt(index),
}); });
} } else {
else {
r.spendTxId = txid; r.spendTxId = txid;
r.spendIndex = parseInt(index); r.spendIndex = parseInt(index);
r.spendTs = parseInt(ts); r.spendTs = parseInt(ts);
@ -99,7 +117,10 @@ function spec(b) {
var i = 0; var i = 0;
// outs. // outs.
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({
start: k,
end: k + '~'
})
.on('data', function(data) { .on('data', function(data) {
var k = data.key.split('-'); var k = data.key.split('-');
var v = data.value.split(':'); var v = data.value.split(':');
@ -116,7 +137,10 @@ function spec(b) {
.on('end', function() { .on('end', function() {
var k = SPEND_PREFIX + txid; var k = SPEND_PREFIX + txid;
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({
start: k,
end: k + '~'
})
.on('data', function(data) { .on('data', function(data) {
var k = data.key.split('-'); var k = data.key.split('-');
var j = idx[parseInt(k[2])]; var j = idx[parseInt(k[2])];
@ -142,7 +166,10 @@ function spec(b) {
if (!info) return cb(); if (!info) return cb();
var k = SPEND_PREFIX + info.txid; var k = SPEND_PREFIX + info.txid;
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({
start: k,
end: k + '~'
})
.on('data', function(data) { .on('data', function(data) {
var k = data.key.split('-'); var k = data.key.split('-');
self._addSpendInfo(info.vout[k[2]], k[3], k[4], data.value); self._addSpendInfo(info.vout[k[2]], k[3], k[4], data.value);
@ -181,8 +208,7 @@ function spec(b) {
i.value = ret.valueSat / util.COIN; i.value = ret.valueSat / util.COIN;
// Double spend? // Double spend?
if ( ret.multipleSpendAttempt || if (ret.multipleSpendAttempt || !ret.spendTxId ||
!ret.spendTxId ||
(ret.spendTxId && ret.spendTxId !== info.txid) (ret.spendTxId && ret.spendTxId !== info.txid)
) { ) {
if (ret.multipleSpendAttempts) { if (ret.multipleSpendAttempts) {
@ -192,16 +218,13 @@ function spec(b) {
i.doubleSpendIndex = ret.spendIndex; i.doubleSpendIndex = ret.spendIndex;
} }
}); });
} } else if (!ret.spendTxId) {
else if (!ret.spendTxId) {
i.dbError = 'Input spend not registered'; i.dbError = 'Input spend not registered';
} } else {
else {
i.doubleSpendTxID = ret.spendTxId; i.doubleSpendTxID = ret.spendTxId;
i.doubleSpendIndex = ret.spendIndex; i.doubleSpendIndex = ret.spendIndex;
} }
} } else {
else {
i.doubleSpendTxID = null; i.doubleSpendTxID = null;
} }
@ -213,8 +236,7 @@ function spec(b) {
if (!incompleteInputs) { if (!incompleteInputs) {
info.valueIn = valueIn / util.COIN; info.valueIn = valueIn / util.COIN;
info.fees = (valueIn - parseInt(info.valueOut * util.COIN)) / util.COIN; info.fees = (valueIn - parseInt(info.valueOut * util.COIN)) / util.COIN;
} } else {
else {
info.incompleteInputs = 1; info.incompleteInputs = 1;
} }
return cb(); return cb();
@ -242,7 +264,10 @@ function spec(b) {
self._getInfo(txid, function(err, info) { self._getInfo(txid, function(err, info) {
if (err) return cb(err); if (err) return cb(err);
if (!info) return cb(); if (!info) return cb();
return cb(err, {txid: txid, info: info} ); return cb(err, {
txid: txid,
info: info
});
}); });
}; };
@ -252,7 +277,9 @@ function spec(b) {
db.get(k, function(err, val) { db.get(k, function(err, val) {
if (!val || (err && err.notFound)) { if (!val || (err && err.notFound)) {
return cb(null, { unconfirmedInput: 1} ); return cb(null, {
unconfirmedInput: 1
});
} }
var a = val.split(':'); var a = val.split(':');
@ -263,7 +290,10 @@ function spec(b) {
// Spend? // Spend?
var k = SPEND_PREFIX + txid + '-' + n; var k = SPEND_PREFIX + txid + '-' + n;
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({
start: k,
end: k + '~'
})
.on('data', function(data) { .on('data', function(data) {
var k = data.key.split('-'); var k = data.key.split('-');
self._addSpendInfo(ret, k[3], k[4], data.value); self._addSpendInfo(ret, k[3], k[4], data.value);
@ -300,8 +330,7 @@ function spec(b) {
return e_c(); return e_c();
}); });
}, cb); }, cb);
} } else {
else {
self.isConfirmed(o.spendTxId, function(err, is) { self.isConfirmed(o.spendTxId, function(err, is) {
if (err) return cb(err); if (err) return cb(err);
o.spendIsConfirmed = is; o.spendIsConfirmed = is;
@ -317,7 +346,10 @@ function spec(b) {
var k = ADDR_PREFIX + addr; var k = ADDR_PREFIX + addr;
var ret = []; var ret = [];
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({
start: k,
end: k + '~'
})
.on('data', function(data) { .on('data', function(data) {
var k = data.key.split('-'); var k = data.key.split('-');
var v = data.value.split(':'); var v = data.value.split(':');
@ -335,7 +367,10 @@ function spec(b) {
async.each(ret, function(o, e_c) { async.each(ret, function(o, e_c) {
var k = SPEND_PREFIX + o.txid + '-' + o.index; var k = SPEND_PREFIX + o.txid + '-' + o.index;
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({
start: k,
end: k + '~'
})
.on('data', function(data) { .on('data', function(data) {
var k = data.key.split('-'); var k = data.key.split('-');
self._addSpendInfo(o, k[3], k[4], data.value); self._addSpendInfo(o, k[3], k[4], data.value);
@ -362,12 +397,15 @@ function spec(b) {
TransactionDb.prototype.removeFromTxId = function(txid, cb) { TransactionDb.prototype.removeFromTxId = function(txid, cb) {
async.series([ async.series([
function(c) { function(c) {
db.createReadStream({ db.createReadStream({
start: OUTS_PREFIX + txid, start: OUTS_PREFIX + txid,
end: OUTS_PREFIX + txid + '~', end: OUTS_PREFIX + txid + '~',
}).pipe( }).pipe(
db.createWriteStream({type:'del'}) db.createWriteStream({
type: 'del'
})
).on('close', c); ).on('close', c);
}, },
function(c) { function(c) {
@ -376,9 +414,12 @@ function spec(b) {
end: SPEND_PREFIX + txid + '~' end: SPEND_PREFIX + txid + '~'
}) })
.pipe( .pipe(
db.createWriteStream({type:'del'}) db.createWriteStream({
type: 'del'
})
).on('close', c); ).on('close', c);
}], }
],
function(err) { function(err) {
cb(err); cb(err);
}); });
@ -386,20 +427,70 @@ function spec(b) {
}; };
// TODO. replace with
// Script.prototype.getAddrStrs if that one get merged in bitcore
TransactionDb.prototype.getAddrStr = function(s) {
var self = this;
var addrStrs = [];
var type = s.classify();
var addr;
switch (type) {
case Script.TX_PUBKEY:
var chunk = s.captureOne();
addr = new Address(self.network.addressPubkey, bitutil.sha256ripe160(chunk));
addrStrs.push(addr.toString());
break;
case Script.TX_PUBKEYHASH:
addr = new Address(self.network.addressPubkey, s.captureOne());
addrStrs.push(addr.toString());
break;
case Script.TX_SCRIPTHASH:
addr = new Address(self.network.addressScript, s.captureOne());
addrStrs.push(addr.toString());
break;
case Script.TX_MULTISIG:
var chunks = s.capture();
chunks.forEach(function(chunk) {
var a = new Address(self.network.addressPubkey, bitutil.sha256ripe160(chunk));
addrStrs.push(a.toString());
});
break;
case Script.TX_UNKNOWN:
break;
}
return addrStrs;
};
TransactionDb.prototype.adaptTxObject = function(txInfo) { TransactionDb.prototype.adaptTxObject = function(txInfo) {
var self = this;
// adapt bitcore TX object to bitcoind JSON response // adapt bitcore TX object to bitcoind JSON response
txInfo.txid = txInfo.hash; txInfo.txid = txInfo.hash;
var to=0;
var tx = txInfo;
tx.outs.forEach( function(o) {
var s = new Script(o.s);
var addrs = self.getAddrStr(s);
// support only for p2pubkey p2pubkeyhash and p2sh
if (addrs.length === 1) {
tx.out[to].addrStr = addrs[0];
tx.out[to].n = to;
}
to++;
});
var count = 0; var count = 0;
txInfo.vin = txInfo.in.map(function(txin) { txInfo.vin = txInfo.in.map(function(txin) {
var i = {}; var i = {};
if (txin.coinbase) { if (txin.coinbase) {
txInfo.isCoinBase = true; txInfo.isCoinBase = true;
} } else {
else {
i.txid = txin.prev_out.hash; i.txid = txin.prev_out.hash;
i.vout = txin.prev_out.n; i.vout = txin.prev_out.n;
} }
@ -434,7 +525,7 @@ function spec(b) {
var ts = tx.time; var ts = tx.time;
async.series([ async.series([
// Input Outpoints (mark them as spended) // Input Outpoints (mark them as spent)
function(p_c) { function(p_c) {
if (tx.isCoinBase) return p_c(); if (tx.isCoinBase) return p_c();
async.forEachLimit(tx.vin, CONCURRENCY, async.forEachLimit(tx.vin, CONCURRENCY,
@ -454,17 +545,15 @@ function spec(b) {
function(o, next_out) { function(o, next_out) {
if (o.value && o.scriptPubKey && if (o.value && o.scriptPubKey &&
o.scriptPubKey.addresses && o.scriptPubKey.addresses &&
o.scriptPubKey.addresses[0] && o.scriptPubKey.addresses[0] && !o.scriptPubKey.addresses[1] // TODO : not supported
! o.scriptPubKey.addresses[1] // TODO : not supported
) { ) {
// This is only to broadcast (WIP)
if (addrs.indexOf(o.scriptPubKey.addresses[0]) === -1) {
addrs.push(o.scriptPubKey.addresses[0]);
}
var addr = o.scriptPubKey.addresses[0]; var addr = o.scriptPubKey.addresses[0];
var sat = Math.round(o.value * util.COIN); var sat = Math.round(o.value * util.COIN);
if (addrs.indexOf(addr) === -1) {
addrs.push(addr);
}
// existed? // existed?
var k = OUTS_PREFIX + tx.txid + '-' + o.n; var k = OUTS_PREFIX + tx.txid + '-' + o.n;
db.get(k, function(err) { db.get(k, function(err) {
@ -473,14 +562,11 @@ function spec(b) {
.put(k, addr + ':' + sat) .put(k, addr + ':' + sat)
.put(ADDR_PREFIX + addr + '-' + tx.txid + '-' + o.n, sat + ':' + ts) .put(ADDR_PREFIX + addr + '-' + tx.txid + '-' + o.n, sat + ':' + ts)
.write(next_out); .write(next_out);
} } else {
else {
return next_out(); return next_out();
} }
}); });
} } else {
else {
//console.log ('WARN in TX: %s could not parse OUTPUT %d', tx.txid, o.n);
return next_out(); return next_out();
} }
}, },
@ -493,11 +579,26 @@ function spec(b) {
}); });
}, },
function(p_c) { function(p_c) {
if (!blockhash) return p_c(); if (!blockhash) {
return p_c();
}
return self.setConfirmation(tx.txid, blockhash, true, p_c); return self.setConfirmation(tx.txid, blockhash, true, p_c);
}, },
], function(err) { ], function(err) {
return cb(err, addrs); if (addrs.length > 0 && !blockhash) {
// only emit if we are processing a single tx (not from a block)
addrs.forEach(function(addr) {
self.emit('tx_for_address', {
address: addr,
txid: tx.txid
});
});
}
self.emit('new_tx', {
txid: tx.txid
});
return cb(err);
}); });
}; };
@ -520,7 +621,10 @@ function spec(b) {
var k = IN_BLK_PREFIX + txId; var k = IN_BLK_PREFIX + txId;
var ret = false; var ret = false;
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({
start: k,
end: k + '~'
})
.on('data', function(data) { .on('data', function(data) {
if (data.value === '1') ret = true; if (data.value === '1') ret = true;
}) })
@ -539,7 +643,10 @@ function spec(b) {
var k = FROM_BLK_PREFIX + hash; var k = FROM_BLK_PREFIX + hash;
var k2 = IN_BLK_PREFIX; var k2 = IN_BLK_PREFIX;
// This is slow, but prevent us to create a new block->tx index. // This is slow, but prevent us to create a new block->tx index.
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({
start: k,
end: k + '~'
})
.on('data', function(data) { .on('data', function(data) {
var ks = data.key.split('-'); var ks = data.key.split('-');
toChange.push({ toChange.push({
@ -561,15 +668,10 @@ function spec(b) {
// txs can be a [hashes] or [txObjects] // txs can be a [hashes] or [txObjects]
TransactionDb.prototype.createFromArray = function(txs, blockHash, next) { TransactionDb.prototype.createFromArray = function(txs, blockHash, next) {
var self = this; var self = this;
if (!txs) return next(); if (!txs) return next();
var updatedAddrs = []; // TODO
async.forEachLimit(txs, CONCURRENCY, function(t, each_cb) { async.forEachLimit(txs, CONCURRENCY, function(t, each_cb) {
if (typeof t === 'string') { if (typeof t === 'string') {
// Is it from genesis block? (testnet==livenet)
// TODO: parse it from networks.genesisTX? // TODO: parse it from networks.genesisTX?
if (t === genesisTXID) return each_cb(); if (t === genesisTXID) return each_cb();
@ -578,13 +680,12 @@ function spec(b) {
return self.add(inInfo, blockHash, each_cb); return self.add(inInfo, blockHash, each_cb);
}); });
} } else {
else {
return self.add(t, blockHash, each_cb); return self.add(t, blockHash, each_cb);
} }
}, },
function(err) { function(err) {
return next(err, updatedAddrs); return next(err);
}); });
}; };