Gustavo Cortez
11 years ago
36 changed files with 1110 additions and 336 deletions
@ -0,0 +1,11 @@ |
|||
--extra=+f |
|||
--exclude=*jquery* |
|||
--exclude=node_modules/a* |
|||
--exclude=node_modules/[c-z]* |
|||
--exclude=*grunt* |
|||
--exclude=*bower* |
|||
--exclude=.swp |
|||
--exclude=public |
|||
--links=yes |
|||
--totals=yes |
|||
|
@ -1,213 +0,0 @@ |
|||
require('classtool'); |
|||
|
|||
function ClassSpec(b) { |
|||
var assert = require('assert'); |
|||
var fs = require('fs'); |
|||
var Block = require('bitcore/Block').class(); |
|||
var Deserialize = require('bitcore/Deserialize'); |
|||
var Parser = require('bitcore/util/BinaryParser').class(); |
|||
var coinUtil = require('bitcore/util/util'); |
|||
|
|||
function HeaderDB(b) { |
|||
this.network = b.network; |
|||
this.fd = null; |
|||
this.blocks = {}; |
|||
this.byHeight = []; |
|||
this.bestBlock = null; |
|||
this.cached_size = 0; |
|||
} |
|||
|
|||
HeaderDB.prototype.size = function() { |
|||
this.cached_size = Object.keys(this.blocks).length; |
|||
return this.cached_size; |
|||
}; |
|||
|
|||
HeaderDB.prototype.locator = function(block) { |
|||
if (!block) |
|||
block = this.bestBlock; |
|||
|
|||
var step = 1; |
|||
var start = 0; |
|||
var loc = []; |
|||
// see https://en.bitcoin.it/wiki/Protocol_specification#getblocks
|
|||
for (var i = block.height; i > 0; i -= step, ++start) { |
|||
if (start >= 10) |
|||
step *= 2; |
|||
loc.push(this.byHeight[i]); |
|||
} |
|||
assert.equal(this.byHeight[0].toString(), |
|||
this.network.genesisBlock.hash.toString()); |
|||
loc.push(this.byHeight[0]); |
|||
//console.log('Requesting more headers. Current height: ' + block.height );
|
|||
return loc; |
|||
}; |
|||
|
|||
HeaderDB.prototype.add = function(block) { |
|||
var hash = block.calcHash(); |
|||
block.hash = hash; |
|||
var curWork = Deserialize.intFromCompact(block.bits); |
|||
|
|||
if (hash in this.blocks) { |
|||
var old = this.blocks[hash]; |
|||
throw new Error('duplicate block (was at height ' + old.height + ')'); |
|||
} |
|||
|
|||
var bestChain = false; |
|||
|
|||
var reorg = { |
|||
oldBest: null, |
|||
conn: 0, |
|||
disconn: 0, |
|||
}; |
|||
|
|||
if (this.cached_size == 0) { |
|||
if (this.network.genesisBlock.hash.toString() != |
|||
hash.toString()) |
|||
throw new Error('Invalid genesis block'); |
|||
|
|||
block.height = 0; |
|||
block.work = curWork; |
|||
bestChain = true; |
|||
this.cached_size++; |
|||
} else { |
|||
var prevBlock = this.blocks[block.prev_hash]; |
|||
if (!prevBlock) |
|||
throw new Error('orphan block; prev not found'); |
|||
|
|||
block.height = prevBlock.height + 1; |
|||
block.work = prevBlock.work + curWork; |
|||
this.cached_size++; |
|||
|
|||
if (block.work > this.bestBlock.work) |
|||
bestChain = true; |
|||
} |
|||
|
|||
|
|||
// add to by-hash index
|
|||
this.blocks[hash] = block; |
|||
|
|||
if (bestChain) { |
|||
var oldBest = this.bestBlock; |
|||
var newBest = block; |
|||
|
|||
reorg.oldBest = oldBest; |
|||
|
|||
// likely case: new best chain has greater height
|
|||
if (!oldBest) { |
|||
while (newBest) { |
|||
newBest = this.blocks[newBest.prev_hash]; |
|||
reorg.conn++; |
|||
} |
|||
} else { |
|||
while (newBest && |
|||
(newBest.height > oldBest.height)) { |
|||
newBest = this.blocks[newBest.prev_hash]; |
|||
reorg.conn++; |
|||
} |
|||
} |
|||
|
|||
// unlikely: old best chain has greater height
|
|||
while (oldBest && newBest && |
|||
(oldBest.height > newBest.height)) { |
|||
oldBest = this.blocks[oldBest.prev_hash]; |
|||
reorg.disconn++; |
|||
} |
|||
|
|||
// height matches, but still walking parallel
|
|||
while (oldBest && newBest && (oldBest != newBest)) { |
|||
newBest = this.blocks[newBest.prev_hash]; |
|||
reorg.conn++; |
|||
|
|||
oldBest = this.blocks[oldBest.prev_hash]; |
|||
reorg.disconn++; |
|||
} |
|||
|
|||
var shuf = (reorg.conn > reorg.disconn) ? |
|||
reorg.conn : reorg.disconn; |
|||
|
|||
// reorg analyzed, updated best-chain pointer
|
|||
this.bestBlock = block; |
|||
|
|||
// update by-height index
|
|||
var ptr = block; |
|||
var updated = []; |
|||
for (var idx = block.height; |
|||
idx > (block.height - shuf); idx--) { |
|||
if (idx < 0) |
|||
break; |
|||
var update = [ idx, ptr ]; |
|||
updated.push(update); |
|||
ptr = this.blocks[ptr.prev_hash]; |
|||
} |
|||
|
|||
updated.reverse(); |
|||
|
|||
for (var i = 0; i < updated.length; i++) { |
|||
var update = updated[i]; |
|||
var idx = update[0]; |
|||
var ptr = update[1]; |
|||
|
|||
if (idx < this.byHeight.length) |
|||
this.byHeight[idx] = ptr.hash; |
|||
else |
|||
this.byHeight.push(ptr.hash); |
|||
} |
|||
} |
|||
return reorg; |
|||
}; |
|||
|
|||
HeaderDB.prototype.addBuf = function(buf) { |
|||
var block = new Block(); |
|||
var parser = new Parser(buf); |
|||
block.parse(parser, true); |
|||
this.add(block); |
|||
|
|||
}; |
|||
|
|||
|
|||
HeaderDB.prototype.readFile = function(filename) { |
|||
var fd = fs.openSync(filename, 'r'); |
|||
var stats = fs.fstatSync(fd); |
|||
if (stats.size % 80 != 0) |
|||
throw new Error('Corrupted header db'); |
|||
|
|||
while (1) { |
|||
var buf = new Buffer(80); |
|||
var bread = fs.readSync(fd, buf, 0, 80, null); |
|||
if (bread < 80) |
|||
break; |
|||
|
|||
this.addBuf(buf); |
|||
|
|||
if ( ! ( this.cached_size % 1000 )) { |
|||
console.log('\tblock...' + this.cached_size ) ; |
|||
} |
|||
} |
|||
|
|||
fs.closeSync(fd); |
|||
}; |
|||
|
|||
HeaderDB.prototype.writeFile = function(filename) { |
|||
var block = this.bestBlock; |
|||
var data = []; |
|||
while (block) { |
|||
var s = block.getHeader(); |
|||
data.push(s); |
|||
block = this.blocks[block.prev_hash]; |
|||
} |
|||
|
|||
data.reverse(); |
|||
|
|||
var fd = fs.openSync(filename, 'w'); |
|||
|
|||
data.forEach(function(datum) { |
|||
fs.writeSync(fd, datum, 0, 80, null); |
|||
}); |
|||
|
|||
fs.closeSync(fd); |
|||
}; |
|||
|
|||
return HeaderDB; |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
|
@ -0,0 +1,37 @@ |
|||
'use strict'; |
|||
|
|||
/** |
|||
* Module dependencies. |
|||
*/ |
|||
|
|||
var Address = require('../models/Address'); |
|||
|
|||
|
|||
/** |
|||
* Find block by hash ... |
|||
*/ |
|||
exports.address = function(req, res, next, addr) { |
|||
var a = Address.new(addr); |
|||
|
|||
a.update(function(err) { |
|||
if (err && !a.totalReceivedSat) { |
|||
console.log(err); |
|||
res.status(404).send('Invalid address'); |
|||
return next(); |
|||
} |
|||
|
|||
req.address = a; |
|||
return next(); |
|||
}); |
|||
}; |
|||
|
|||
|
|||
/** |
|||
* Show block |
|||
*/ |
|||
exports.show = function(req, res) { |
|||
if (req.address) { |
|||
res.jsonp(req.address); |
|||
} |
|||
}; |
|||
|
@ -0,0 +1,127 @@ |
|||
'use strict'; |
|||
|
|||
require('classtool'); |
|||
|
|||
|
|||
function spec() { |
|||
var async = require('async'); |
|||
var TransactionItem = require('./TransactionItem'); |
|||
var BitcoreAddress = require('bitcore/Address').class(); |
|||
var BitcoreUtil = require('bitcore/util/util'); |
|||
|
|||
function Address(addrStr) { |
|||
this.balanceSat = 0; |
|||
this.totalReceivedSat = 0; |
|||
this.totalSentSat = 0; |
|||
this.txApperances = 0; |
|||
|
|||
// TODO store only txids? +index? +all?
|
|||
this.transactions = []; |
|||
|
|||
var a = new BitcoreAddress(addrStr); |
|||
try { |
|||
a.validate(); |
|||
this.addrStr = addrStr; |
|||
} catch(e){ |
|||
} |
|||
} |
|||
|
|||
|
|||
Address.prototype.__defineGetter__('balance', function(){ |
|||
|
|||
console.log('#################### '+this.balanceSat); |
|||
|
|||
|
|||
return this.balanceSat / BitcoreUtil.COIN; |
|||
}); |
|||
|
|||
Address.prototype.update = function(next) { |
|||
|
|||
if (! this.addrStr) { |
|||
return next(new Error('Invalid or undefined address string')); |
|||
} |
|||
|
|||
var that = this; |
|||
async.series([ |
|||
// TODO TXout!
|
|||
//T
|
|||
function (cb) { |
|||
TransactionItem.find({addr:that.addrStr}, function(err,txItems){ |
|||
if (err) return cb(err); |
|||
|
|||
txItems.forEach(function(txItem){ |
|||
|
|||
// console.log(txItem.txid + ' : ' + txItem.value_sat);
|
|||
that.txApperances +=1; |
|||
that.balanceSat += txItem.value_sat; |
|||
|
|||
that.transactions.push(txItem.txid); |
|||
|
|||
if (txItem.value_sat > 0) |
|||
that.totalSentSat += txItem.value_sat; |
|||
else |
|||
that.totalReceivedSat += Math.abs(txItem.value_sat); |
|||
}); |
|||
return cb(); |
|||
}); |
|||
} |
|||
], function (err) { |
|||
return next(err); |
|||
}); |
|||
}; |
|||
|
|||
return Address; |
|||
} |
|||
module.defineClass(spec); |
|||
|
|||
|
|||
/** |
|||
* Addr Schema Idea for moogose. Not used now. |
|||
* |
|||
var AddressSchema = new Schema({ |
|||
|
|||
// For now we keep this as short as possible
|
|||
// More fields will be propably added as we move
|
|||
// forward with the UX
|
|||
addr: { |
|||
type: String, |
|||
index: true, |
|||
unique: true, |
|||
}, |
|||
inputs: [{ |
|||
type: mongoose.Schema.Types.ObjectId, |
|||
ref: 'TransactionItem' //Edit: I'd put the schema. Silly me.
|
|||
}], |
|||
output: [{ |
|||
type: mongoose.Schema.Types.ObjectId, |
|||
ref: 'TransactionItem' //Edit: I'd put the schema. Silly me.
|
|||
}], |
|||
}); |
|||
|
|||
|
|||
AddressSchema.statics.load = function(id, cb) { |
|||
this.findOne({ |
|||
_id: id |
|||
}).exec(cb); |
|||
}; |
|||
|
|||
|
|||
AddressSchema.statics.fromAddr = function(hash, cb) { |
|||
this.findOne({ |
|||
hash: hash, |
|||
}).exec(cb); |
|||
}; |
|||
|
|||
|
|||
AddressSchema.statics.fromAddrWithInfo = function(hash, cb) { |
|||
this.fromHash(hash, function(err, addr) { |
|||
if (err) return cb(err); |
|||
if (!addr) { return cb(new Error('Addr not found')); } |
|||
// TODO
|
|||
// addr.getInfo(function(err) { return cb(err,addr); } );
|
|||
}); |
|||
}; |
|||
|
|||
module.exports = mongoose.model('Address', AddressSchema); |
|||
*/ |
|||
|
@ -0,0 +1,54 @@ |
|||
'use strict'; |
|||
|
|||
/** |
|||
* Module dependencies. |
|||
*/ |
|||
var mongoose = require('mongoose'), |
|||
Schema = mongoose.Schema; |
|||
|
|||
var TransactionItemSchema = new Schema({ |
|||
txid: String, |
|||
index: Number, |
|||
addr: { |
|||
type: String, |
|||
index: true, |
|||
}, |
|||
// OJO: mongoose doesnt accept camelcase for field names
|
|||
// <0 is Input >0 is Output
|
|||
value_sat: Number, |
|||
ts: Number, |
|||
}); |
|||
|
|||
|
|||
// Compound index
|
|||
TransactionItemSchema.index({txid: 1, index: 1, value_sat: 1}, {unique: true, dropDups: true}); |
|||
|
|||
|
|||
TransactionItemSchema.statics.load = function(id, cb) { |
|||
this.findOne({ |
|||
_id: id |
|||
}).exec(cb); |
|||
}; |
|||
|
|||
|
|||
TransactionItemSchema.statics.fromTxId = function(txid, cb) { |
|||
this.find({ |
|||
txid: txid, |
|||
}).exec(function (err,items) { |
|||
|
|||
// sort by 1) value sign 2) index
|
|||
return cb(err,items.sort(function(a,b){ |
|||
var sa= a.value_sat < 0 ? -1 : 1; |
|||
var sb= b.value_sat < 0 ? -1 : 1; |
|||
|
|||
if (sa !== sb) { |
|||
return sa-sb; |
|||
} |
|||
else { |
|||
return a.index - b.index; |
|||
} |
|||
})); |
|||
}); |
|||
}; |
|||
|
|||
module.exports = mongoose.model('TransactionItem', TransactionItemSchema); |
@ -0,0 +1,13 @@ |
|||
'use strict'; |
|||
|
|||
var Transaction = require('../../models/Transaction'); |
|||
|
|||
module.exports = function(app, io) { |
|||
io.set('log level', 1); // reduce logging
|
|||
io.sockets.on('connection', function(socket) { |
|||
Transaction.findOne(function(err, tx) { |
|||
socket.emit('tx', tx); |
|||
}); |
|||
}); |
|||
}; |
|||
|
@ -1,16 +1,17 @@ |
|||
'use strict'; |
|||
|
|||
module.exports = { |
|||
db: "mongodb://localhost/mystery-dev", |
|||
db: "mongodb://localhost/mystery-test", |
|||
app: { |
|||
name: "Mystery - Test" |
|||
}, |
|||
port: '3301', |
|||
bitcoind: { |
|||
user: 'mystery', |
|||
pass: 'real_mystery', |
|||
protocol: 'http', |
|||
protocol: process.env.BITCOIND_PROTO || 'http', |
|||
user: process.env.BITCOIND_USER || 'mystery', |
|||
pass: process.env.BITCOIND_PASS || 'real_mystery', |
|||
host: process.env.BITCOIND_HOST || '127.0.0.1', |
|||
port: process.env.BITCOIND_PORT || '8332', |
|||
port: process.env.BITCOIND_PORT || '18332', |
|||
}, |
|||
network: 'testnet', |
|||
} |
|||
|
@ -0,0 +1,121 @@ |
|||
'use strict'; |
|||
require('classtool'); |
|||
|
|||
function spec() { |
|||
var fs = require('fs'); |
|||
var CoinConst = require('bitcore/const'); |
|||
var coinUtil = require('bitcore/util/util'); |
|||
var Sync = require('./Sync').class(); |
|||
var Peer = require('bitcore/Peer').class(); |
|||
|
|||
var peerdb_fn = 'peerdb.json'; |
|||
|
|||
function PeerSync() {} |
|||
PeerSync.prototype.init = function(config) { |
|||
|
|||
var network = config && (config.network || "testnet"); |
|||
|
|||
this.peerdb = undefined; |
|||
this.sync = new Sync({ |
|||
networkName: network |
|||
}); |
|||
this.sync.init(config); |
|||
|
|||
this.PeerManager = require('bitcore/PeerManager').createClass({ |
|||
config: { |
|||
network: network |
|||
} |
|||
}); |
|||
this.load_peers(); |
|||
|
|||
}; |
|||
|
|||
PeerSync.prototype.load_peers = function() { |
|||
try { |
|||
this.peerdb = JSON.parse(fs.readFileSync(peerdb_fn)); |
|||
} catch(d) { |
|||
console.warn('Unable to read peer db', peerdb_fn, 'creating new one.'); |
|||
this.peerdb = [{ |
|||
ipv4: '127.0.0.1', |
|||
port: 18333 |
|||
}, |
|||
]; |
|||
|
|||
fs.writeFileSync(peerdb_fn, JSON.stringify(this.peerdb)); |
|||
} |
|||
}; |
|||
|
|||
PeerSync.prototype.handle_inv = function(info) { |
|||
// TODO: should limit the invs to objects we haven't seen yet
|
|||
var invs = info.message.invs; |
|||
invs.forEach(function(inv) { |
|||
console.log('[p2p_sync] Handle inv for a ' + CoinConst.MSG.to_str(inv.type)); |
|||
}); |
|||
// this is not needed right now, but it's left in case
|
|||
// we need to store more info in the future
|
|||
info.conn.sendGetData(invs); |
|||
}; |
|||
|
|||
PeerSync.prototype.handle_tx = function(info) { |
|||
var tx = info.message.tx.getStandardizedObject(); |
|||
console.log('[p2p_sync] Handle tx: ' + tx.hash); |
|||
this.sync.storeTxs([tx.hash], function(err) { |
|||
if (err) { |
|||
console.log('[p2p_sync] Error in handle TX: ' + err); |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
PeerSync.prototype.handle_block = function(info) { |
|||
var self = this; |
|||
var block = info.message.block; |
|||
var now = Math.round(new Date().getTime() / 1000); |
|||
var blockHash = coinUtil.formatHashFull(block.calcHash()); |
|||
console.log('[p2p_sync] Handle block: ' + blockHash); |
|||
this.sync.storeBlock({ |
|||
'hash': blockHash, |
|||
'time': now |
|||
}, |
|||
function(err) { |
|||
if (err) { |
|||
console.log('[p2p_sync] Error in handle Block: ' + err); |
|||
} else { |
|||
// if no errors importing block, import the transactions
|
|||
var hashes = block.txs.map(function(tx) { |
|||
return coinUtil.formatHashFull(tx.hash); |
|||
}); |
|||
self.sync.storeTxs(hashes, function() {}); |
|||
} |
|||
}); |
|||
|
|||
}; |
|||
|
|||
PeerSync.prototype.handle_connected = function(data) { |
|||
var peerman = data.pm; |
|||
var peers_n = peerman.peers.length; |
|||
console.log('[p2p_sync] Connected to ' + peers_n + ' peer' + (peers_n !== 1 ? 's': '')); |
|||
}; |
|||
|
|||
PeerSync.prototype.run = function() { |
|||
var self = this; |
|||
var peerman = new this.PeerManager(); |
|||
|
|||
this.peerdb.forEach(function(datum) { |
|||
var peer = new Peer(datum.ipv4, datum.port); |
|||
peerman.addPeer(peer); |
|||
}); |
|||
|
|||
peerman.on('connection', function(conn) { |
|||
conn.on('inv', self.handle_inv.bind(self)); |
|||
conn.on('block', self.handle_block.bind(self)); |
|||
conn.on('tx', self.handle_tx.bind(self)); |
|||
}); |
|||
peerman.on('connect', self.handle_connected.bind(self)); |
|||
|
|||
peerman.start(); |
|||
}; |
|||
return PeerSync; |
|||
|
|||
} |
|||
module.defineClass(spec); |
|||
|
@ -1,6 +1,16 @@ |
|||
'use strict'; |
|||
|
|||
angular.module('mystery.system').controller('IndexController', ['$scope', 'Global', 'Index', function ($scope, Global, Index) { |
|||
angular.module('mystery.system').controller('IndexController', ['$scope', 'Global', 'Index', function($scope, Global, Index) { |
|||
$scope.global = Global; |
|||
$scope.index = Index; |
|||
}]); |
|||
|
|||
$(document).ready(function() { |
|||
var socket = io.connect('http://localhost'); |
|||
socket.on('tx', function(data) { |
|||
var tx = data; |
|||
console.log('Transaction received! '+tx.txid); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
@ -0,0 +1,8 @@ |
|||
'use strict'; |
|||
|
|||
angular.module('mystery.address').factory('Address', ['$resource', function($resource) { |
|||
return $resource('/api/addr/:addrStr', { |
|||
addrStr: '@addStr' |
|||
}); |
|||
}]); |
|||
|
@ -0,0 +1,54 @@ |
|||
#!/usr/bin/env node
|
|||
|
|||
process.env.NODE_ENV = process.env.NODE_ENV || 'development'; |
|||
|
|||
var |
|||
assert = require('assert'), |
|||
fs = require('fs'), |
|||
config = require('../../config/config'), |
|||
Address = require('../../app/models/Address').class(); |
|||
mongoose= require('mongoose'), |
|||
addrValid = JSON.parse(fs.readFileSync('test/model/addr.json')); |
|||
|
|||
describe('Address update', function(){ |
|||
|
|||
before(function(done) { |
|||
mongoose.connect(config.db); |
|||
done(); |
|||
}); |
|||
|
|||
after(function(done) { |
|||
mongoose.connection.close(); |
|||
done(); |
|||
}); |
|||
|
|||
addrValid.forEach( function(v) { |
|||
if (v.disabled) { |
|||
console.log(v.addr + " => disabled in JSON"); |
|||
} |
|||
else { |
|||
it('should retrieve the correct info for:' + v.addr, function(done) { |
|||
this.timeout(5000); |
|||
|
|||
var a = new Address(v.addr); |
|||
|
|||
a.update(function(err) { |
|||
if (err) done(err); |
|||
|
|||
assert.equal(v.addr, a.addrStr); |
|||
if (v.balance) assert.equal(v.balance, a.balance); |
|||
if (v.totalReceived) assert.equal(v.totalReceived, a.totalReceived); |
|||
if (v.totalSent) assert.equal(v.totalSent, a.totalSent); |
|||
if (v.transactions) { |
|||
v.transactions.forEach( function(tx) { |
|||
assert(tx in a.inTransactions); |
|||
}); |
|||
} |
|||
done(); |
|||
}); |
|||
}); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
@ -0,0 +1,93 @@ |
|||
[ |
|||
{ |
|||
"addr": "mjRmkmYzvZN3cA3aBKJgYJ65epn3WCG84H" |
|||
}, |
|||
{ |
|||
"addr": "mp3Rzxx9s1A21SY3sjJ3CQoa2Xjph7e5eS", |
|||
"balance": 0, |
|||
"totalReceived": 50, |
|||
"totalSent": 50.0 |
|||
} |
|||
, |
|||
{ |
|||
"addr": "mgqvRGJMwR9JU5VhJ3x9uX9MTkzTsmmDgQ", |
|||
"balance": 43.1 |
|||
}, |
|||
{ |
|||
"disabled":1, |
|||
"addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29", |
|||
"balance": 910.39522682, |
|||
"totalReceived": 910.39522682, |
|||
"totalSent": 0 |
|||
} |
|||
, |
|||
|
|||
|
|||
|
|||
{ |
|||
"disabled":1, |
|||
"addr": "mjRmkmYzvZN3cA3aBKJgYJ65epn3WCG84H", |
|||
"balance": 46413.0, |
|||
"totalReceived": 357130.17644359, |
|||
"totalSent": 310717.17644359 |
|||
}, |
|||
{ |
|||
"disabled":1, |
|||
"addr": "mgKY35SXqxFpcKK3Dq9mW9919N7wYXvcFM", |
|||
"balance": 0.01979459, |
|||
"totalReceived": 0.01979459, |
|||
"totalSent": 0, |
|||
"transactions": [ "91800d80bb4c69b238c9bfd94eb5155ab821e6b25cae5c79903d12853bbb4ed5" ] |
|||
}, |
|||
{ |
|||
"disabled":1, |
|||
"addr": "mmvP3mTe53qxHdPqXEvdu8WdC7GfQ2vmx5", |
|||
"balance": 10580.50027254, |
|||
"totalReceived": 12157.65075053, |
|||
"totalSent": 1577.15047799, |
|||
"transactions": [ |
|||
"91800d80bb4c69b238c9bfd94eb5155ab821e6b25cae5c79903d12853bbb4ed5", |
|||
"f6e80d4fd1a2377406856c67d0cee5ac7e5120993ff97e617ca9aac33b4c6b1e", |
|||
"bc27f31caae86750b126d9b09e969362b85b7c15f41421387d682064544bf7e7", |
|||
"2cd6a1cb26880276fbc9851396f1bd8081cb2b9107ff6921e8fd65ed2df3df79", |
|||
"8bea41f573bccb7b648bc0b1bbfeba8a96da05b1d819ff4a33d39fbcd334ecfd", |
|||
"cb0d55c37acc57f759255193673e13858b5ab3d8fdfa7ee8b25f9964bdaa11e3", |
|||
"7b007aeace2299d27b6bb6c24d0a8040d6a87e4c2601216c34d226462b75f915", |
|||
"a9f40fbaecd2b28a05405e28b95566d7b3bd8ac38a2853debd72517f2994c6fc", |
|||
"4123255b7678e37c168b9e929927760bc5d9363b0c78ec61a7b4a78b2a07adab", |
|||
"cb3760529c2684c32047a2fddf0e2534c9241e5d72011aac4a8982e0c7b46df3", |
|||
"e8d00d8cc744381233dbc95e2d657345084dfb6df785b81285183f4c89b678d4", |
|||
"7a748364255c5b64979d9d3da35ea0fbef0114e0d7f96fccd5bea76f6d19f06b", |
|||
"d0b7e087040f67ef9bd9f21ccf53d1b5410400351d949cabf127caf28a6e7add", |
|||
"209f97873265652b83922921148cad92d7e048c6822e4864e984753e04181470", |
|||
"3a4af7755d3061ecced2f3707c2623534104f08aa73a52ca243d7ddecf5fe86d", |
|||
"4a4b5c8d464a77814ed35a37e2a28e821d467a803761427c057f67823309b725", |
|||
"d85f5265618fb694c3ea3ca6f73eba93df8a644bc1c7286cec2fbc2fbf7d895e", |
|||
"0d2c778ed9976b52792c941cac126bda37d3b1453082022d5e36ac401be3b249", |
|||
"daf03d666047ca0b5340b4a0027f8562b7c5bac87dca3727093b5393176a541a", |
|||
"a0dc03a870e589ea51e3d3a8aed0d34f4f1ae6844acad26dae48fe523b26e764", |
|||
"3df1a50e2e5d8525f04bd21a66bad824364a975449fa24fd5c2537d0f713919b", |
|||
"7bc26c1f3b4ab5ca57677593d28d13bff468a658f4d5efc379c1612554cf668e", |
|||
"ded4cbc9c52fd5599b6a93f89a79cde9aeb5a7f8f56732bb67ae9554325b3666", |
|||
"91224a219196a3f6e6f40ad2137b13fe54109e57aaed7527ea34aa903e6b8313", |
|||
"ee899a182bbb75e98ef14d83489e631dd66a8c5059dc8255692dd8ca9efba01f", |
|||
"0a61590c7548bd4f6a0df1575b268057e5e3e295a44eaeeb1dfbd01332c585ed", |
|||
"d56c22950ad2924f404b5b0baa6e49b0df1aaf09d1947842aed9d0178958eb9d", |
|||
"c6b5368c5a256141894972fbd02377b3894aa0df7c35fab5e0eca90de064fdc1", |
|||
"158e1f9c3f8ec44e88052cadef74e8eb99fbad5697d0b005ba48c933f7d96816", |
|||
"7f6191c0f4e3040901ef0d5d6e76af4f16423061ca1347524c86205e35d904d9", |
|||
"2c2e20f976b98a0ca76c57eca3653699b60c1bd9503cc9cc2fb755164a679a26", |
|||
"59bc81733ff0eaf2b106a70a655e22d2cdeff80ada27b937693993bf0c22e9ea", |
|||
"7da38b66fb5e8582c8be85abecfd744a6de89e738dd5f3aaa0270b218ec424eb", |
|||
"393d51119cdfbf0a308c0bbde2d4c63546c0961022bad1503c4bbaed0638c837", |
|||
"4518868741817ae6757fd98de27693b51fad100e89e5206b9bbf798aeebb804c", |
|||
"c58bce14de1e3016504babd8bbe8175207d75074134a2548a71743fa3e56c58d", |
|||
"6e69ec4a97515a8fd424f123a5fc1fdfd3c3adcd741292cbc09c09a2cc433bea", |
|||
"0e15f2498362050e5ceb6157d0fbf820fdcaf936e447207d433ee7701d7b99c2", |
|||
"a3789e113041db907a1217ddb5c3aaf0eff905cc3d913e68d977e1ab4d19acea", |
|||
"80b460922faf0ad1e8b8a55533654c9a9f3039bfff0fff2bcf8536b8adf95939" |
|||
] |
|||
} |
|||
] |
|||
|
|||
|
@ -0,0 +1,72 @@ |
|||
[ |
|||
{ |
|||
"disabled": 1, |
|||
"txid": "75c5ffe6dc2eb0f6bd011a08c041ef115380ccd637d859b379506a0dca4c26fc" |
|||
}, |
|||
{ |
|||
"txid": "21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237", |
|||
"items": [ |
|||
{ |
|||
"addr": "mwcFwXv2Yquy4vJA4nnNLAbHVjrPdC8Q1Z", |
|||
"value_sat": -166224000, |
|||
"index": 0 |
|||
}, |
|||
{ |
|||
"addr": "mzjLe62faUqCSjkwQkwPAL5nYyR8K132fA", |
|||
"value_sat": 134574000, |
|||
"index": 0 |
|||
}, |
|||
{ |
|||
"addr": "n28wb1cRGxPtfmsenYKFfsvnZ6kRapx3jF", |
|||
"value_sat": 31600000, |
|||
"index": 1 |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"txid": "b633a6249d4a2bc123e7f8a151cae2d4afd17aa94840009f8697270c7818ceee", |
|||
"items": [ |
|||
{ |
|||
"addr": "mzjLe62faUqCSjkwQkwPAL5nYyR8K132fA", |
|||
"value_sat": -40790667, |
|||
"index": 0 |
|||
}, |
|||
{ |
|||
"addr": "mhfQJUSissP6nLM5pz6DxHfctukrrLct2T", |
|||
"value_sat": 19300000, |
|||
"index": 0 |
|||
}, |
|||
{ |
|||
"addr": "mzcDhbL877ES3MGftWnc3EuTSXs3WXDDML", |
|||
"value_sat": 21440667, |
|||
"index": 1 |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"txid": "ca2f42e44455b8a84434de139efea1fe2c7d71414a8939e0a20f518849085c3b", |
|||
"items": [ |
|||
{ |
|||
"addr": "mzeiUi4opeheWYveXqp8ebqHyVwYGA2s3x", |
|||
"value_sat": -1225871, |
|||
"index": 0 |
|||
}, |
|||
{ |
|||
"addr": "mtMLijHAbG8CsgBbQGajsqav9p9wKUYad5", |
|||
"value_sat": -1201823, |
|||
"index": 1 |
|||
}, |
|||
{ |
|||
"addr": "mhqyL1nDQDo1WLH9qH8sjRjx2WwrnmAaXE", |
|||
"value_sat": 1327746, |
|||
"index": 0 |
|||
}, |
|||
{ |
|||
"addr": "mkGrySSnxcqRbtPCisApj3zXCQVmUUWbf1", |
|||
"value_sat": 1049948, |
|||
"index": 1 |
|||
} |
|||
] |
|||
} |
|||
|
|||
] |
@ -0,0 +1,33 @@ |
|||
#!/bin/bash |
|||
|
|||
FIND='find'; |
|||
|
|||
##if [[ "$OSTYPE" =~ "darwin" ]] |
|||
##then |
|||
## FIND='gfind' |
|||
##fi |
|||
|
|||
|
|||
if [ -z "$1" ] |
|||
then |
|||
echo "$0 : find functions references " |
|||
echo "Usage $0 function_name " |
|||
exit; |
|||
fi |
|||
|
|||
EXTRA='' |
|||
|
|||
|
|||
CMD="grep -rnH" |
|||
|
|||
if [ "$2" != '--nocolor' ] |
|||
then |
|||
CMD="$CMD --color=always" |
|||
fi |
|||
|
|||
|
|||
$FIND -L . -name \*.json -not -wholename \*node_modules\* -not -wholename \*public/lib\* -exec $CMD "$1" {} + \ |
|||
-o -name \*.html -not -wholename \*node_modules\* -not -wholename \*public/lib\* -exec $CMD "$1" {} + \ |
|||
-o -name \*.jade -not -wholename \*node_modules\* -not -wholename \*public/lib\* -exec $CMD "$1" {} + \ |
|||
-o -name \*.js -not -wholename \*node_modules\* -not -wholename \*public/lib\* -exec $CMD "$1" {} + |
|||
|
@ -0,0 +1,20 @@ |
|||
#! /usr/bin/env node
|
|||
'use strict'; |
|||
|
|||
process.env.NODE_ENV = process.env.NODE_ENV || 'development'; |
|||
|
|||
var PeerSync = require('../lib/PeerSync').class(); |
|||
|
|||
var PROGRAM_VERSION = '0.1'; |
|||
var program = require('commander'); |
|||
|
|||
program |
|||
.version(PROGRAM_VERSION) |
|||
.option('-N --network [testnet]', 'Set bitcoin network [testnet]', 'testnet') |
|||
.parse(process.argv); |
|||
|
|||
var ps = new PeerSync(); |
|||
ps.init(program); |
|||
ps.run(); |
|||
|
|||
|
Loading…
Reference in new issue