wallet: classify.
This commit is contained in:
parent
9240d2f827
commit
f313ca166d
@ -908,7 +908,7 @@ class ChainDB {
|
|||||||
return this.db.values({
|
return this.db.values({
|
||||||
gte: layout.e(encoding.ZERO_HASH),
|
gte: layout.e(encoding.ZERO_HASH),
|
||||||
lte: layout.e(encoding.MAX_HASH),
|
lte: layout.e(encoding.MAX_HASH),
|
||||||
parse: value => ChainEntry.fromRaw(value)
|
parse: data => ChainEntry.fromRaw(data)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -26,14 +26,16 @@ const HDPrivateKey = require('../hd/private');
|
|||||||
const HDPublicKey = require('../hd/public');
|
const HDPublicKey = require('../hd/public');
|
||||||
const common = require('./common');
|
const common = require('./common');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP
|
||||||
|
* @alias module:wallet.HTTP
|
||||||
|
*/
|
||||||
|
|
||||||
class HTTP extends Server {
|
class HTTP extends Server {
|
||||||
/**
|
/**
|
||||||
* HTTP
|
* Create an http server.
|
||||||
* @alias module:wallet.HTTP
|
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @see HTTPBase
|
|
||||||
* @emits HTTP#socket
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -10,159 +10,160 @@ const assert = require('assert');
|
|||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NullClient
|
* Null Client
|
||||||
* Sort of a fake local client for separation of concerns.
|
* Sort of a fake local client for separation of concerns.
|
||||||
* @alias module:node.NullClient
|
* @alias module:node.NullClient
|
||||||
* @constructor
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function NullClient(wdb) {
|
class NullClient extends EventEmitter {
|
||||||
if (!(this instanceof NullClient))
|
/**
|
||||||
return new NullClient(wdb);
|
* Create a client.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
EventEmitter.call(this);
|
constructor(wdb) {
|
||||||
|
super();
|
||||||
|
|
||||||
this.wdb = wdb;
|
this.wdb = wdb;
|
||||||
this.network = wdb.network;
|
this.network = wdb.network;
|
||||||
this.opened = false;
|
this.opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the client.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async open(options) {
|
||||||
|
assert(!this.opened, 'NullClient is already open.');
|
||||||
|
this.opened = true;
|
||||||
|
setImmediate(() => this.emit('connect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the client.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
assert(this.opened, 'NullClient is not open.');
|
||||||
|
this.opened = false;
|
||||||
|
setImmediate(() => this.emit('disconnect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a listener.
|
||||||
|
* @param {String} type
|
||||||
|
* @param {Function} handler
|
||||||
|
*/
|
||||||
|
|
||||||
|
bind(type, handler) {
|
||||||
|
return this.on(type, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a listener.
|
||||||
|
* @param {String} type
|
||||||
|
* @param {Function} handler
|
||||||
|
*/
|
||||||
|
|
||||||
|
hook(type, handler) {
|
||||||
|
return this.on(type, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get chain tip.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getTip() {
|
||||||
|
const {hash, height, time} = this.network.genesis;
|
||||||
|
return { hash, height, time };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get chain entry.
|
||||||
|
* @param {Hash} hash
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getEntry(hash) {
|
||||||
|
return { hash, height: 0, time: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a transaction. Do not wait for promise.
|
||||||
|
* @param {TX} tx
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async send(tx) {
|
||||||
|
this.wdb.emit('send', tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set bloom filter.
|
||||||
|
* @param {Bloom} filter
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async setFilter(filter) {
|
||||||
|
this.wdb.emit('set filter', filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add data to filter.
|
||||||
|
* @param {Buffer} data
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async addFilter(data) {
|
||||||
|
this.wdb.emit('add filter', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset filter.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async resetFilter() {
|
||||||
|
this.wdb.emit('reset filter');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Esimate smart fee.
|
||||||
|
* @param {Number?} blocks
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async estimateFee(blocks) {
|
||||||
|
return this.network.feeRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get hash range.
|
||||||
|
* @param {Number} start
|
||||||
|
* @param {Number} end
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getHashes(start = -1, end = -1) {
|
||||||
|
return [this.network.genesis.hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rescan for any missed transactions.
|
||||||
|
* @param {Number|Hash} start - Start block.
|
||||||
|
* @param {Bloom} filter
|
||||||
|
* @param {Function} iter - Iterator.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async rescan(start) {
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(NullClient.prototype, EventEmitter.prototype);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open the client.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.open = async function open(options) {
|
|
||||||
assert(!this.opened, 'NullClient is already open.');
|
|
||||||
this.opened = true;
|
|
||||||
setImmediate(() => this.emit('connect'));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the client.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.close = async function close() {
|
|
||||||
assert(this.opened, 'NullClient is not open.');
|
|
||||||
this.opened = false;
|
|
||||||
setImmediate(() => this.emit('disconnect'));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a listener.
|
|
||||||
* @param {String} type
|
|
||||||
* @param {Function} handler
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.bind = function bind(type, handler) {
|
|
||||||
return this.on(type, handler);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a listener.
|
|
||||||
* @param {String} type
|
|
||||||
* @param {Function} handler
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.hook = function hook(type, handler) {
|
|
||||||
return this.on(type, handler);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get chain tip.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.getTip = async function getTip() {
|
|
||||||
const {hash, height, time} = this.network.genesis;
|
|
||||||
return { hash, height, time };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get chain entry.
|
|
||||||
* @param {Hash} hash
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.getEntry = async function getEntry(hash) {
|
|
||||||
return { hash, height: 0, time: 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a transaction. Do not wait for promise.
|
|
||||||
* @param {TX} tx
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.send = async function send(tx) {
|
|
||||||
this.wdb.emit('send', tx);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set bloom filter.
|
|
||||||
* @param {Bloom} filter
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.setFilter = async function setFilter(filter) {
|
|
||||||
this.wdb.emit('set filter', filter);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add data to filter.
|
|
||||||
* @param {Buffer} data
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.addFilter = async function addFilter(data) {
|
|
||||||
this.wdb.emit('add filter', data);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset filter.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.resetFilter = async function resetFilter() {
|
|
||||||
this.wdb.emit('reset filter');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Esimate smart fee.
|
|
||||||
* @param {Number?} blocks
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.estimateFee = async function estimateFee(blocks) {
|
|
||||||
return this.network.feeRate;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get hash range.
|
|
||||||
* @param {Number} start
|
|
||||||
* @param {Number} end
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.getHashes = async function getHashes(start = -1, end = -1) {
|
|
||||||
return [this.network.genesis.hash];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rescan for any missed transactions.
|
|
||||||
* @param {Number|Hash} start - Start block.
|
|
||||||
* @param {Bloom} filter
|
|
||||||
* @param {Function} iter - Iterator.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
NullClient.prototype.rescan = async function rescan(start) {
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -14,36 +14,283 @@ const {encoding} = bio;
|
|||||||
/**
|
/**
|
||||||
* Path
|
* Path
|
||||||
* @alias module:wallet.Path
|
* @alias module:wallet.Path
|
||||||
* @constructor
|
|
||||||
* @property {WalletID} wid
|
|
||||||
* @property {String} name - Account name.
|
* @property {String} name - Account name.
|
||||||
* @property {Number} account - Account index.
|
* @property {Number} account - Account index.
|
||||||
* @property {Number} branch - Branch index.
|
* @property {Number} branch - Branch index.
|
||||||
* @property {Number} index - Address index.
|
* @property {Number} index - Address index.
|
||||||
* @property {Address|null} address
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Path(options) {
|
class Path {
|
||||||
if (!(this instanceof Path))
|
/**
|
||||||
return new Path(options);
|
* Create a path.
|
||||||
|
* @constructor
|
||||||
|
* @param {Object?} options
|
||||||
|
*/
|
||||||
|
|
||||||
this.keyType = Path.types.HD;
|
constructor(options) {
|
||||||
|
this.keyType = Path.types.HD;
|
||||||
|
|
||||||
this.name = null; // Passed in by caller.
|
this.name = null; // Passed in by caller.
|
||||||
this.account = 0;
|
this.account = 0;
|
||||||
this.branch = -1;
|
this.branch = -1;
|
||||||
this.index = -1;
|
this.index = -1;
|
||||||
|
|
||||||
this.encrypted = false;
|
this.encrypted = false;
|
||||||
this.data = null;
|
this.data = null;
|
||||||
|
|
||||||
// Currently unused.
|
// Currently unused.
|
||||||
this.type = Address.types.PUBKEYHASH;
|
this.type = Address.types.PUBKEYHASH;
|
||||||
this.version = -1;
|
this.version = -1;
|
||||||
this.hash = null; // Passed in by caller.
|
this.hash = null; // Passed in by caller.
|
||||||
|
|
||||||
if (options)
|
if (options)
|
||||||
this.fromOptions(options);
|
this.fromOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate path from options object.
|
||||||
|
* @private
|
||||||
|
* @param {Object} options
|
||||||
|
* @returns {Path}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fromOptions(options) {
|
||||||
|
this.keyType = options.keyType;
|
||||||
|
|
||||||
|
this.name = options.name;
|
||||||
|
this.account = options.account;
|
||||||
|
this.branch = options.branch;
|
||||||
|
this.index = options.index;
|
||||||
|
|
||||||
|
this.encrypted = options.encrypted;
|
||||||
|
this.data = options.data;
|
||||||
|
|
||||||
|
this.type = options.type;
|
||||||
|
this.version = options.version;
|
||||||
|
this.hash = options.hash;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate path from options object.
|
||||||
|
* @param {Object} options
|
||||||
|
* @returns {Path}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fromOptions(options) {
|
||||||
|
return new this().fromOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone the path object.
|
||||||
|
* @returns {Path}
|
||||||
|
*/
|
||||||
|
|
||||||
|
clone() {
|
||||||
|
const path = new this.constructor();
|
||||||
|
|
||||||
|
path.keyType = this.keyType;
|
||||||
|
|
||||||
|
path.name = this.name;
|
||||||
|
path.account = this.account;
|
||||||
|
path.branch = this.branch;
|
||||||
|
path.index = this.index;
|
||||||
|
|
||||||
|
path.encrypted = this.encrypted;
|
||||||
|
path.data = this.data;
|
||||||
|
|
||||||
|
path.type = this.type;
|
||||||
|
path.version = this.version;
|
||||||
|
path.hash = this.hash;
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject properties from serialized data.
|
||||||
|
* @private
|
||||||
|
* @param {Buffer} data
|
||||||
|
*/
|
||||||
|
|
||||||
|
fromRaw(data) {
|
||||||
|
const br = bio.read(data);
|
||||||
|
|
||||||
|
this.account = br.readU32();
|
||||||
|
this.keyType = br.readU8();
|
||||||
|
|
||||||
|
switch (this.keyType) {
|
||||||
|
case Path.types.HD:
|
||||||
|
this.branch = br.readU32();
|
||||||
|
this.index = br.readU32();
|
||||||
|
break;
|
||||||
|
case Path.types.KEY:
|
||||||
|
this.encrypted = br.readU8() === 1;
|
||||||
|
this.data = br.readVarBytes();
|
||||||
|
break;
|
||||||
|
case Path.types.ADDRESS:
|
||||||
|
// Hash will be passed in by caller.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.version = br.readI8();
|
||||||
|
this.type = br.readU8();
|
||||||
|
|
||||||
|
if (this.type === 129 || this.type === 130)
|
||||||
|
this.type = 4;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate path from serialized data.
|
||||||
|
* @param {Buffer} data
|
||||||
|
* @returns {Path}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fromRaw(data) {
|
||||||
|
return new this().fromRaw(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate serialization size.
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
|
||||||
|
getSize() {
|
||||||
|
let size = 0;
|
||||||
|
|
||||||
|
size += 5;
|
||||||
|
|
||||||
|
switch (this.keyType) {
|
||||||
|
case Path.types.HD:
|
||||||
|
size += 8;
|
||||||
|
break;
|
||||||
|
case Path.types.KEY:
|
||||||
|
size += 1;
|
||||||
|
size += encoding.sizeVarBytes(this.data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size += 2;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize path.
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
|
toRaw() {
|
||||||
|
const size = this.getSize();
|
||||||
|
const bw = bio.write(size);
|
||||||
|
|
||||||
|
bw.writeU32(this.account);
|
||||||
|
bw.writeU8(this.keyType);
|
||||||
|
|
||||||
|
switch (this.keyType) {
|
||||||
|
case Path.types.HD:
|
||||||
|
assert(!this.data);
|
||||||
|
assert(this.index !== -1);
|
||||||
|
bw.writeU32(this.branch);
|
||||||
|
bw.writeU32(this.index);
|
||||||
|
break;
|
||||||
|
case Path.types.KEY:
|
||||||
|
assert(this.data);
|
||||||
|
assert(this.index === -1);
|
||||||
|
bw.writeU8(this.encrypted ? 1 : 0);
|
||||||
|
bw.writeVarBytes(this.data);
|
||||||
|
break;
|
||||||
|
case Path.types.ADDRESS:
|
||||||
|
assert(!this.data);
|
||||||
|
assert(this.index === -1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bw.writeI8(this.version);
|
||||||
|
bw.writeU8(this.type);
|
||||||
|
|
||||||
|
return bw.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject properties from address.
|
||||||
|
* @private
|
||||||
|
* @param {Account} account
|
||||||
|
* @param {Address} address
|
||||||
|
*/
|
||||||
|
|
||||||
|
fromAddress(account, address) {
|
||||||
|
this.keyType = Path.types.ADDRESS;
|
||||||
|
this.name = account.name;
|
||||||
|
this.account = account.accountIndex;
|
||||||
|
this.version = address.version;
|
||||||
|
this.type = address.type;
|
||||||
|
this.hash = address.getHash('hex');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate path from address.
|
||||||
|
* @param {Account} account
|
||||||
|
* @param {Address} address
|
||||||
|
* @returns {Path}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fromAddress(account, address) {
|
||||||
|
return new this().fromAddress(account, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert path object to string derivation path.
|
||||||
|
* @returns {String}
|
||||||
|
*/
|
||||||
|
|
||||||
|
toPath() {
|
||||||
|
if (this.keyType !== Path.types.HD)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return `m/${this.account}'/${this.branch}/${this.index}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert path object to an address (currently unused).
|
||||||
|
* @returns {Address}
|
||||||
|
*/
|
||||||
|
|
||||||
|
toAddress() {
|
||||||
|
return Address.fromHash(this.hash, this.type, this.version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert path to a json-friendly object.
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
name: this.name,
|
||||||
|
account: this.account,
|
||||||
|
change: this.branch === 1,
|
||||||
|
derivation: this.toPath()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inspect the path.
|
||||||
|
* @returns {String}
|
||||||
|
*/
|
||||||
|
|
||||||
|
inspect() {
|
||||||
|
return `<Path: ${this.name}:${this.toPath()}>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,249 +306,16 @@ Path.types = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate path from options object.
|
* Path types.
|
||||||
* @private
|
* @enum {Number}
|
||||||
* @param {Object} options
|
* @default
|
||||||
* @returns {Path}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Path.prototype.fromOptions = function fromOptions(options) {
|
Path.typesByVal = [
|
||||||
this.keyType = options.keyType;
|
'HD',
|
||||||
|
'KEY',
|
||||||
this.name = options.name;
|
'ADDRESS'
|
||||||
this.account = options.account;
|
];
|
||||||
this.branch = options.branch;
|
|
||||||
this.index = options.index;
|
|
||||||
|
|
||||||
this.encrypted = options.encrypted;
|
|
||||||
this.data = options.data;
|
|
||||||
|
|
||||||
this.type = options.type;
|
|
||||||
this.version = options.version;
|
|
||||||
this.hash = options.hash;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate path from options object.
|
|
||||||
* @param {Object} options
|
|
||||||
* @returns {Path}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.fromOptions = function fromOptions(options) {
|
|
||||||
return new Path().fromOptions(options);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clone the path object.
|
|
||||||
* @returns {Path}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.clone = function clone() {
|
|
||||||
const path = new Path();
|
|
||||||
|
|
||||||
path.keyType = this.keyType;
|
|
||||||
|
|
||||||
path.name = this.name;
|
|
||||||
path.account = this.account;
|
|
||||||
path.branch = this.branch;
|
|
||||||
path.index = this.index;
|
|
||||||
|
|
||||||
path.encrypted = this.encrypted;
|
|
||||||
path.data = this.data;
|
|
||||||
|
|
||||||
path.type = this.type;
|
|
||||||
path.version = this.version;
|
|
||||||
path.hash = this.hash;
|
|
||||||
|
|
||||||
return path;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inject properties from serialized data.
|
|
||||||
* @private
|
|
||||||
* @param {Buffer} data
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.fromRaw = function fromRaw(data) {
|
|
||||||
const br = bio.read(data);
|
|
||||||
|
|
||||||
this.account = br.readU32();
|
|
||||||
this.keyType = br.readU8();
|
|
||||||
|
|
||||||
switch (this.keyType) {
|
|
||||||
case Path.types.HD:
|
|
||||||
this.branch = br.readU32();
|
|
||||||
this.index = br.readU32();
|
|
||||||
break;
|
|
||||||
case Path.types.KEY:
|
|
||||||
this.encrypted = br.readU8() === 1;
|
|
||||||
this.data = br.readVarBytes();
|
|
||||||
break;
|
|
||||||
case Path.types.ADDRESS:
|
|
||||||
// Hash will be passed in by caller.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.version = br.readI8();
|
|
||||||
this.type = br.readU8();
|
|
||||||
|
|
||||||
if (this.type === 129 || this.type === 130)
|
|
||||||
this.type = 4;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate path from serialized data.
|
|
||||||
* @param {Buffer} data
|
|
||||||
* @returns {Path}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.fromRaw = function fromRaw(data) {
|
|
||||||
return new Path().fromRaw(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate serialization size.
|
|
||||||
* @returns {Number}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.getSize = function getSize() {
|
|
||||||
let size = 0;
|
|
||||||
|
|
||||||
size += 5;
|
|
||||||
|
|
||||||
switch (this.keyType) {
|
|
||||||
case Path.types.HD:
|
|
||||||
size += 8;
|
|
||||||
break;
|
|
||||||
case Path.types.KEY:
|
|
||||||
size += 1;
|
|
||||||
size += encoding.sizeVarBytes(this.data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
size += 2;
|
|
||||||
|
|
||||||
return size;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize path.
|
|
||||||
* @returns {Buffer}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.toRaw = function toRaw() {
|
|
||||||
const size = this.getSize();
|
|
||||||
const bw = bio.write(size);
|
|
||||||
|
|
||||||
bw.writeU32(this.account);
|
|
||||||
bw.writeU8(this.keyType);
|
|
||||||
|
|
||||||
switch (this.keyType) {
|
|
||||||
case Path.types.HD:
|
|
||||||
assert(!this.data);
|
|
||||||
assert(this.index !== -1);
|
|
||||||
bw.writeU32(this.branch);
|
|
||||||
bw.writeU32(this.index);
|
|
||||||
break;
|
|
||||||
case Path.types.KEY:
|
|
||||||
assert(this.data);
|
|
||||||
assert(this.index === -1);
|
|
||||||
bw.writeU8(this.encrypted ? 1 : 0);
|
|
||||||
bw.writeVarBytes(this.data);
|
|
||||||
break;
|
|
||||||
case Path.types.ADDRESS:
|
|
||||||
assert(!this.data);
|
|
||||||
assert(this.index === -1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bw.writeI8(this.version);
|
|
||||||
bw.writeU8(this.type);
|
|
||||||
|
|
||||||
return bw.render();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inject properties from address.
|
|
||||||
* @private
|
|
||||||
* @param {Account} account
|
|
||||||
* @param {Address} address
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.fromAddress = function fromAddress(account, address) {
|
|
||||||
this.keyType = Path.types.ADDRESS;
|
|
||||||
this.name = account.name;
|
|
||||||
this.account = account.accountIndex;
|
|
||||||
this.version = address.version;
|
|
||||||
this.type = address.type;
|
|
||||||
this.hash = address.getHash('hex');
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate path from address.
|
|
||||||
* @param {Account} account
|
|
||||||
* @param {Address} address
|
|
||||||
* @returns {Path}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.fromAddress = function fromAddress(account, address) {
|
|
||||||
return new Path().fromAddress(account, address);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert path object to string derivation path.
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.toPath = function toPath() {
|
|
||||||
if (this.keyType !== Path.types.HD)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return `m/${this.account}'/${this.branch}/${this.index}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert path object to an address (currently unused).
|
|
||||||
* @returns {Address}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.toAddress = function toAddress() {
|
|
||||||
return Address.fromHash(this.hash, this.type, this.version);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert path to a json-friendly object.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.toJSON = function toJSON() {
|
|
||||||
return {
|
|
||||||
name: this.name,
|
|
||||||
account: this.account,
|
|
||||||
change: this.branch === 1,
|
|
||||||
derivation: this.toPath()
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inspect the path.
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.inspect = function inspect() {
|
|
||||||
return `<Path: ${this.name}:${this.toPath()}>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose
|
* Expose
|
||||||
|
|||||||
@ -20,71 +20,75 @@ const plugin = exports;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin
|
* Plugin
|
||||||
* @constructor
|
* @extends EventEmitter
|
||||||
* @param {Node} node
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Plugin(node) {
|
class Plugin extends EventEmitter {
|
||||||
if (!(this instanceof Plugin))
|
/**
|
||||||
return new Plugin(node);
|
* Create a plugin.
|
||||||
|
* @constructor
|
||||||
|
* @param {Node} node
|
||||||
|
*/
|
||||||
|
|
||||||
const config = node.config;
|
constructor(node) {
|
||||||
|
super();
|
||||||
|
|
||||||
this.network = node.network;
|
const config = node.config;
|
||||||
this.logger = node.logger;
|
|
||||||
|
|
||||||
this.client = new NodeClient(node);
|
this.network = node.network;
|
||||||
this.plugin = true;
|
this.logger = node.logger;
|
||||||
|
|
||||||
this.wdb = new WalletDB({
|
this.client = new NodeClient(node);
|
||||||
network: node.network,
|
this.plugin = true;
|
||||||
logger: node.logger,
|
|
||||||
workers: node.workers,
|
|
||||||
client: this.client,
|
|
||||||
prefix: config.prefix,
|
|
||||||
db: config.str(['wallet-db', 'db']),
|
|
||||||
maxFiles: config.uint('wallet-max-files'),
|
|
||||||
cacheSize: config.mb('wallet-cache-size'),
|
|
||||||
witness: config.bool('wallet-witness'),
|
|
||||||
checkpoints: config.bool('wallet-checkpoints'),
|
|
||||||
startHeight: config.uint('wallet-start-height'),
|
|
||||||
wipeNoReally: config.bool('wallet-wipe-no-really'),
|
|
||||||
spv: node.spv
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rpc = new RPC(this);
|
this.wdb = new WalletDB({
|
||||||
|
network: node.network,
|
||||||
|
logger: node.logger,
|
||||||
|
workers: node.workers,
|
||||||
|
client: this.client,
|
||||||
|
prefix: config.prefix,
|
||||||
|
db: config.str(['wallet-db', 'db']),
|
||||||
|
maxFiles: config.uint('wallet-max-files'),
|
||||||
|
cacheSize: config.mb('wallet-cache-size'),
|
||||||
|
witness: config.bool('wallet-witness'),
|
||||||
|
checkpoints: config.bool('wallet-checkpoints'),
|
||||||
|
startHeight: config.uint('wallet-start-height'),
|
||||||
|
wipeNoReally: config.bool('wallet-wipe-no-really'),
|
||||||
|
spv: node.spv
|
||||||
|
});
|
||||||
|
|
||||||
this.http = new HTTP({
|
this.rpc = new RPC(this);
|
||||||
network: node.network,
|
|
||||||
logger: node.logger,
|
|
||||||
node: this,
|
|
||||||
apiKey: config.str(['wallet-api-key', 'api-key']),
|
|
||||||
walletAuth: config.bool('wallet-auth'),
|
|
||||||
noAuth: config.bool(['wallet-no-auth', 'no-auth'])
|
|
||||||
});
|
|
||||||
|
|
||||||
this.http.attach('/wallet', node.http);
|
this.http = new HTTP({
|
||||||
|
network: node.network,
|
||||||
|
logger: node.logger,
|
||||||
|
node: this,
|
||||||
|
apiKey: config.str(['wallet-api-key', 'api-key']),
|
||||||
|
walletAuth: config.bool('wallet-auth'),
|
||||||
|
noAuth: config.bool(['wallet-no-auth', 'no-auth'])
|
||||||
|
});
|
||||||
|
|
||||||
this.init();
|
this.http.attach('/wallet', node.http);
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.wdb.on('error', err => this.emit('error', err));
|
||||||
|
this.http.on('error', err => this.emit('error', err));
|
||||||
|
}
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
await this.wdb.open();
|
||||||
|
this.rpc.wallet = this.wdb.primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
this.rpc.wallet = null;
|
||||||
|
await this.wdb.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(Plugin.prototype, EventEmitter.prototype);
|
|
||||||
|
|
||||||
Plugin.prototype.init = function init() {
|
|
||||||
this.wdb.on('error', err => this.emit('error', err));
|
|
||||||
this.http.on('error', err => this.emit('error', err));
|
|
||||||
};
|
|
||||||
|
|
||||||
Plugin.prototype.open = async function open() {
|
|
||||||
await this.wdb.open();
|
|
||||||
this.rpc.wallet = this.wdb.primary;
|
|
||||||
};
|
|
||||||
|
|
||||||
Plugin.prototype.close = async function close() {
|
|
||||||
this.rpc.wallet = this.wdb.primary;
|
|
||||||
await this.wdb.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin name.
|
* Plugin name.
|
||||||
* @const {String}
|
* @const {String}
|
||||||
|
|||||||
@ -18,464 +18,479 @@ const {encoding} = bio;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Chain State
|
* Chain State
|
||||||
* @constructor
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ChainState() {
|
class ChainState {
|
||||||
if (!(this instanceof ChainState))
|
/**
|
||||||
return new ChainState();
|
* Create a chain state.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
this.startHeight = 0;
|
constructor() {
|
||||||
this.startHash = encoding.NULL_HASH;
|
this.startHeight = 0;
|
||||||
this.height = 0;
|
this.startHash = encoding.NULL_HASH;
|
||||||
this.marked = false;
|
this.height = 0;
|
||||||
|
this.marked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone the state.
|
||||||
|
* @returns {ChainState}
|
||||||
|
*/
|
||||||
|
|
||||||
|
clone() {
|
||||||
|
const state = new ChainState();
|
||||||
|
state.startHeight = this.startHeight;
|
||||||
|
state.startHash = this.startHash;
|
||||||
|
state.height = this.height;
|
||||||
|
state.marked = this.marked;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject properties from serialized data.
|
||||||
|
* @private
|
||||||
|
* @param {Buffer} data
|
||||||
|
*/
|
||||||
|
|
||||||
|
fromRaw(data) {
|
||||||
|
const br = bio.read(data);
|
||||||
|
|
||||||
|
this.startHeight = br.readU32();
|
||||||
|
this.startHash = br.readHash('hex');
|
||||||
|
this.height = br.readU32();
|
||||||
|
this.marked = br.readU8() === 1;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate chain state from serialized data.
|
||||||
|
* @param {Hash} hash
|
||||||
|
* @param {Buffer} data
|
||||||
|
* @returns {ChainState}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fromRaw(data) {
|
||||||
|
return new this().fromRaw(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the chain state.
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
|
toRaw() {
|
||||||
|
const bw = bio.write(41);
|
||||||
|
|
||||||
|
bw.writeU32(this.startHeight);
|
||||||
|
bw.writeHash(this.startHash);
|
||||||
|
bw.writeU32(this.height);
|
||||||
|
bw.writeU8(this.marked ? 1 : 0);
|
||||||
|
|
||||||
|
return bw.render();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Clone the state.
|
|
||||||
* @returns {ChainState}
|
|
||||||
*/
|
|
||||||
|
|
||||||
ChainState.prototype.clone = function clone() {
|
|
||||||
const state = new ChainState();
|
|
||||||
state.startHeight = this.startHeight;
|
|
||||||
state.startHash = this.startHash;
|
|
||||||
state.height = this.height;
|
|
||||||
state.marked = this.marked;
|
|
||||||
return state;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inject properties from serialized data.
|
|
||||||
* @private
|
|
||||||
* @param {Buffer} data
|
|
||||||
*/
|
|
||||||
|
|
||||||
ChainState.prototype.fromRaw = function fromRaw(data) {
|
|
||||||
const br = bio.read(data);
|
|
||||||
|
|
||||||
this.startHeight = br.readU32();
|
|
||||||
this.startHash = br.readHash('hex');
|
|
||||||
this.height = br.readU32();
|
|
||||||
this.marked = br.readU8() === 1;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate chain state from serialized data.
|
|
||||||
* @param {Hash} hash
|
|
||||||
* @param {Buffer} data
|
|
||||||
* @returns {ChainState}
|
|
||||||
*/
|
|
||||||
|
|
||||||
ChainState.fromRaw = function fromRaw(data) {
|
|
||||||
return new ChainState().fromRaw(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize the chain state.
|
|
||||||
* @returns {Buffer}
|
|
||||||
*/
|
|
||||||
|
|
||||||
ChainState.prototype.toRaw = function toRaw() {
|
|
||||||
const bw = bio.write(41);
|
|
||||||
|
|
||||||
bw.writeU32(this.startHeight);
|
|
||||||
bw.writeHash(this.startHash);
|
|
||||||
bw.writeU32(this.height);
|
|
||||||
bw.writeU8(this.marked ? 1 : 0);
|
|
||||||
|
|
||||||
return bw.render();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block Meta
|
* Block Meta
|
||||||
* @constructor
|
|
||||||
* @param {Hash} hash
|
|
||||||
* @param {Number} height
|
|
||||||
* @param {Number} time
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function BlockMeta(hash, height, time) {
|
class BlockMeta {
|
||||||
if (!(this instanceof BlockMeta))
|
/**
|
||||||
return new BlockMeta(hash, height, time);
|
* Create block meta.
|
||||||
|
* @constructor
|
||||||
|
* @param {Hash} hash
|
||||||
|
* @param {Number} height
|
||||||
|
* @param {Number} time
|
||||||
|
*/
|
||||||
|
|
||||||
this.hash = hash || encoding.NULL_HASH;
|
constructor(hash, height, time) {
|
||||||
this.height = height != null ? height : -1;
|
this.hash = hash || encoding.NULL_HASH;
|
||||||
this.time = time || 0;
|
this.height = height != null ? height : -1;
|
||||||
}
|
this.time = time || 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Clone the block.
|
|
||||||
* @returns {BlockMeta}
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.prototype.clone = function clone() {
|
|
||||||
return new BlockMeta(this.hash, this.height, this.time);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get block meta hash as a buffer.
|
|
||||||
* @returns {Buffer}
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.prototype.toHash = function toHash() {
|
|
||||||
return Buffer.from(this.hash, 'hex');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate block meta from chain entry.
|
|
||||||
* @private
|
|
||||||
* @param {ChainEntry} entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.prototype.fromEntry = function fromEntry(entry) {
|
|
||||||
this.hash = entry.hash;
|
|
||||||
this.height = entry.height;
|
|
||||||
this.time = entry.time;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate block meta from json object.
|
|
||||||
* @private
|
|
||||||
* @param {Object} json
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.prototype.fromJSON = function fromJSON(json) {
|
|
||||||
this.hash = encoding.revHex(json.hash);
|
|
||||||
this.height = json.height;
|
|
||||||
this.time = json.time;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate block meta from serialized tip data.
|
|
||||||
* @private
|
|
||||||
* @param {Buffer} data
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.prototype.fromRaw = function fromRaw(data) {
|
|
||||||
const br = bio.read(data);
|
|
||||||
this.hash = br.readHash('hex');
|
|
||||||
this.height = br.readU32();
|
|
||||||
this.time = br.readU32();
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate block meta from chain entry.
|
|
||||||
* @param {ChainEntry} entry
|
|
||||||
* @returns {BlockMeta}
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.fromEntry = function fromEntry(entry) {
|
|
||||||
return new BlockMeta().fromEntry(entry);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate block meta from json object.
|
|
||||||
* @param {Object} json
|
|
||||||
* @returns {BlockMeta}
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.fromJSON = function fromJSON(json) {
|
|
||||||
return new BlockMeta().fromJSON(json);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate block meta from serialized data.
|
|
||||||
* @param {Hash} hash
|
|
||||||
* @param {Buffer} data
|
|
||||||
* @returns {BlockMeta}
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.fromRaw = function fromRaw(data) {
|
|
||||||
return new BlockMeta().fromRaw(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize the block meta.
|
|
||||||
* @returns {Buffer}
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.prototype.toRaw = function toRaw() {
|
|
||||||
const bw = bio.write(42);
|
|
||||||
bw.writeHash(this.hash);
|
|
||||||
bw.writeU32(this.height);
|
|
||||||
bw.writeU32(this.time);
|
|
||||||
return bw.render();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the block meta to a more json-friendly object.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockMeta.prototype.toJSON = function toJSON() {
|
|
||||||
return {
|
|
||||||
hash: encoding.revHex(this.hash),
|
|
||||||
height: this.height,
|
|
||||||
time: this.time
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TXRecord
|
|
||||||
* @constructor
|
|
||||||
* @param {TX} tx
|
|
||||||
* @param {BlockMeta?} block
|
|
||||||
*/
|
|
||||||
|
|
||||||
function TXRecord(tx, block) {
|
|
||||||
if (!(this instanceof TXRecord))
|
|
||||||
return new TXRecord(tx, block);
|
|
||||||
|
|
||||||
this.tx = null;
|
|
||||||
this.hash = null;
|
|
||||||
this.mtime = util.now();
|
|
||||||
this.height = -1;
|
|
||||||
this.block = null;
|
|
||||||
this.index = -1;
|
|
||||||
this.time = 0;
|
|
||||||
|
|
||||||
if (tx)
|
|
||||||
this.fromTX(tx, block);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inject properties from tx and block.
|
|
||||||
* @private
|
|
||||||
* @param {TX} tx
|
|
||||||
* @param {Block?} block
|
|
||||||
* @returns {TXRecord}
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXRecord.prototype.fromTX = function fromTX(tx, block) {
|
|
||||||
this.tx = tx;
|
|
||||||
this.hash = tx.hash('hex');
|
|
||||||
|
|
||||||
if (block)
|
|
||||||
this.setBlock(block);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate tx record from tx and block.
|
|
||||||
* @param {TX} tx
|
|
||||||
* @param {Block?} block
|
|
||||||
* @returns {TXRecord}
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXRecord.fromTX = function fromTX(tx, block) {
|
|
||||||
return new TXRecord().fromTX(tx, block);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set block data (confirm).
|
|
||||||
* @param {BlockMeta} block
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXRecord.prototype.setBlock = function setBlock(block) {
|
|
||||||
this.height = block.height;
|
|
||||||
this.block = block.hash;
|
|
||||||
this.time = block.time;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unset block (unconfirm).
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXRecord.prototype.unsetBlock = function unsetBlock() {
|
|
||||||
this.height = -1;
|
|
||||||
this.block = null;
|
|
||||||
this.time = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert tx record to a block meta.
|
|
||||||
* @returns {BlockMeta}
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXRecord.prototype.getBlock = function getBlock() {
|
|
||||||
if (this.height === -1)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return new BlockMeta(this.block, this.height, this.time);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate current number of transaction confirmations.
|
|
||||||
* @param {Number} height - Current chain height.
|
|
||||||
* @returns {Number} confirmations
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXRecord.prototype.getDepth = function getDepth(height) {
|
|
||||||
assert(typeof height === 'number', 'Must pass in height.');
|
|
||||||
|
|
||||||
if (this.height === -1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (height < this.height)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return height - this.height + 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get serialization size.
|
|
||||||
* @returns {Number}
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXRecord.prototype.getSize = function getSize() {
|
|
||||||
let size = 0;
|
|
||||||
|
|
||||||
size += this.tx.getSize();
|
|
||||||
size += 4;
|
|
||||||
|
|
||||||
if (this.block) {
|
|
||||||
size += 1;
|
|
||||||
size += 32;
|
|
||||||
size += 4 * 3;
|
|
||||||
} else {
|
|
||||||
size += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
/**
|
||||||
};
|
* Clone the block.
|
||||||
|
* @returns {BlockMeta}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
clone() {
|
||||||
* Serialize a transaction to "extended format".
|
return new this.constructor(this.hash, this.height, this.time);
|
||||||
* @returns {Buffer}
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXRecord.prototype.toRaw = function toRaw() {
|
|
||||||
const size = this.getSize();
|
|
||||||
const bw = bio.write(size);
|
|
||||||
|
|
||||||
let index = this.index;
|
|
||||||
|
|
||||||
this.tx.toWriter(bw);
|
|
||||||
|
|
||||||
bw.writeU32(this.mtime);
|
|
||||||
|
|
||||||
if (this.block) {
|
|
||||||
if (index === -1)
|
|
||||||
index = 0x7fffffff;
|
|
||||||
|
|
||||||
bw.writeU8(1);
|
|
||||||
bw.writeHash(this.block);
|
|
||||||
bw.writeU32(this.height);
|
|
||||||
bw.writeU32(this.time);
|
|
||||||
bw.writeU32(index);
|
|
||||||
} else {
|
|
||||||
bw.writeU8(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bw.render();
|
/**
|
||||||
};
|
* Get block meta hash as a buffer.
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
toHash() {
|
||||||
* Inject properties from "extended" format.
|
return Buffer.from(this.hash, 'hex');
|
||||||
* @private
|
}
|
||||||
* @param {Buffer} data
|
|
||||||
*/
|
|
||||||
|
|
||||||
TXRecord.prototype.fromRaw = function fromRaw(data) {
|
/**
|
||||||
const br = bio.read(data);
|
* Instantiate block meta from chain entry.
|
||||||
|
* @private
|
||||||
|
* @param {ChainEntry} entry
|
||||||
|
*/
|
||||||
|
|
||||||
this.tx = new TX();
|
fromEntry(entry) {
|
||||||
this.tx.fromReader(br);
|
this.hash = entry.hash;
|
||||||
|
this.height = entry.height;
|
||||||
|
this.time = entry.time;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
this.hash = this.tx.hash('hex');
|
/**
|
||||||
this.mtime = br.readU32();
|
* Instantiate block meta from json object.
|
||||||
|
* @private
|
||||||
|
* @param {Object} json
|
||||||
|
*/
|
||||||
|
|
||||||
if (br.readU8() === 1) {
|
fromJSON(json) {
|
||||||
this.block = br.readHash('hex');
|
this.hash = encoding.revHex(json.hash);
|
||||||
|
this.height = json.height;
|
||||||
|
this.time = json.time;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate block meta from serialized tip data.
|
||||||
|
* @private
|
||||||
|
* @param {Buffer} data
|
||||||
|
*/
|
||||||
|
|
||||||
|
fromRaw(data) {
|
||||||
|
const br = bio.read(data);
|
||||||
|
this.hash = br.readHash('hex');
|
||||||
this.height = br.readU32();
|
this.height = br.readU32();
|
||||||
this.time = br.readU32();
|
this.time = br.readU32();
|
||||||
this.index = br.readU32();
|
return this;
|
||||||
if (this.index === 0x7fffffff)
|
|
||||||
this.index = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
/**
|
||||||
};
|
* Instantiate block meta from chain entry.
|
||||||
|
* @param {ChainEntry} entry
|
||||||
|
* @returns {BlockMeta}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fromEntry(entry) {
|
||||||
|
return new this().fromEntry(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate block meta from json object.
|
||||||
|
* @param {Object} json
|
||||||
|
* @returns {BlockMeta}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fromJSON(json) {
|
||||||
|
return new this().fromJSON(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate block meta from serialized data.
|
||||||
|
* @param {Hash} hash
|
||||||
|
* @param {Buffer} data
|
||||||
|
* @returns {BlockMeta}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fromRaw(data) {
|
||||||
|
return new this().fromRaw(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the block meta.
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
|
toRaw() {
|
||||||
|
const bw = bio.write(42);
|
||||||
|
bw.writeHash(this.hash);
|
||||||
|
bw.writeU32(this.height);
|
||||||
|
bw.writeU32(this.time);
|
||||||
|
return bw.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the block meta to a more json-friendly object.
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
hash: encoding.revHex(this.hash),
|
||||||
|
height: this.height,
|
||||||
|
time: this.time
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate a transaction from a buffer
|
* TX Record
|
||||||
* in "extended" serialization format.
|
|
||||||
* @param {Buffer} data
|
|
||||||
* @returns {TX}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TXRecord.fromRaw = function fromRaw(data) {
|
class TXRecord {
|
||||||
return new TXRecord().fromRaw(data);
|
/**
|
||||||
};
|
* Create tx record.
|
||||||
|
* @constructor
|
||||||
|
* @param {TX} tx
|
||||||
|
* @param {BlockMeta?} block
|
||||||
|
*/
|
||||||
|
|
||||||
|
constructor(tx, block) {
|
||||||
|
this.tx = null;
|
||||||
|
this.hash = null;
|
||||||
|
this.mtime = util.now();
|
||||||
|
this.height = -1;
|
||||||
|
this.block = null;
|
||||||
|
this.index = -1;
|
||||||
|
this.time = 0;
|
||||||
|
|
||||||
|
if (tx)
|
||||||
|
this.fromTX(tx, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject properties from tx and block.
|
||||||
|
* @private
|
||||||
|
* @param {TX} tx
|
||||||
|
* @param {Block?} block
|
||||||
|
* @returns {TXRecord}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fromTX(tx, block) {
|
||||||
|
this.tx = tx;
|
||||||
|
this.hash = tx.hash('hex');
|
||||||
|
|
||||||
|
if (block)
|
||||||
|
this.setBlock(block);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate tx record from tx and block.
|
||||||
|
* @param {TX} tx
|
||||||
|
* @param {Block?} block
|
||||||
|
* @returns {TXRecord}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fromTX(tx, block) {
|
||||||
|
return new this().fromTX(tx, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set block data (confirm).
|
||||||
|
* @param {BlockMeta} block
|
||||||
|
*/
|
||||||
|
|
||||||
|
setBlock(block) {
|
||||||
|
this.height = block.height;
|
||||||
|
this.block = block.hash;
|
||||||
|
this.time = block.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unset block (unconfirm).
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsetBlock() {
|
||||||
|
this.height = -1;
|
||||||
|
this.block = null;
|
||||||
|
this.time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert tx record to a block meta.
|
||||||
|
* @returns {BlockMeta}
|
||||||
|
*/
|
||||||
|
|
||||||
|
getBlock() {
|
||||||
|
if (this.height === -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new BlockMeta(this.block, this.height, this.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate current number of transaction confirmations.
|
||||||
|
* @param {Number} height - Current chain height.
|
||||||
|
* @returns {Number} confirmations
|
||||||
|
*/
|
||||||
|
|
||||||
|
getDepth(height) {
|
||||||
|
assert(typeof height === 'number', 'Must pass in height.');
|
||||||
|
|
||||||
|
if (this.height === -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (height < this.height)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return height - this.height + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get serialization size.
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
|
||||||
|
getSize() {
|
||||||
|
let size = 0;
|
||||||
|
|
||||||
|
size += this.tx.getSize();
|
||||||
|
size += 4;
|
||||||
|
|
||||||
|
if (this.block) {
|
||||||
|
size += 1;
|
||||||
|
size += 32;
|
||||||
|
size += 4 * 3;
|
||||||
|
} else {
|
||||||
|
size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a transaction to "extended format".
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
|
|
||||||
|
toRaw() {
|
||||||
|
const size = this.getSize();
|
||||||
|
const bw = bio.write(size);
|
||||||
|
|
||||||
|
let index = this.index;
|
||||||
|
|
||||||
|
this.tx.toWriter(bw);
|
||||||
|
|
||||||
|
bw.writeU32(this.mtime);
|
||||||
|
|
||||||
|
if (this.block) {
|
||||||
|
if (index === -1)
|
||||||
|
index = 0x7fffffff;
|
||||||
|
|
||||||
|
bw.writeU8(1);
|
||||||
|
bw.writeHash(this.block);
|
||||||
|
bw.writeU32(this.height);
|
||||||
|
bw.writeU32(this.time);
|
||||||
|
bw.writeU32(index);
|
||||||
|
} else {
|
||||||
|
bw.writeU8(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bw.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject properties from "extended" format.
|
||||||
|
* @private
|
||||||
|
* @param {Buffer} data
|
||||||
|
*/
|
||||||
|
|
||||||
|
fromRaw(data) {
|
||||||
|
const br = bio.read(data);
|
||||||
|
|
||||||
|
this.tx = new TX();
|
||||||
|
this.tx.fromReader(br);
|
||||||
|
|
||||||
|
this.hash = this.tx.hash('hex');
|
||||||
|
this.mtime = br.readU32();
|
||||||
|
|
||||||
|
if (br.readU8() === 1) {
|
||||||
|
this.block = br.readHash('hex');
|
||||||
|
this.height = br.readU32();
|
||||||
|
this.time = br.readU32();
|
||||||
|
this.index = br.readU32();
|
||||||
|
if (this.index === 0x7fffffff)
|
||||||
|
this.index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a transaction from a buffer
|
||||||
|
* in "extended" serialization format.
|
||||||
|
* @param {Buffer} data
|
||||||
|
* @returns {TX}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fromRaw(data) {
|
||||||
|
return new this().fromRaw(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map Record
|
* Map Record
|
||||||
* @constructor
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function MapRecord() {
|
class MapRecord {
|
||||||
this.wids = new Set();
|
/**
|
||||||
|
* Create map record.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.wids = new Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
add(wid) {
|
||||||
|
if (this.wids.has(wid))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this.wids.add(wid);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(wid) {
|
||||||
|
return this.wids.delete(wid);
|
||||||
|
}
|
||||||
|
|
||||||
|
toWriter(bw) {
|
||||||
|
bw.writeU32(this.wids.size);
|
||||||
|
|
||||||
|
for (const wid of this.wids)
|
||||||
|
bw.writeU32(wid);
|
||||||
|
|
||||||
|
return bw;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSize() {
|
||||||
|
return 4 + this.wids.size * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
toRaw() {
|
||||||
|
const size = this.getSize();
|
||||||
|
return this.toWriter(bio.write(size)).render();
|
||||||
|
}
|
||||||
|
|
||||||
|
fromReader(br) {
|
||||||
|
const count = br.readU32();
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++)
|
||||||
|
this.wids.add(br.readU32());
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
fromRaw(data) {
|
||||||
|
return this.fromReader(bio.read(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromReader(br) {
|
||||||
|
return new this().fromReader(br);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromRaw(data) {
|
||||||
|
return new this().fromRaw(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MapRecord.prototype.add = function add(wid) {
|
|
||||||
if (this.wids.has(wid))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
this.wids.add(wid);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
MapRecord.prototype.remove = function remove(wid) {
|
|
||||||
return this.wids.delete(wid);
|
|
||||||
};
|
|
||||||
|
|
||||||
MapRecord.prototype.toWriter = function toWriter(bw) {
|
|
||||||
bw.writeU32(this.wids.size);
|
|
||||||
|
|
||||||
for (const wid of this.wids)
|
|
||||||
bw.writeU32(wid);
|
|
||||||
|
|
||||||
return bw;
|
|
||||||
};
|
|
||||||
|
|
||||||
MapRecord.prototype.getSize = function getSize() {
|
|
||||||
return 4 + this.wids.size * 4;
|
|
||||||
};
|
|
||||||
|
|
||||||
MapRecord.prototype.toRaw = function toRaw() {
|
|
||||||
const size = this.getSize();
|
|
||||||
return this.toWriter(bio.write(size)).render();
|
|
||||||
};
|
|
||||||
|
|
||||||
MapRecord.prototype.fromReader = function fromReader(br) {
|
|
||||||
const count = br.readU32();
|
|
||||||
|
|
||||||
for (let i = 0; i < count; i++)
|
|
||||||
this.wids.add(br.readU32());
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
MapRecord.prototype.fromRaw = function fromRaw(data) {
|
|
||||||
return this.fromReader(bio.read(data));
|
|
||||||
};
|
|
||||||
|
|
||||||
MapRecord.fromReader = function fromReader(br) {
|
|
||||||
return new MapRecord().fromReader(br);
|
|
||||||
};
|
|
||||||
|
|
||||||
MapRecord.fromRaw = function fromRaw(data) {
|
|
||||||
return new MapRecord().fromRaw(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -16,121 +16,123 @@ const RPC = require('./rpc');
|
|||||||
/**
|
/**
|
||||||
* Wallet Node
|
* Wallet Node
|
||||||
* @extends Node
|
* @extends Node
|
||||||
* @constructor
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function WalletNode(options) {
|
class WalletNode extends Node {
|
||||||
if (!(this instanceof WalletNode))
|
/**
|
||||||
return new WalletNode(options);
|
* Create a wallet node.
|
||||||
|
* @constructor
|
||||||
|
* @param {Object?} options
|
||||||
|
*/
|
||||||
|
|
||||||
Node.call(this, 'bcoin', 'wallet.conf', 'wallet.log', options);
|
constructor(options) {
|
||||||
|
super('bcoin', 'wallet.conf', 'wallet.log', options);
|
||||||
|
|
||||||
this.opened = false;
|
this.opened = false;
|
||||||
|
|
||||||
this.client = new Client({
|
this.client = new Client({
|
||||||
network: this.network,
|
network: this.network,
|
||||||
url: this.config.str('node-url'),
|
url: this.config.str('node-url'),
|
||||||
host: this.config.str('node-host'),
|
host: this.config.str('node-host'),
|
||||||
port: this.config.str('node-port', this.network.rpcPort),
|
port: this.config.str('node-port', this.network.rpcPort),
|
||||||
ssl: this.config.str('node-ssl'),
|
ssl: this.config.str('node-ssl'),
|
||||||
apiKey: this.config.str('node-api-key')
|
apiKey: this.config.str('node-api-key')
|
||||||
});
|
});
|
||||||
|
|
||||||
this.wdb = new WalletDB({
|
this.wdb = new WalletDB({
|
||||||
network: this.network,
|
network: this.network,
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
workers: this.workers,
|
workers: this.workers,
|
||||||
client: this.client,
|
client: this.client,
|
||||||
prefix: this.config.prefix,
|
prefix: this.config.prefix,
|
||||||
db: this.config.str('db'),
|
db: this.config.str('db'),
|
||||||
maxFiles: this.config.uint('max-files'),
|
maxFiles: this.config.uint('max-files'),
|
||||||
cacheSize: this.config.mb('cache-size'),
|
cacheSize: this.config.mb('cache-size'),
|
||||||
witness: this.config.bool('witness'),
|
witness: this.config.bool('witness'),
|
||||||
checkpoints: this.config.bool('checkpoints'),
|
checkpoints: this.config.bool('checkpoints'),
|
||||||
startHeight: this.config.uint('start-height'),
|
startHeight: this.config.uint('start-height'),
|
||||||
wipeNoReally: this.config.bool('wipe-no-really'),
|
wipeNoReally: this.config.bool('wipe-no-really'),
|
||||||
spv: this.config.bool('spv')
|
spv: this.config.bool('spv')
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rpc = new RPC(this);
|
this.rpc = new RPC(this);
|
||||||
|
|
||||||
this.http = new HTTP({
|
this.http = new HTTP({
|
||||||
network: this.network,
|
network: this.network,
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
node: this,
|
node: this,
|
||||||
prefix: this.config.prefix,
|
prefix: this.config.prefix,
|
||||||
ssl: this.config.bool('ssl'),
|
ssl: this.config.bool('ssl'),
|
||||||
keyFile: this.config.path('ssl-key'),
|
keyFile: this.config.path('ssl-key'),
|
||||||
certFile: this.config.path('ssl-cert'),
|
certFile: this.config.path('ssl-cert'),
|
||||||
host: this.config.str('http-host'),
|
host: this.config.str('http-host'),
|
||||||
port: this.config.uint('http-port'),
|
port: this.config.uint('http-port'),
|
||||||
apiKey: this.config.str('api-key'),
|
apiKey: this.config.str('api-key'),
|
||||||
noAuth: this.config.bool('no-auth'),
|
noAuth: this.config.bool('no-auth'),
|
||||||
walletAuth: this.config.bool('wallet-auth')
|
walletAuth: this.config.bool('wallet-auth')
|
||||||
});
|
});
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the node.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.wdb.on('error', err => this.error(err));
|
||||||
|
this.http.on('error', err => this.error(err));
|
||||||
|
|
||||||
|
this.loadPlugins();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the node and all its child objects,
|
||||||
|
* wait for the database to load.
|
||||||
|
* @alias WalletNode#open
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
assert(!this.opened, 'WalletNode is already open.');
|
||||||
|
this.opened = true;
|
||||||
|
|
||||||
|
await this.handlePreopen();
|
||||||
|
await this.wdb.open();
|
||||||
|
|
||||||
|
this.rpc.wallet = this.wdb.primary;
|
||||||
|
|
||||||
|
await this.openPlugins();
|
||||||
|
|
||||||
|
await this.http.open();
|
||||||
|
await this.handleOpen();
|
||||||
|
|
||||||
|
this.logger.info('Wallet node is loaded.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the node, wait for the database to close.
|
||||||
|
* @alias WalletNode#close
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
assert(this.opened, 'WalletNode is not open.');
|
||||||
|
this.opened = false;
|
||||||
|
|
||||||
|
await this.handlePreclose();
|
||||||
|
await this.http.close();
|
||||||
|
|
||||||
|
await this.closePlugins();
|
||||||
|
|
||||||
|
this.rpc.wallet = null;
|
||||||
|
|
||||||
|
await this.wdb.close();
|
||||||
|
await this.handleClose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(WalletNode.prototype, Node.prototype);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the node.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletNode.prototype.init = function init() {
|
|
||||||
this.wdb.on('error', err => this.error(err));
|
|
||||||
this.http.on('error', err => this.error(err));
|
|
||||||
|
|
||||||
this.loadPlugins();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open the node and all its child objects,
|
|
||||||
* wait for the database to load.
|
|
||||||
* @alias WalletNode#open
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletNode.prototype.open = async function open() {
|
|
||||||
assert(!this.opened, 'WalletNode is already open.');
|
|
||||||
this.opened = true;
|
|
||||||
|
|
||||||
await this.handlePreopen();
|
|
||||||
await this.wdb.open();
|
|
||||||
|
|
||||||
this.rpc.wallet = this.wdb.primary;
|
|
||||||
|
|
||||||
await this.openPlugins();
|
|
||||||
|
|
||||||
await this.http.open();
|
|
||||||
await this.handleOpen();
|
|
||||||
|
|
||||||
this.logger.info('Wallet node is loaded.');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the node, wait for the database to close.
|
|
||||||
* @alias WalletNode#close
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletNode.prototype.close = async function close() {
|
|
||||||
assert(this.opened, 'WalletNode is not open.');
|
|
||||||
this.opened = false;
|
|
||||||
|
|
||||||
await this.handlePreclose();
|
|
||||||
await this.http.close();
|
|
||||||
|
|
||||||
await this.closePlugins();
|
|
||||||
|
|
||||||
this.rpc.wallet = null;
|
|
||||||
|
|
||||||
await this.wdb.close();
|
|
||||||
await this.handleClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
5261
lib/wallet/txdb.js
5261
lib/wallet/txdb.js
File diff suppressed because it is too large
Load Diff
4129
lib/wallet/wallet.js
4129
lib/wallet/wallet.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -36,79 +36,6 @@ class WalletKey extends KeyRing {
|
|||||||
this.index = -1;
|
this.index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate key ring from options.
|
|
||||||
* @param {Object} options
|
|
||||||
* @returns {WalletKey}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static fromOptions(options) {
|
|
||||||
return new this().fromOptions(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate wallet key from a private key.
|
|
||||||
* @param {Buffer} key
|
|
||||||
* @param {Boolean?} compressed
|
|
||||||
* @returns {WalletKey}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static fromPrivate(key, compressed) {
|
|
||||||
return new this().fromPrivate(key, compressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a wallet key.
|
|
||||||
* @param {Boolean?} compressed
|
|
||||||
* @returns {WalletKey}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static generate(compressed) {
|
|
||||||
return new this().generate(compressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate wallet key from a public key.
|
|
||||||
* @param {Buffer} publicKey
|
|
||||||
* @returns {WalletKey}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static fromPublic(key) {
|
|
||||||
return new this().fromPublic(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate wallet key from a public key.
|
|
||||||
* @param {Buffer} publicKey
|
|
||||||
* @returns {WalletKey}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static fromKey(key, compressed) {
|
|
||||||
return new this().fromKey(key, compressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate wallet key from script.
|
|
||||||
* @param {Buffer} key
|
|
||||||
* @param {Script} script
|
|
||||||
* @returns {WalletKey}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static fromScript(key, script, compressed) {
|
|
||||||
return new this().fromScript(key, script, compressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate a wallet key from a serialized CBitcoinSecret.
|
|
||||||
* @param {Base58String} secret
|
|
||||||
* @param {Network?} network
|
|
||||||
* @returns {WalletKey}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static fromSecret(data, network) {
|
|
||||||
return new this().fromSecret(data, network);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an WalletKey to a more json-friendly object.
|
* Convert an WalletKey to a more json-friendly object.
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
@ -130,26 +57,6 @@ class WalletKey extends KeyRing {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate an WalletKey from a jsonified transaction object.
|
|
||||||
* @param {Object} json - The jsonified transaction object.
|
|
||||||
* @returns {WalletKey}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static fromJSON(json) {
|
|
||||||
return new this().fromJSON(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate a wallet key from serialized data.
|
|
||||||
* @param {Buffer} data
|
|
||||||
* @returns {WalletKey}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static fromRaw(data) {
|
|
||||||
return new this().fromRaw(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject properties from hd key.
|
* Inject properties from hd key.
|
||||||
* @private
|
* @private
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user