lib: JSON serialization for everyone
This commit is contained in:
parent
b98be4b388
commit
a6be7bf5f7
@ -1,3 +1,4 @@
|
||||
var assert = require('assert');
|
||||
var util = require('util');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
@ -27,17 +28,13 @@ function Chain(options) {
|
||||
count: 0
|
||||
};
|
||||
this.index = {
|
||||
bloom: new bcoin.bloom(28 * 1024 * 1024, 33, 0xdeadbee0),
|
||||
hashes: preload.hashes.slice(),
|
||||
ts: preload.ts.slice()
|
||||
bloom: null,
|
||||
hashes: [],
|
||||
ts: []
|
||||
};
|
||||
this.request = new utils.RequestCache();
|
||||
|
||||
if (this.index.hashes.length === 0)
|
||||
this.add(new bcoin.block(constants.genesis));
|
||||
|
||||
for (var i = 0; i < this.index.hashes.length; i++)
|
||||
this.index.bloom.add(this.index.hashes[i], 'hex');
|
||||
this.fromJSON(preload);
|
||||
}
|
||||
util.inherits(Chain, EventEmitter);
|
||||
module.exports = Chain;
|
||||
@ -69,7 +66,11 @@ Chain.prototype.addIndex = function addIndex(hash, ts) {
|
||||
if (this.probeIndex(hash, ts))
|
||||
return;
|
||||
|
||||
var pos = utils.binaryInsert(this.index.ts, ts, compareTs);
|
||||
var pos = utils.binaryInsert(this.index.ts, ts, compareTs, true);
|
||||
if (pos <= this.index.ts.length - 1000)
|
||||
return;
|
||||
|
||||
this.index.ts.splice(pos, 0, ts);
|
||||
this.index.hashes.splice(pos, 0, hash);
|
||||
this.index.bloom.add(hash, 'hex');
|
||||
};
|
||||
@ -216,3 +217,45 @@ Chain.prototype.hashesInRange = function hashesInRange(start, end) {
|
||||
Chain.prototype.getLast = function getLast() {
|
||||
return this.index.hashes[this.index.hashes.length - 1];
|
||||
};
|
||||
|
||||
Chain.prototype.toJSON = function toJSON() {
|
||||
// Keep only last 1000 consequent blocks, use every 50th for older
|
||||
var last = {
|
||||
hashes: this.index.hashes.slice(-1000),
|
||||
ts: this.index.ts.slice(-1000)
|
||||
};
|
||||
|
||||
var first = {
|
||||
hashes: [],
|
||||
ts: []
|
||||
};
|
||||
var len = (this.index.hashes.length - 1000) - this.index.hashes.length % 50;
|
||||
for (var i = 0; i < len; i += 50) {
|
||||
first.hashes.push(this.index.hashes[i]);
|
||||
first.ts.push(this.index.ts[i]);
|
||||
}
|
||||
|
||||
return {
|
||||
v: 1,
|
||||
type: 'chain',
|
||||
hashes: first.hashes.concat(last.hashes),
|
||||
ts: first.ts.concat(last.ts),
|
||||
};
|
||||
};
|
||||
|
||||
Chain.prototype.fromJSON = function fromJSON(json) {
|
||||
assert.equal(json.v, 1);
|
||||
assert.equal(json.type, 'chain');
|
||||
this.index.hashes = json.hashes.slice();
|
||||
this.index.ts = json.ts.slice();
|
||||
if (this.index.bloom)
|
||||
this.index.bloom.reset();
|
||||
else
|
||||
this.index.bloom = new bcoin.bloom(28 * 1024 * 1024, 33, 0xdeadbee0);
|
||||
|
||||
if (this.index.hashes.length === 0)
|
||||
this.add(new bcoin.block(constants.genesis));
|
||||
|
||||
for (var i = 0; i < this.index.hashes.length; i++)
|
||||
this.index.bloom.add(this.index.hashes[i], 'hex');
|
||||
};
|
||||
|
||||
@ -532,6 +532,22 @@ Pool.prototype.sendTX = function sendTX(tx) {
|
||||
return e;
|
||||
};
|
||||
|
||||
Pool.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
v: 1,
|
||||
type: 'pool',
|
||||
chain: this.chain.toJSON()
|
||||
};
|
||||
};
|
||||
|
||||
Pool.prototype.fromJSON = function fromJSON(json) {
|
||||
assert.equal(json.v, 1);
|
||||
assert.equal(json.type, 'pool');
|
||||
this.chain.fromJSON(json.chain);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
function LoadRequest(pool, type, hash, cb) {
|
||||
this.pool = pool
|
||||
this.type = type;
|
||||
|
||||
@ -270,10 +270,10 @@ Parser.prototype.parseTX = function parseTX(p) {
|
||||
var inCount = readIntv(p, 4);
|
||||
var off = inCount.off;
|
||||
inCount = inCount.r;
|
||||
if (inCount <= 0)
|
||||
return this._error('Invalid tx_in count');
|
||||
if (inCount < 0)
|
||||
return this._error('Invalid tx_in count (negative)');
|
||||
if (off + 41 * inCount + 14 > p.length)
|
||||
return this._error('Invalid tx_in count');
|
||||
return this._error('Invalid tx_in count (too big)');
|
||||
|
||||
var txIn = new Array(inCount);
|
||||
for (var i = 0; i < inCount; i++) {
|
||||
@ -290,10 +290,10 @@ Parser.prototype.parseTX = function parseTX(p) {
|
||||
var outCount = readIntv(p, off);
|
||||
var off = outCount.off;
|
||||
outCount = outCount.r;
|
||||
if (outCount <= 0)
|
||||
return this._error('Invalid tx_out count');
|
||||
if (outCount < 0)
|
||||
return this._error('Invalid tx_out count (negative)');
|
||||
if (off + 9 * outCount + 4 > p.length)
|
||||
return this._error('Invalid tx_out count');
|
||||
return this._error('Invalid tx_out count (too big)');
|
||||
|
||||
var txOut = new Array(outCount);
|
||||
for (var i = 0; i < outCount; i++) {
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
"v": 1,
|
||||
"type": "chain",
|
||||
"hashes": [
|
||||
"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000",
|
||||
"33aa0fa26441ead7005df4b0ad2e61405e80cb805e3c657f194df32600000000",
|
||||
|
||||
@ -1,19 +1,22 @@
|
||||
var assert = require('assert');
|
||||
var bn = require('bn.js');
|
||||
var bcoin = require('../bcoin');
|
||||
|
||||
function TXPool() {
|
||||
function TXPool(wallet) {
|
||||
if (!(this instanceof TXPool))
|
||||
return new TXPool();
|
||||
return new TXPool(wallet);
|
||||
|
||||
this._wallet = wallet;
|
||||
this._all = {};
|
||||
this._unspent = {};
|
||||
this._orphans = {};
|
||||
}
|
||||
module.exports = TXPool;
|
||||
|
||||
TXPool.prototype.add = function add(tx, wallet) {
|
||||
TXPool.prototype.add = function add(tx) {
|
||||
var hash = tx.hash('hex');
|
||||
|
||||
if (!wallet.own(tx))
|
||||
if (!this._wallet.own(tx))
|
||||
return;
|
||||
|
||||
// Do not add TX two times
|
||||
@ -61,17 +64,17 @@ TXPool.prototype.add = function add(tx, wallet) {
|
||||
return true;
|
||||
};
|
||||
|
||||
TXPool.prototype.unspent = function unspent(wallet) {
|
||||
TXPool.prototype.unspent = function unspent() {
|
||||
return Object.keys(this._unspent).map(function(key) {
|
||||
return this._unspent[key];
|
||||
}, this).filter(function(item) {
|
||||
return wallet.own(item.tx, item.index);
|
||||
});
|
||||
return this._wallet.own(item.tx, item.index);
|
||||
}, this);
|
||||
};
|
||||
|
||||
TXPool.prototype.balance = function balance(wallet) {
|
||||
TXPool.prototype.balance = function balance() {
|
||||
var acc = new bn(0);
|
||||
var unspent = this.unspent(wallet);
|
||||
var unspent = this.unspent();
|
||||
if (unspent.length === 0)
|
||||
return acc;
|
||||
|
||||
@ -79,3 +82,22 @@ TXPool.prototype.balance = function balance(wallet) {
|
||||
return acc.iadd(item.tx.outputs[item.index].value);
|
||||
}, acc);
|
||||
};
|
||||
|
||||
TXPool.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
v: 1,
|
||||
type: 'tx-pool',
|
||||
txs: Object.keys(this._all).map(function(hash) {
|
||||
return this._all[hash].toJSON();
|
||||
}, this)
|
||||
};
|
||||
};
|
||||
|
||||
TXPool.prototype.fromJSON = function fromJSON(json) {
|
||||
assert.equal(json.v, 1);
|
||||
assert.equal(json.type, 'tx-pool');
|
||||
|
||||
json.txs.forEach(function(tx) {
|
||||
this.add(bcoin.tx.fromJSON(tx));
|
||||
}, this);
|
||||
};
|
||||
|
||||
@ -171,3 +171,13 @@ TX.prototype.verify = function verify() {
|
||||
return stack.length > 0 && utils.isEqual(stack.pop(), [ 1 ]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
TX.prototype.toJSON = function toJSON() {
|
||||
// Compact representation
|
||||
return utils.toBase58(this.render());
|
||||
};
|
||||
|
||||
TX.fromJSON = function fromJSON(json) {
|
||||
// Compact representation
|
||||
return new TX(new bcoin.protocol.parser().parseTX(utils.fromBase58(json)));
|
||||
};
|
||||
|
||||
@ -18,7 +18,7 @@ function Wallet(options, passphrase) {
|
||||
options = {};
|
||||
|
||||
this.compressed = true;
|
||||
this.tx = new bcoin.txPool();
|
||||
this.tx = new bcoin.txPool(this);
|
||||
this.key = null;
|
||||
|
||||
if (options.passphrase) {
|
||||
@ -41,7 +41,12 @@ Wallet.prototype.getPrivateKey = function getPrivateKey(enc) {
|
||||
|
||||
if (enc === 'base58') {
|
||||
// We'll be using ncompressed public key as an address
|
||||
var arr = [ 128 ].concat(priv);
|
||||
var arr = [ 128 ];
|
||||
|
||||
// 0-pad key
|
||||
while (arr.length + priv.length < 33)
|
||||
arr.push(0);
|
||||
arr = arr.concat(priv);
|
||||
if (this.compressed)
|
||||
arr.push(1);
|
||||
var chk = utils.checksum(arr);
|
||||
@ -149,13 +154,45 @@ Wallet.prototype.sign = function sign(tx, type) {
|
||||
};
|
||||
|
||||
Wallet.prototype.addTX = function addTX(tx) {
|
||||
return this.tx.add(tx, this);
|
||||
return this.tx.add(tx);
|
||||
};
|
||||
|
||||
Wallet.prototype.unspent = function unspent() {
|
||||
return this.tx.unspent(this);
|
||||
return this.tx.unspent();
|
||||
};
|
||||
|
||||
Wallet.prototype.balance = function balance() {
|
||||
return this.tx.balance(this);
|
||||
return this.tx.balance();
|
||||
};
|
||||
|
||||
Wallet.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
v: 1,
|
||||
type: 'wallet',
|
||||
key: this.getPrivateKey('base58'),
|
||||
tx: this.tx.toJSON()
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.fromJSON = function fromJSON(json) {
|
||||
assert.equal(json.v, 1);
|
||||
assert.equal(json.type, 'wallet');
|
||||
|
||||
var key = bcoin.utils.fromBase58(json.key);
|
||||
assert(utils.isEqual(key.slice(-4), utils.checksum(key.slice(0, -4))));
|
||||
assert.equal(key[0], 128);
|
||||
|
||||
key = key.slice(0, -4);
|
||||
if (key.length === 34) {
|
||||
assert.equal(key[33], 1);
|
||||
this.key = bcoin.ecdsa.keyPair(key.slice(1, -1));
|
||||
this.compressed = true;
|
||||
} else {
|
||||
this.key = bcoin.ecdsa.keyPair(key.slice(1));
|
||||
this.compressed = false;
|
||||
}
|
||||
|
||||
this.tx.fromJSON(json.tx);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@ -71,7 +71,7 @@ describe('Wallet', function() {
|
||||
assert(tx.verify());
|
||||
});
|
||||
|
||||
it('should have TX pool', function() {
|
||||
it('should have TX pool and be serializable', function() {
|
||||
var w = bcoin.wallet();
|
||||
|
||||
// Coinbase
|
||||
@ -93,5 +93,8 @@ describe('Wallet', function() {
|
||||
assert.equal(w.balance().toString(10), '47000');
|
||||
w.addTX(t3);
|
||||
assert.equal(w.balance().toString(10), '22000');
|
||||
|
||||
var w2 = bcoin.wallet().fromJSON(w.toJSON());
|
||||
assert.equal(w2.balance().toString(10), '22000');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user