'use strict'; require('classtool'); function spec(b) { // blockHash -> txid mapping var IN_BLK_PREFIX = 'tx-b-'; //tx-b-- => 1/0 (connected or not) // Only for orphan blocks // var FROM_BLK_PREFIX = 'tx-'; //tx-- => 1/0 (connected or not) // to show tx outs var OUTS_PREFIX = 'txouts-'; //txouts-- => [addr, btc_sat] // to sum up addr balance var ADDR_PREFIX = 'txouts-addr-'; //txouts-addr---- => + btc_sat var SPEND_PREFIX = 'txouts-spend-';//txouts-spend-- => [txid(in),n(in),ts] // TODO: use bitcore networks module var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'; var CONCURRENCY = 100; /** * Module dependencies. */ var TransactionRpc = require('./TransactionRpc').class(), util = require('bitcore/util/util'), levelup = require('levelup'), async = require('async'), config = require('../config/config'), assert = require('assert'); var db = b.db || levelup(config.leveldb + '/txs'); var TransactionDb = function() { }; TransactionDb.prototype.close = function(cb) { db.close(cb); }; TransactionDb.prototype.drop = function(cb) { var path = config.leveldb + '/txs'; db.close(function() { require('leveldown').destroy(path, function () { db = levelup(path); return cb(); }); }); }; // TransactionDb.prototype.fromTxIdOne = function(txid, cb) { TODO TransactionDb.prototype.has = function(txid, cb) { var k = OUTS_PREFIX + txid; db.get(k, function (err,val) { var ret; if (err && err.notFound) { err = null; ret = false; } if (typeof val !== undefined) { ret = true; } return cb(err, ret); }); }; TransactionDb.prototype.fromTxId = function(txid, cb) { var k = OUTS_PREFIX + txid; var ret=[]; // outs. db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); var v = data.value.split(':'); ret.push({ addr: v[0], value_sat: parseInt(v[1]), index: parseInt(k[2]), }); }) .on('error', function (err) { return cb(err); }) .on('end', function () { var k = SPEND_PREFIX + txid; var l = ret.length; db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); var v = data.value.split(':'); var set=0; for(var i=0; itx index. db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { if (data.key.indexOf(hash)>=0) toChange.push({ type: 'put', key: data.key, value: isMain?1:0, }); }) .on('error', function (err) { return cb(err); }) .on('end', function (err) { if (err) return cb(err); console.log('\t%s %d Txs', isMain?'Confirming':'Invalidating',toChange.length); db.batch(toChange, cb); }); }; // txs can be a [hashes] or [txObjects] TransactionDb.prototype.createFromArray = function(txs, blockHash, next) { var self = this; if (!txs) return next(); var updatedAddrs = []; // TODO async.forEachLimit(txs, CONCURRENCY, function(t, each_cb) { if (typeof t === 'string') { // Is it from genesis block? (testnet==livenet) // TODO: parse it from networks.genesisTX? if (t === genesisTXID) return each_cb(); TransactionRpc.getRpcInfo(t, function(err, inInfo) { if (!inInfo) return each_cb(err); return self.add(inInfo, blockHash, each_cb); }); } else { return self.add(t, blockHash, each_cb); } }, function(err) { return next(err, updatedAddrs); }); }; TransactionDb.prototype.createFromBlock = function(b, next) { var self = this; if (!b || !b.tx) return next(); return self.createFromArray(b.tx, b.hash, next); }; TransactionDb.prototype.setOrphan = function(blockHash, next) { // var self = this; //Get Txs // TODO //Mark Tx's output as fromOrphan //Mark Tx's outpoiunt as fromOrphan. Undo spents return next(); }; return TransactionDb; } module.defineClass(spec);