test working with values stored in satoshis

This commit is contained in:
Matias Alejo Garcia 2014-01-13 15:29:19 -03:00
parent 1324d8c183
commit 5a97c96d6e
8 changed files with 124 additions and 58 deletions

View File

@ -14,9 +14,9 @@ function spec() {
function Address(addrStr,cb) { function Address(addrStr,cb) {
this.addrStr = addrStr; this.addrStr = addrStr;
this.balance = null; this.balanceSat = 0;
this.totalReceived = null; this.totalReceivedSat = 0;
this.totalSent = null; this.totalSentSat = 0;
this.txApperances = 0; this.txApperances = 0;
// TODO store only txids? +index? +all? // TODO store only txids? +index? +all?
@ -35,16 +35,16 @@ function spec() {
txItems.forEach(function(txItem){ txItems.forEach(function(txItem){
console.log(txItem.txid + ' : ' + txItem.value_sat);
that.txApperances +=1; that.txApperances +=1;
// TESTING that.balanceSat += txItem.value_sat;
that.balance += txItem.value + 0.1;
that.transactions.push(txItem.txid); that.transactions.push(txItem.txid);
if (txItem.value > 0) if (txItem.value_sat > 0)
that.totalSent += txItem.value; that.totalSentSat += txItem.value_sat;
else else
that.totalReceived += Math.abs(txItem.value); that.totalReceivedSat += Math.abs(txItem.value_sat);
}); });
return cb(); return cb();
}) })

View File

