373 lines
7.1 KiB
JavaScript
373 lines
7.1 KiB
JavaScript
/*!
|
|
* records.js - walletdb records
|
|
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
|
|
* https://github.com/bcoin-org/bcoin
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var utils = require('../utils/utils');
|
|
var assert = require('assert');
|
|
var constants = require('../protocol/constants');
|
|
var BufferReader = require('../utils/reader');
|
|
var BufferWriter = require('../utils/writer');
|
|
|
|
/**
|
|
* Wallet Tip
|
|
* @constructor
|
|
* @param {Hash} hash
|
|
* @param {Number} height
|
|
*/
|
|
|
|
function HeaderRecord(hash, height, ts) {
|
|
if (!(this instanceof HeaderRecord))
|
|
return new HeaderRecord(hash, height, ts);
|
|
|
|
this.hash = hash || constants.NULL_HASH;
|
|
this.height = height != null ? height : -1;
|
|
this.ts = ts || 0;
|
|
}
|
|
|
|
/**
|
|
* Clone the block.
|
|
* @returns {HeaderRecord}
|
|
*/
|
|
|
|
HeaderRecord.prototype.clone = function clone() {
|
|
return new HeaderRecord(this.hash, this.height, this.ts);
|
|
};
|
|
|
|
/**
|
|
* Instantiate wallet block from chain entry.
|
|
* @private
|
|
* @param {ChainEntry} entry
|
|
*/
|
|
|
|
HeaderRecord.prototype.fromEntry = function fromEntry(entry) {
|
|
this.hash = entry.hash;
|
|
this.height = entry.height;
|
|
this.ts = entry.ts;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Instantiate wallet block from json object.
|
|
* @private
|
|
* @param {Object} json
|
|
*/
|
|
|
|
HeaderRecord.prototype.fromJSON = function fromJSON(json) {
|
|
this.hash = utils.revHex(json.hash);
|
|
this.height = json.height;
|
|
this.ts = json.ts;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Instantiate wallet block from serialized tip data.
|
|
* @private
|
|
* @param {Buffer} data
|
|
*/
|
|
|
|
HeaderRecord.prototype.fromRaw = function fromRaw(data) {
|
|
var p = new BufferReader(data);
|
|
this.hash = p.readHash('hex');
|
|
this.height = p.readU32();
|
|
this.ts = p.readU32();
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Instantiate wallet block from chain entry.
|
|
* @param {ChainEntry} entry
|
|
* @returns {HeaderRecord}
|
|
*/
|
|
|
|
HeaderRecord.fromEntry = function fromEntry(entry) {
|
|
return new HeaderRecord().fromEntry(entry);
|
|
};
|
|
|
|
/**
|
|
* Instantiate wallet block from json object.
|
|
* @param {Object} json
|
|
* @returns {HeaderRecord}
|
|
*/
|
|
|
|
HeaderRecord.fromJSON = function fromJSON(json) {
|
|
return new HeaderRecord().fromJSON(json);
|
|
};
|
|
|
|
/**
|
|
* Instantiate wallet block from serialized data.
|
|
* @param {Hash} hash
|
|
* @param {Buffer} data
|
|
* @returns {HeaderRecord}
|
|
*/
|
|
|
|
HeaderRecord.fromRaw = function fromRaw(data) {
|
|
return new HeaderRecord().fromRaw(data);
|
|
};
|
|
|
|
/**
|
|
* Serialize the wallet block as a tip (hash and height).
|
|
* @returns {Buffer}
|
|
*/
|
|
|
|
HeaderRecord.prototype.toRaw = function toRaw(writer) {
|
|
var p = new BufferWriter(writer);
|
|
|
|
p.writeHash(this.hash);
|
|
p.writeU32(this.height);
|
|
p.writeU32(this.ts);
|
|
|
|
if (!writer)
|
|
p = p.render();
|
|
|
|
return p;
|
|
};
|
|
|
|
/**
|
|
* Convert the block to a more json-friendly object.
|
|
* @returns {Object}
|
|
*/
|
|
|
|
HeaderRecord.prototype.toJSON = function toJSON() {
|
|
return {
|
|
hash: utils.revHex(this.hash),
|
|
height: this.height,
|
|
ts: this.ts
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Wallet Block
|
|
* @constructor
|
|
* @param {Hash} hash
|
|
* @param {Number} height
|
|
*/
|
|
|
|
function BlockMapRecord(height) {
|
|
if (!(this instanceof BlockMapRecord))
|
|
return new BlockMapRecord(height);
|
|
|
|
this.height = height != null ? height : -1;
|
|
this.txs = [];
|
|
this.index = {};
|
|
}
|
|
|
|
/**
|
|
* Instantiate wallet block from serialized data.
|
|
* @private
|
|
* @param {Hash} hash
|
|
* @param {Buffer} data
|
|
*/
|
|
|
|
BlockMapRecord.prototype.fromRaw = function fromRaw(data) {
|
|
var p = new BufferReader(data);
|
|
var i, hash, tx, count;
|
|
|
|
while (p.left()) {
|
|
hash = p.readHash('hex');
|
|
tx = new TXMapRecord(hash);
|
|
count = p.readVarint();
|
|
for (i = 0; i < count; i++)
|
|
tx.wids.push(p.readU32());
|
|
this.txs.push(tx);
|
|
this.index[tx.hash] = tx;
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Instantiate wallet block from serialized data.
|
|
* @param {Hash} hash
|
|
* @param {Buffer} data
|
|
* @returns {BlockMapRecord}
|
|
*/
|
|
|
|
BlockMapRecord.fromRaw = function fromRaw(height, data) {
|
|
return new BlockMapRecord(height).fromRaw(data);
|
|
};
|
|
|
|
/**
|
|
* Serialize the wallet block as a block.
|
|
* Contains matching transaction hashes.
|
|
* @returns {Buffer}
|
|
*/
|
|
|
|
BlockMapRecord.prototype.toRaw = function toRaw(writer) {
|
|
var p = new BufferWriter(writer);
|
|
var i, j, tx;
|
|
|
|
for (i = 0; i < this.txs.length; i++) {
|
|
tx = this.txs[i];
|
|
p.writeHash(tx.hash);
|
|
p.writeVarint(tx.wids.length);
|
|
for (j = 0; j < tx.wids.length; j++)
|
|
p.writeU32(tx.wids[j]);
|
|
}
|
|
|
|
if (!writer)
|
|
p = p.render();
|
|
|
|
return p;
|
|
};
|
|
|
|
/**
|
|
* Add a hash and wid pair to the block.
|
|
* @param {Hash} hash
|
|
* @param {WalletID} wid
|
|
* @returns {Boolean}
|
|
*/
|
|
|
|
BlockMapRecord.prototype.add = function add(hash, wid) {
|
|
var tx = this.index[hash];
|
|
|
|
if (!tx) {
|
|
tx = new TXMapRecord(hash);
|
|
tx.wids.push(wid);
|
|
this.txs.push(tx);
|
|
this.index[tx.hash] = tx;
|
|
return true;
|
|
}
|
|
|
|
return tx.add(wid);
|
|
};
|
|
|
|
/**
|
|
* Remove a hash and wid pair from the block.
|
|
* @param {Hash} hash
|
|
* @param {WalletID} wid
|
|
* @returns {Boolean}
|
|
*/
|
|
|
|
BlockMapRecord.prototype.remove = function remove(hash, wid) {
|
|
var tx = this.index[hash];
|
|
var result;
|
|
|
|
if (!tx)
|
|
return false;
|
|
|
|
if (!tx.remove(wid))
|
|
return false;
|
|
|
|
if (tx.wids.length === 0) {
|
|
result = utils.binaryRemove(this.txs, tx, cmpid);
|
|
assert(result);
|
|
delete this.index[tx.hash];
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* TX Hash
|
|
* @constructor
|
|
*/
|
|
|
|
function TXMapRecord(hash, wids) {
|
|
this.hash = hash || constants.NULL_HASH;
|
|
this.wids = wids || [];
|
|
this.id = TXMapRecord.id++;
|
|
}
|
|
|
|
TXMapRecord.id = 0;
|
|
|
|
TXMapRecord.prototype.add = function add(wid) {
|
|
return utils.binaryInsert(this.wids, wid, cmp, true) !== -1;
|
|
};
|
|
|
|
TXMapRecord.prototype.remove = function remove(wid) {
|
|
return utils.binaryRemove(this.wids, wid, cmp);
|
|
};
|
|
|
|
TXMapRecord.prototype.toRaw = function toRaw() {
|
|
return serializeWallets(this.wids);
|
|
};
|
|
|
|
TXMapRecord.prototype.fromRaw = function fromRaw(data) {
|
|
this.wids = parseWallets(data);
|
|
return this;
|
|
};
|
|
|
|
TXMapRecord.fromRaw = function fromRaw(hash, data) {
|
|
return new TXMapRecord(hash).fromRaw(data);
|
|
};
|
|
|
|
/**
|
|
* Path Record
|
|
* @constructor
|
|
*/
|
|
|
|
function PathMapRecord(hash, wids) {
|
|
this.hash = hash || constants.NULL_HASH;
|
|
this.wids = wids || [];
|
|
}
|
|
|
|
PathMapRecord.prototype.add = function add(wid) {
|
|
return utils.binaryInsert(this.wids, wid, cmp, true) !== -1;
|
|
};
|
|
|
|
PathMapRecord.prototype.remove = function remove(wid) {
|
|
return utils.binaryRemove(this.wids, wid, cmp);
|
|
};
|
|
|
|
PathMapRecord.prototype.toRaw = function toRaw() {
|
|
return serializeWallets(this.wids);
|
|
};
|
|
|
|
PathMapRecord.prototype.fromRaw = function fromRaw(data) {
|
|
this.wids = parseWallets(data);
|
|
return this;
|
|
};
|
|
|
|
PathMapRecord.fromRaw = function fromRaw(hash, data) {
|
|
return new PathMapRecord(hash).fromRaw(data);
|
|
};
|
|
|
|
/*
|
|
* Helpers
|
|
*/
|
|
|
|
function cmp(a, b) {
|
|
return a - b;
|
|
}
|
|
|
|
function cmpid(a, b) {
|
|
return a.id - b.id;
|
|
}
|
|
|
|
function parseWallets(data) {
|
|
var p = new BufferReader(data);
|
|
var wids = [];
|
|
|
|
while (p.left())
|
|
wids.push(p.readU32());
|
|
|
|
return wids;
|
|
}
|
|
|
|
function serializeWallets(wids) {
|
|
var p = new BufferWriter();
|
|
var i, wid;
|
|
|
|
for (i = 0; i < wids.length; i++) {
|
|
wid = wids[i];
|
|
p.writeU32(wid);
|
|
}
|
|
|
|
return p.render();
|
|
}
|
|
|
|
/*
|
|
* Expose
|
|
*/
|
|
|
|
exports.HeaderRecord = HeaderRecord;
|
|
exports.BlockMapRecord = BlockMapRecord;
|
|
exports.TXMapRecord = TXMapRecord;
|
|
exports.PathMapRecord = PathMapRecord;
|
|
|
|
module.exports = exports;
|