txdb: refactor block handling.
This commit is contained in:
parent
debe2e4ec7
commit
282fe7e4d9
@ -17,6 +17,7 @@ var BufferWriter = require('../utils/writer');
|
|||||||
var TX = require('../primitives/tx');
|
var TX = require('../primitives/tx');
|
||||||
var Coin = require('../primitives/coin');
|
var Coin = require('../primitives/coin');
|
||||||
var Outpoint = require('../primitives/outpoint');
|
var Outpoint = require('../primitives/outpoint');
|
||||||
|
var WalletBlock = require('./walletblock');
|
||||||
var DUMMY = new Buffer([0]);
|
var DUMMY = new Buffer([0]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -857,10 +858,15 @@ TXDB.prototype.getSpent = co(function* getSpent(hash, index) {
|
|||||||
* @returns {Promise} - Returns Boolean.
|
* @returns {Promise} - Returns Boolean.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.isSpent = co(function* isSpent(hash, index) {
|
TXDB.prototype.isSpent = function isSpent(hash, index) {
|
||||||
var data = yield this.get(layout.s(hash, index));
|
return this.has(layout.s(hash, index));
|
||||||
return data != null;
|
};
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* Append to the global tx record.
|
||||||
|
* @param {TX} tx
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
TXDB.prototype.addTXRecord = co(function* addTXRecord(tx) {
|
TXDB.prototype.addTXRecord = co(function* addTXRecord(tx) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
@ -878,6 +884,12 @@ TXDB.prototype.addTXRecord = co(function* addTXRecord(tx) {
|
|||||||
this.walletdb.writeTX(this.wallet, hash, wids);
|
this.walletdb.writeTX(this.wallet, hash, wids);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove from the global tx record.
|
||||||
|
* @param {TX} tx
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
TXDB.prototype.removeTXRecord = co(function* removeTXRecord(tx) {
|
TXDB.prototype.removeTXRecord = co(function* removeTXRecord(tx) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var wids = yield this.walletdb.getWalletsByTX(hash);
|
var wids = yield this.walletdb.getWalletsByTX(hash);
|
||||||
@ -893,6 +905,7 @@ TXDB.prototype.removeTXRecord = co(function* removeTXRecord(tx) {
|
|||||||
|
|
||||||
if (tx.height !== -1) {
|
if (tx.height !== -1) {
|
||||||
block = yield this.walletdb.getBlock(tx.height);
|
block = yield this.walletdb.getBlock(tx.height);
|
||||||
|
assert(block);
|
||||||
|
|
||||||
if (block.remove(hash, this.wallet.wid))
|
if (block.remove(hash, this.wallet.wid))
|
||||||
this.walletdb.writeBlock(this.wallet, block);
|
this.walletdb.writeBlock(this.wallet, block);
|
||||||
@ -906,12 +919,19 @@ TXDB.prototype.removeTXRecord = co(function* removeTXRecord(tx) {
|
|||||||
this.walletdb.writeTX(this.wallet, hash, wids);
|
this.walletdb.writeTX(this.wallet, hash, wids);
|
||||||
});
|
});
|
||||||
|
|
||||||
TXDB.prototype.addBlockRecord = co(function* addBlockRecord(tx, record) {
|
/**
|
||||||
|
* Append to the global block record.
|
||||||
|
* @param {TX} tx
|
||||||
|
* @param {Number} height
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
TXDB.prototype.addBlockRecord = co(function* addBlockRecord(tx, height) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var block = yield this.walletdb.getBlock(record.height);
|
var block = yield this.walletdb.getBlock(height);
|
||||||
|
|
||||||
if (!block)
|
if (!block)
|
||||||
block = record.clone();
|
block = new WalletBlock(tx.block, tx.height, tx.ts);
|
||||||
|
|
||||||
if (!block.add(hash, this.wallet.wid))
|
if (!block.add(hash, this.wallet.wid))
|
||||||
return;
|
return;
|
||||||
@ -919,6 +939,13 @@ TXDB.prototype.addBlockRecord = co(function* addBlockRecord(tx, record) {
|
|||||||
this.walletdb.writeBlock(this.wallet, block);
|
this.walletdb.writeBlock(this.wallet, block);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove from the global block record.
|
||||||
|
* @param {TX}
|
||||||
|
* @param {Number} height
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
TXDB.prototype.removeBlockRecord = co(function* removeBlockRecord(tx, height) {
|
TXDB.prototype.removeBlockRecord = co(function* removeBlockRecord(tx, height) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var block = yield this.walletdb.getBlock(height);
|
var block = yield this.walletdb.getBlock(height);
|
||||||
@ -985,6 +1012,9 @@ TXDB.prototype._add = co(function* add(tx, block) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Save the index (can't get this elsewhere).
|
// Save the index (can't get this elsewhere).
|
||||||
|
existing.height = tx.height;
|
||||||
|
existing.block = tx.block;
|
||||||
|
existing.ts = tx.ts;
|
||||||
existing.index = tx.index;
|
existing.index = tx.index;
|
||||||
|
|
||||||
// Confirm transaction.
|
// Confirm transaction.
|
||||||
@ -1026,7 +1056,7 @@ TXDB.prototype._add = co(function* add(tx, block) {
|
|||||||
|
|
||||||
TXDB.prototype.insert = co(function* insert(tx, block) {
|
TXDB.prototype.insert = co(function* insert(tx, block) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var height = block ? block.height : this.walletdb.height;
|
var height = this.walletdb.height + 1;
|
||||||
var details = new Details(this, tx, height);
|
var details = new Details(this, tx, height);
|
||||||
var updated = false;
|
var updated = false;
|
||||||
var i, input, output, coin;
|
var i, input, output, coin;
|
||||||
@ -1164,8 +1194,8 @@ TXDB.prototype.insert = co(function* insert(tx, block) {
|
|||||||
|
|
||||||
yield this.addTXRecord(tx);
|
yield this.addTXRecord(tx);
|
||||||
|
|
||||||
if (block)
|
if (tx.height !== -1)
|
||||||
yield this.addBlockRecord(tx, block);
|
yield this.addBlockRecord(tx, tx.height);
|
||||||
|
|
||||||
// Update the transaction counter and
|
// Update the transaction counter and
|
||||||
// commit the new state. This state will
|
// commit the new state. This state will
|
||||||
@ -1226,18 +1256,11 @@ TXDB.prototype.confirm = co(function* confirm(hash, block) {
|
|||||||
|
|
||||||
TXDB.prototype._confirm = co(function* confirm(tx, block) {
|
TXDB.prototype._confirm = co(function* confirm(tx, block) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var height = block ? block.height : this.walletdb.height;
|
var height = this.walletdb.height + 1;
|
||||||
var details = new Details(this, tx, height);
|
var details = new Details(this, tx, height);
|
||||||
var i, account, output, coin, input, prevout;
|
var i, account, output, coin, input, prevout;
|
||||||
var path, credit, credits;
|
var path, credit, credits;
|
||||||
|
|
||||||
if (!block)
|
|
||||||
block = this.wallet.db.tip;
|
|
||||||
|
|
||||||
tx.height = block.height;
|
|
||||||
tx.block = block.hash;
|
|
||||||
tx.ts = block.ts;
|
|
||||||
|
|
||||||
if (!tx.isCoinbase()) {
|
if (!tx.isCoinbase()) {
|
||||||
credits = yield this.getSpentCredits(tx);
|
credits = yield this.getSpentCredits(tx);
|
||||||
|
|
||||||
@ -1332,8 +1355,8 @@ TXDB.prototype._confirm = co(function* confirm(tx, block) {
|
|||||||
|
|
||||||
yield this.addTXRecord(tx);
|
yield this.addTXRecord(tx);
|
||||||
|
|
||||||
if (block)
|
if (tx.height !== -1)
|
||||||
yield this.addBlockRecord(tx, block);
|
yield this.addBlockRecord(tx, tx.height);
|
||||||
|
|
||||||
// Commit the new state. The balance has updated.
|
// Commit the new state. The balance has updated.
|
||||||
this.put(layout.R, this.pending.commit());
|
this.put(layout.R, this.pending.commit());
|
||||||
@ -1558,7 +1581,7 @@ TXDB.prototype._unconfirm = co(function* unconfirm(hash, block) {
|
|||||||
|
|
||||||
TXDB.prototype.disconnect = co(function* disconnect(tx, block) {
|
TXDB.prototype.disconnect = co(function* disconnect(tx, block) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var details = new Details(this, tx, block.height - 1);
|
var details = new Details(this, tx, this.walletdb.height - 1);
|
||||||
var height = tx.height;
|
var height = tx.height;
|
||||||
var i, account, output, coin, credits;
|
var i, account, output, coin, credits;
|
||||||
var input, path, credit;
|
var input, path, credit;
|
||||||
@ -1630,7 +1653,7 @@ TXDB.prototype.disconnect = co(function* disconnect(tx, block) {
|
|||||||
this.saveCredit(credit, path);
|
this.saveCredit(credit, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield this.removeBlockRecord(tx, block.height);
|
yield this.removeBlockRecord(tx, height);
|
||||||
|
|
||||||
// We need to update the now-removed
|
// We need to update the now-removed
|
||||||
// block properties and reindex due
|
// block properties and reindex due
|
||||||
|
|||||||
310
lib/wallet/walletblock.js
Normal file
310
lib/wallet/walletblock.js
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
/*!
|
||||||
|
* walletdb.js - storage for wallets
|
||||||
|
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
||||||
|
* 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 Block
|
||||||
|
* @constructor
|
||||||
|
* @param {Hash} hash
|
||||||
|
* @param {Number} height
|
||||||
|
*/
|
||||||
|
|
||||||
|
function WalletBlock(hash, height, ts) {
|
||||||
|
if (!(this instanceof WalletBlock))
|
||||||
|
return new WalletBlock(hash, height, ts);
|
||||||
|
|
||||||
|
this.hash = hash || constants.NULL_HASH;
|
||||||
|
this.height = height != null ? height : -1;
|
||||||
|
this.ts = ts || 0;
|
||||||
|
this.txs = [];
|
||||||
|
this.index = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone the block.
|
||||||
|
* @returns {WalletBlock}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.prototype.clone = function clone() {
|
||||||
|
return new WalletBlock(this.hash, this.height, this.ts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate wallet block from chain entry.
|
||||||
|
* @private
|
||||||
|
* @param {ChainEntry} entry
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.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
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.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 data.
|
||||||
|
* @private
|
||||||
|
* @param {Hash} hash
|
||||||
|
* @param {Buffer} data
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.prototype.fromRaw = function fromRaw(data) {
|
||||||
|
var p = new BufferReader(data);
|
||||||
|
var i, hash, tx, count;
|
||||||
|
|
||||||
|
this.hash = p.readHash('hex');
|
||||||
|
this.height = p.readU32();
|
||||||
|
this.ts = p.readU32();
|
||||||
|
|
||||||
|
while (p.left()) {
|
||||||
|
hash = p.readHash('hex');
|
||||||
|
tx = new TXHash(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 tip data.
|
||||||
|
* @private
|
||||||
|
* @param {Buffer} data
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.prototype.fromTip = function fromTip(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 {WalletBlock}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.fromEntry = function fromEntry(entry) {
|
||||||
|
return new WalletBlock().fromEntry(entry);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate wallet block from json object.
|
||||||
|
* @param {Object} json
|
||||||
|
* @returns {WalletBlock}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.fromJSON = function fromJSON(json) {
|
||||||
|
return new WalletBlock().fromJSON(json);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate wallet block from serialized data.
|
||||||
|
* @param {Hash} hash
|
||||||
|
* @param {Buffer} data
|
||||||
|
* @returns {WalletBlock}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.fromRaw = function fromRaw(data) {
|
||||||
|
return new WalletBlock().fromRaw(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate wallet block from serialized tip data.
|
||||||
|
* @private
|
||||||
|
* @param {Buffer} data
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.fromTip = function fromTip(data) {
|
||||||
|
return new WalletBlock().fromTip(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the wallet block as a tip (hash and height).
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.prototype.toTip = function toTip(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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the wallet block as a block.
|
||||||
|
* Contains matching transaction hashes.
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.prototype.toRaw = function toRaw(writer) {
|
||||||
|
var p = new BufferWriter(writer);
|
||||||
|
var i, j, tx;
|
||||||
|
|
||||||
|
p.writeHash(this.hash);
|
||||||
|
p.writeU32(this.height);
|
||||||
|
p.writeU32(this.ts);
|
||||||
|
|
||||||
|
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}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.prototype.add = function add(hash, wid) {
|
||||||
|
var tx = this.index[hash];
|
||||||
|
|
||||||
|
if (!tx) {
|
||||||
|
tx = new TXHash(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}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the block to a more json-friendly object.
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletBlock.prototype.toJSON = function toJSON() {
|
||||||
|
return {
|
||||||
|
hash: utils.revHex(this.hash),
|
||||||
|
height: this.height
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TX Hash
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
|
function TXHash(hash, wids) {
|
||||||
|
this.hash = hash || constants.NULL_HASH;
|
||||||
|
this.wids = wids || [];
|
||||||
|
this.id = TXHash.id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
TXHash.id = 0;
|
||||||
|
|
||||||
|
TXHash.prototype.add = function add(wid) {
|
||||||
|
return utils.binaryInsert(this.wids, wid, cmp, true) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
TXHash.prototype.remove = function remove(wid) {
|
||||||
|
return utils.binaryRemove(this.wids, wid, cmp);
|
||||||
|
};
|
||||||
|
|
||||||
|
TXHash.prototype.toRaw = function toRaw(writer) {
|
||||||
|
return serializeWallets(this.wids, writer);
|
||||||
|
};
|
||||||
|
|
||||||
|
TXHash.prototype.fromRaw = function fromRaw(data) {
|
||||||
|
return parseWallets(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
TXHash.fromRaw = function fromRaw(hash, data) {
|
||||||
|
return new TXHash(hash).fromRaw(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helpers
|
||||||
|
*/
|
||||||
|
|
||||||
|
function cmp(a, b) {
|
||||||
|
return a - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cmpid(a, b) {
|
||||||
|
return a.id - b.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expose
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = WalletBlock;
|
||||||
|
exports.WalletBlock = WalletBlock;
|
||||||
|
exports.TXHash = TXHash;
|
||||||
|
|
||||||
|
module.exports = exports;
|
||||||
@ -25,6 +25,7 @@ var ldb = require('../db/ldb');
|
|||||||
var Bloom = require('../utils/bloom');
|
var Bloom = require('../utils/bloom');
|
||||||
var Logger = require('../node/logger');
|
var Logger = require('../node/logger');
|
||||||
var TX = require('../primitives/tx');
|
var TX = require('../primitives/tx');
|
||||||
|
var WalletBlock = require('./walletblock');
|
||||||
var TXDB = require('./txdb');
|
var TXDB = require('./txdb');
|
||||||
var U32 = utils.U32;
|
var U32 = utils.U32;
|
||||||
|
|
||||||
@ -1804,279 +1805,10 @@ WalletDB.prototype._zap = co(function* zap(age) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Wallet Block
|
|
||||||
* @constructor
|
|
||||||
* @param {Hash} hash
|
|
||||||
* @param {Number} height
|
|
||||||
*/
|
|
||||||
|
|
||||||
function WalletBlock(hash, height, ts) {
|
|
||||||
if (!(this instanceof WalletBlock))
|
|
||||||
return new WalletBlock(hash, height, ts);
|
|
||||||
|
|
||||||
this.hash = hash || constants.NULL_HASH;
|
|
||||||
this.height = height != null ? height : -1;
|
|
||||||
this.ts = ts || 0;
|
|
||||||
this.txs = [];
|
|
||||||
this.index = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clone the block.
|
|
||||||
* @returns {WalletBlock}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.prototype.clone = function clone() {
|
|
||||||
return new WalletBlock(this.hash, this.height, this.ts);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate wallet block from chain entry.
|
|
||||||
* @private
|
|
||||||
* @param {ChainEntry} entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.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
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.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 data.
|
|
||||||
* @private
|
|
||||||
* @param {Hash} hash
|
|
||||||
* @param {Buffer} data
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.prototype.fromRaw = function fromRaw(data) {
|
|
||||||
var p = new BufferReader(data);
|
|
||||||
var i, hash, tx, count;
|
|
||||||
|
|
||||||
this.hash = p.readHash('hex');
|
|
||||||
this.height = p.readU32();
|
|
||||||
this.ts = p.readU32();
|
|
||||||
|
|
||||||
while (p.left()) {
|
|
||||||
hash = p.readHash('hex');
|
|
||||||
tx = new TXHash(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 tip data.
|
|
||||||
* @private
|
|
||||||
* @param {Buffer} data
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.prototype.fromTip = function fromTip(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 {WalletBlock}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.fromEntry = function fromEntry(entry) {
|
|
||||||
return new WalletBlock().fromEntry(entry);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate wallet block from json object.
|
|
||||||
* @param {Object} json
|
|
||||||
* @returns {WalletBlock}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.fromJSON = function fromJSON(json) {
|
|
||||||
return new WalletBlock().fromJSON(json);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate wallet block from serialized data.
|
|
||||||
* @param {Hash} hash
|
|
||||||
* @param {Buffer} data
|
|
||||||
* @returns {WalletBlock}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.fromRaw = function fromRaw(data) {
|
|
||||||
return new WalletBlock().fromRaw(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate wallet block from serialized tip data.
|
|
||||||
* @private
|
|
||||||
* @param {Buffer} data
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.fromTip = function fromTip(data) {
|
|
||||||
return new WalletBlock().fromTip(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize the wallet block as a tip (hash and height).
|
|
||||||
* @returns {Buffer}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.prototype.toTip = function toTip(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;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize the wallet block as a block.
|
|
||||||
* Contains matching transaction hashes.
|
|
||||||
* @returns {Buffer}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.prototype.toRaw = function toRaw(writer) {
|
|
||||||
var p = new BufferWriter(writer);
|
|
||||||
var i, j, tx;
|
|
||||||
|
|
||||||
p.writeHash(this.hash);
|
|
||||||
p.writeU32(this.height);
|
|
||||||
p.writeU32(this.ts);
|
|
||||||
|
|
||||||
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}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.prototype.add = function add(hash, wid) {
|
|
||||||
var tx = this.index[hash];
|
|
||||||
|
|
||||||
if (!tx) {
|
|
||||||
tx = new TXHash(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}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.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;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the block to a more json-friendly object.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletBlock.prototype.toJSON = function toJSON() {
|
|
||||||
return {
|
|
||||||
hash: utils.revHex(this.hash),
|
|
||||||
height: this.height
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helpers
|
* Helpers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function TXHash(hash, wids) {
|
|
||||||
this.hash = hash || constants.NULL_HASH;
|
|
||||||
this.wids = wids || [];
|
|
||||||
this.id = TXHash.id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
TXHash.id = 0;
|
|
||||||
|
|
||||||
TXHash.prototype.add = function add(wid) {
|
|
||||||
return utils.binaryInsert(this.wids, wid, cmp, true) !== -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
TXHash.prototype.remove = function remove(wid) {
|
|
||||||
return utils.binaryRemove(this.wids, wid, cmp);
|
|
||||||
};
|
|
||||||
|
|
||||||
TXHash.prototype.toRaw = function toRaw(writer) {
|
|
||||||
return serializeWallets(this.wids, writer);
|
|
||||||
};
|
|
||||||
|
|
||||||
TXHash.prototype.fromRaw = function fromRaw(data) {
|
|
||||||
return parseWallets(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
TXHash.fromRaw = function fromRaw(hash, data) {
|
|
||||||
return new TXHash(hash).fromRaw(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
function parseWallets(data) {
|
function parseWallets(data) {
|
||||||
var p = new BufferReader(data);
|
var p = new BufferReader(data);
|
||||||
var wids = [];
|
var wids = [];
|
||||||
@ -2106,10 +1838,6 @@ function cmp(a, b) {
|
|||||||
return a - b;
|
return a - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmpid(a, b) {
|
|
||||||
return a.id - b.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user