@ -58,19 +58,36 @@ TransactionSchema.statics.fromId = function(txid, cb) {
TransactionSchema.statics.fromIdWithInfo = function(txid, cb) { TransactionSchema.statics.fromIdWithInfo = function(txid, cb) {
var that = this;
// TODO Should we go to mongoDB first? Now, no extra information is stored at mongo.
this.fromId(txid, function(err, tx) { this.fromId(txid, function(err, tx) {
if (err) return cb(err); if (err) return cb(err);
if (!tx) { return cb(new Error('TX not found')); } if (!tx) {
return cb(new Error('TX not found'));
// No in mongo...but maybe in bitcoind... lets query it
/* var tx = new that();
tx.txid = txid;
tx.queryInfo(function(err, txInfo) {
if (!txInfo) return cb(new Error('TX not found'));
tx.save(function(err) {
console.log('asdadsads');
return cb(err,tx);
});
});
*/ }
tx.queryInfo(function(err) { return cb(err,tx); } ); tx.queryInfo(function(err) { return cb(err,tx); } );
}); });
}; };
TransactionSchema.statics.createFromArray = function(txs, next) { TransactionSchema.statics.createFromArray = function(txs, next) {
var that = this; var that = this;
if (!txs) return next(); if (!txs) return next();
@ -97,23 +114,23 @@ TransactionSchema.statics.explodeTransactionItems = function(txid, cb) {
if (err || !t) return cb(err); if (err || !t) return cb(err);
var index=0; var index=0;
t.info.vin.forEach(function(i){ i.n = index++});
async.each(t.info.vin, function(i, next_in) { async.each(t.info.vin, function(i, next_in) {
/*
* TODO Support multisigs???
*/
if (i.addr && i.value) { if (i.addr && i.value) {
//console.log("Creating IN %s %d", i.addr, i.valueSat);
TransactionItem.create({ TransactionItem.create({
txid : t.txid, txid : t.txid,
value : -1 * i.value, value_sat : -1 * i.valueSat,
addr : i.addr, addr : i.addr,
index : index++, index : i.n,
ts : t.info.time,
}, next_in); }, next_in);
} }
else { else {
if ( !i.coinbase ) { if ( !i.coinbase ) {
console.log ("TX: %s seems to be multisig IN. Skipping... ", t.txid); console.log ("TX: %s,%d could not parse INPUT", t.txid, i.n);
} }
return next_in(); return next_in();
} }
@ -129,15 +146,17 @@ TransactionSchema.statics.explodeTransactionItems = function(txid, cb) {
&& o.scriptPubKey.addresses && o.scriptPubKey.addresses
&& o.scriptPubKey.addresses[0] && o.scriptPubKey.addresses[0]
) { ) {
//console.log("Creating OUT %s %d", o.scriptPubKey.addresses[0], o.valueSat);
TransactionItem.create({ TransactionItem.create({
txid : t.txid, txid : t.txid,
value : o.value, value_sat : o.valueSat,
addr : o.scriptPubKey.addresses[0], addr : o.scriptPubKey.addresses[0],
index : o.n, index : o.n,
ts : t.info.time,
}, next_out); }, next_out);
} }
else { else {
console.log ("TX: %s,%d seems to be multisig OUT. Skipping... ", t.txid, o.n); console.log ("TX: %s,%d could not parse OUTPUT. Skipping... ", t.txid, o.n);
return next_out(); return next_out();
} }
}, },
@ -240,6 +259,7 @@ TransactionSchema.methods.queryInfo = function (next) {
if (i.value) { if (i.value) {
that.info.vin[c].value = util.formatValue(i.value); that.info.vin[c].value = util.formatValue(i.value);
var n = util.valueToBigInt(i.value).toNumber(); var n = util.valueToBigInt(i.value).toNumber();
that.info.vin[c].valueSat = n;
valueIn = valueIn.add( n ); valueIn = valueIn.add( n );
var scriptSig = i.getScript(); var scriptSig = i.getScript();
@ -264,9 +284,13 @@ TransactionSchema.methods.queryInfo = function (next) {
}); });
} }
var c = 0;
tx.outs.forEach( function(i) { tx.outs.forEach( function(i) {
var n = util.valueToBigInt(i.v).toNumber(); var n = util.valueToBigInt(i.v).toNumber();
valueOut = valueOut.add(n); valueOut = valueOut.add(n);
that.info.vout[c].valueSat = n;
c++;
}); });
that.info.valueOut = valueOut / util.COIN; that.info.valueOut = valueOut / util.COIN;

View File

@ -13,13 +13,15 @@ var TransactionItemSchema = new Schema({
type: String, type: String,
index: true, index: true,
}, },
// OJO: mongoose doesnt accept camelcase for field names
// <0 is Input >0 is Output // <0 is Input >0 is Output
value: Number, value_sat: Number,
ts: Number,
}); });
// Compound index // Compound index
TransactionItemSchema.index({txid: 1, index: 1, value: 1}, {unique: true, dropDups: true}); TransactionItemSchema.index({txid: 1, index: 1, value_sat: 1}, {unique: true, dropDups: true});
TransactionItemSchema.statics.load = function(id, cb) { TransactionItemSchema.statics.load = function(id, cb) {
@ -29,10 +31,24 @@ TransactionItemSchema.statics.load = function(id, cb) {
}; };
TransactionItemSchema.statics.fromAddr = function(addr, cb) { TransactionItemSchema.statics.fromTxId = function(txid, cb) {
this.find({ this.find({
addr: addr, txid: txid,
}).exec(cb); }).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); module.exports = mongoose.model('TransactionItem', TransactionItemSchema);

View File

@ -6,9 +6,9 @@ module.exports = {
name: "Mystery - Development" name: "Mystery - Development"
}, },
bitcoind: { bitcoind: {
user: 'mystery', protocol: process.env.BITCOIND_USER || 'http',
pass: 'real_mystery', user: process.env.BITCOIND_USER || 'mystery',
protocol: 'http', pass: process.env.BITCOIND_PASS || 'real_mystery',
host: process.env.BITCOIND_HOST || '127.0.0.1', host: process.env.BITCOIND_HOST || '127.0.0.1',
port: process.env.BITCOIND_PORT || '18332', port: process.env.BITCOIND_PORT || '18332',
}, },

View File

@ -8,9 +8,7 @@ var
config = require('../../config/config'), config = require('../../config/config'),
Address = require('../../app/models/Address'); Address = require('../../app/models/Address');
mongoose= require('mongoose'), mongoose= require('mongoose'),
config = require('../../config/config'); addrValid = JSON.parse(fs.readFileSync('test/model/addr.json'));
var addrValid = JSON.parse(fs.readFileSync('test/model/addr.json'));
describe('Address update', function(){ describe('Address update', function(){

View File

@ -1,15 +1,20 @@
[ [
{ {
"disabled":1,
"addr": "mjRmkmYzvZN3cA3aBKJgYJ65epn3WCG84H" "addr": "mjRmkmYzvZN3cA3aBKJgYJ65epn3WCG84H"
}, },
{ {
"disabled":1,
"addr": "mp3Rzxx9s1A21SY3sjJ3CQoa2Xjph7e5eS", "addr": "mp3Rzxx9s1A21SY3sjJ3CQoa2Xjph7e5eS",
"balance": 0, "balance": 0,
"totalReceived": 50, "totalReceived": 50,
"totalSent": 50.0 "totalSent": 50.0
} }
, ,
{
"addr": "mgqvRGJMwR9JU5VhJ3x9uX9MTkzTsmmDgQ",
"balance": 43.1
},
{ {
"addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29", "addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29",
"balance": 910.39522682, "balance": 910.39522682,

View File

@ -28,9 +28,6 @@ describe('Transaction', function(){
mongoose.connection.close(); mongoose.connection.close();
done(); done();
}); });
it('should pool tx\'s object from mongoose', function(done) { it('should pool tx\'s object from mongoose', function(done) {
var txid = '7e621eeb02874ab039a8566fd36f4591e65eca65313875221842c53de6907d6c'; var txid = '7e621eeb02874ab039a8566fd36f4591e65eca65313875221842c53de6907d6c';
Transaction.fromIdWithInfo(txid, function(err, tx) { Transaction.fromIdWithInfo(txid, function(err, tx) {
@ -80,23 +77,42 @@ describe('Transaction', function(){
done(); done();
}); });
}); });
var txid22 = '666';
it('test unexisting TX ' + txid22, function(done) {
Transaction.fromIdWithInfo(txid22, function(err, tx) {
if (err && err.toString().match(/TX.not.found/)) {
return done();
}
else {
return done(err);
}
});
});
var txid2 = '64496d005faee77ac5a18866f50af6b8dd1f60107d6795df34c402747af98608';
it('create TX on the fly ' + txid2, function(done) {
TransactionItem.remove({txid: txid2}, function(err) {
Transaction.fromIdWithInfo(txid2, function(err, tx) {
if (err) return done(err);
assert.equal(tx.info.txid, txid2);
done();
});
});
});
var txid2 = '64496d005faee77ac5a18866f50af6b8dd1f60107d6795df34c402747af98608'; var txid2 = '64496d005faee77ac5a18866f50af6b8dd1f60107d6795df34c402747af98608';
it('test a broken TX ' + txid2, function(done) { it('test a broken TX ' + txid2, function(done) {
Transaction.fromIdWithInfo(txid2, function(err, tx) { Transaction.fromIdWithInfo(txid2, function(err, tx) {
if (err) done(err); if (err) return done(err);
assert.equal(tx.info.txid, txid2); assert.equal(tx.info.txid, txid2);
assert.equal(tx.info.vin[0].addr, 'n1JagbRWBDi6VMvG7HfZmXX74dB9eiHJzU'); assert.equal(tx.info.vin[0].addr, 'n1JagbRWBDi6VMvG7HfZmXX74dB9eiHJzU');
// TODO output -> multisig!
// https://www.biteasy.com/testnet/transactions/64496d005faee77ac5a18866f50af6b8dd1f60107d6795df34c402747af98608
done(); done();
}); });
}); });
txItemsValid.forEach( function(v) { txItemsValid.forEach( function(v) {
if (v.disabled) return;
it('test a exploding TX ' + v.txid, function(done) { it('test a exploding TX ' + v.txid, function(done) {
// Remove first // Remove first
@ -105,7 +121,8 @@ describe('Transaction', function(){
Transaction.explodeTransactionItems(v.txid, function(err, tx) { Transaction.explodeTransactionItems(v.txid, function(err, tx) {
if (err) done(err); if (err) done(err);
TransactionItem.find({txid: v.txid}).sort({ index:1 }).exec(function(err, readItems) { TransactionItem
.fromTxId( v.txid, function(err, readItems) {
var unmatch={}; var unmatch={};
@ -113,20 +130,22 @@ describe('Transaction', function(){
unmatch[validItem.addr] =1; unmatch[validItem.addr] =1;
}); });
v.items.forEach(function(validItem){ v.items.forEach(function(validItem){
readItems.forEach(function(readItem){ var readItem = readItems.shift();
if ( readItem.addr === validItem.addr && assert.equal(readItem.addr,validItem.addr);
parseInt(readItem.index) == parseInt(validItem.index) && assert.equal(readItem.value_sat,validItem.value_sat);
parseFloat(readItem.value) == parseFloat(validItem.value) ) assert.equal(readItem.index,validItem.index);
delete unmatch[validItem.addr]; delete unmatch[validItem.addr];
});
}); });
var valid = util.inspect(v.items, { depth: null }); var valid = util.inspect(v.items, { depth: null });
assert(!Object.keys(unmatch).length, '\n\tmatched:' + Object.keys(unmatch) + "\n\n" +valid + '\nvs.\n' + readItems); assert(!Object.keys(unmatch).length,
'\n\tUnmatchs:' + Object.keys(unmatch) + "\n\n" +valid + '\nvs.\n' + readItems);
done(); done();
}); });
}); });
}); });
}); });
}); });
}); });

View File

@ -1,20 +1,24 @@
[ [
{
"disabled": 1,
"txid": "75c5ffe6dc2eb0f6bd011a08c041ef115380ccd637d859b379506a0dca4c26fc"
},
{ {
"txid": "21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237", "txid": "21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237",
"items": [ "items": [
{ {
"addr": "mwcFwXv2Yquy4vJA4nnNLAbHVjrPdC8Q1Z", "addr": "mwcFwXv2Yquy4vJA4nnNLAbHVjrPdC8Q1Z",
"value": -1.66224, "value_sat": -166224000,
"index": 0 "index": 0
}, },
{ {
"addr": "mzjLe62faUqCSjkwQkwPAL5nYyR8K132fA", "addr": "mzjLe62faUqCSjkwQkwPAL5nYyR8K132fA",
"value": 1.34574, "value_sat": 134574000,
"index": 0 "index": 0
}, },
{ {
"addr": "n28wb1cRGxPtfmsenYKFfsvnZ6kRapx3jF", "addr": "n28wb1cRGxPtfmsenYKFfsvnZ6kRapx3jF",
"value": 0.316, "value_sat": 31600000,
"index": 1 "index": 1
} }
] ]
@ -24,17 +28,17 @@
"items": [ "items": [
{ {
"addr": "mzjLe62faUqCSjkwQkwPAL5nYyR8K132fA", "addr": "mzjLe62faUqCSjkwQkwPAL5nYyR8K132fA",
"value": -0.40790667, "value_sat": -40790667,
"index": 0 "index": 0
}, },
{ {
"addr": "mhfQJUSissP6nLM5pz6DxHfctukrrLct2T", "addr": "mhfQJUSissP6nLM5pz6DxHfctukrrLct2T",
"value": 0.193, "value_sat": 19300000,
"index": 0 "index": 0
}, },
{ {
"addr": "mzcDhbL877ES3MGftWnc3EuTSXs3WXDDML", "addr": "mzcDhbL877ES3MGftWnc3EuTSXs3WXDDML",
"value": 0.21440667, "value_sat": 21440667,
"index": 1 "index": 1
} }
] ]
@ -44,22 +48,22 @@
"items": [ "items": [
{ {
"addr": "mzeiUi4opeheWYveXqp8ebqHyVwYGA2s3x", "addr": "mzeiUi4opeheWYveXqp8ebqHyVwYGA2s3x",
"value": -0.01225871, "value_sat": -1225871,
"index": 0 "index": 0
}, },
{ {
"addr": "mtMLijHAbG8CsgBbQGajsqav9p9wKUYad5", "addr": "mtMLijHAbG8CsgBbQGajsqav9p9wKUYad5",
"value": -0.01201823, "value_sat": -1201823,
"index": 1 "index": 1
}, },
{ {
"addr": "mhqyL1nDQDo1WLH9qH8sjRjx2WwrnmAaXE", "addr": "mhqyL1nDQDo1WLH9qH8sjRjx2WwrnmAaXE",
"value": 0.01327746, "value_sat": 1327746,
"index": 0 "index": 0
}, },
{ {
"addr": "mkGrySSnxcqRbtPCisApj3zXCQVmUUWbf1", "addr": "mkGrySSnxcqRbtPCisApj3zXCQVmUUWbf1",
"value": 0.01049948, "value_sat": 1049948,
"index": 1 "index": 1
} }
] ]