wallet refactor.
This commit is contained in:
parent
2a18a76973
commit
f1376e5a99
@ -2809,25 +2809,14 @@ Script.prototype.isNulldata = function isNulldata(sloppy) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.raw.length === 2) {
|
if (this.raw.length === 2)
|
||||||
if (this.raw[1] === opcodes.OP_0)
|
return Script.getSmall(this.raw[1]) !== -1;
|
||||||
return true;
|
|
||||||
if (this.raw[1] >= opcodes.OP_1 && this.raw[1] <= opcodes.OP_16)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.raw[1] >= 0x01 && this.raw[1] <= 0x4b) {
|
if (this.raw[1] >= 0x01 && this.raw[1] <= 0x4b)
|
||||||
if (this.raw[1] + 2 !== this.raw.length)
|
return this.raw[1] + 2 === this.raw.length;
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.raw[1] === opcodes.OP_PUSHDATA1) {
|
if (this.raw[1] === opcodes.OP_PUSHDATA1)
|
||||||
if (this.raw[2] + 3 !== this.raw.length)
|
return this.raw[2] > 75 && this.raw[2] + 3 === this.raw.length;
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -39,23 +39,37 @@ var BufferWriter = require('./writer');
|
|||||||
* (default=account key "address").
|
* (default=account key "address").
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Wallet(options) {
|
function Wallet(db, options) {
|
||||||
var master;
|
|
||||||
|
|
||||||
if (!(this instanceof Wallet))
|
if (!(this instanceof Wallet))
|
||||||
return new Wallet(options);
|
return new Wallet(db, options);
|
||||||
|
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
assert(options, 'Options required.');
|
assert(db, 'DB required.');
|
||||||
assert(options.db, 'DB required.');
|
|
||||||
|
|
||||||
this.options = options;
|
this.db = db;
|
||||||
this.network = bcoin.network.get(options.network);
|
this.network = db.network;
|
||||||
this.db = options.db;
|
|
||||||
this.locker = new bcoin.locker(this);
|
this.locker = new bcoin.locker(this);
|
||||||
|
|
||||||
master = options.master;
|
this.id = null;
|
||||||
|
this.master = null;
|
||||||
|
this.initialized = false;
|
||||||
|
this.accountDepth = 0;
|
||||||
|
|
||||||
|
this.account = null;
|
||||||
|
|
||||||
|
if (options)
|
||||||
|
this.fromOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.inherits(Wallet, EventEmitter);
|
||||||
|
|
||||||
|
Wallet.fromOptions = function fromOptions(db, options) {
|
||||||
|
return new Wallet(db).fromOptions(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
Wallet.prototype.fromOptions = function fromOptions(options) {
|
||||||
|
var master = options.master;
|
||||||
|
|
||||||
if (!master)
|
if (!master)
|
||||||
master = bcoin.hd.fromMnemonic(null, this.network);
|
master = bcoin.hd.fromMnemonic(null, this.network);
|
||||||
@ -66,58 +80,47 @@ function Wallet(options) {
|
|||||||
if (!MasterKey.isMasterKey(master))
|
if (!MasterKey.isMasterKey(master))
|
||||||
master = MasterKey.fromKey(master);
|
master = MasterKey.fromKey(master);
|
||||||
|
|
||||||
this.id = options.id || null;
|
|
||||||
this.master = master;
|
this.master = master;
|
||||||
this.initialized = options.initialized || false;
|
this.initialized = options.initialized || false;
|
||||||
this.accountDepth = options.accountDepth || 0;
|
this.accountDepth = options.accountDepth || 0;
|
||||||
|
this.id = options.id || this.getID();
|
||||||
|
|
||||||
this.loaded = false;
|
return this;
|
||||||
this.loading = false;
|
};
|
||||||
this.account = null;
|
|
||||||
|
|
||||||
if (!this.id)
|
Wallet.prototype.init = function init(options, callback) {
|
||||||
this.id = this.getID();
|
var self = this;
|
||||||
|
|
||||||
if (this.options.passphrase)
|
assert(!this.initialized);
|
||||||
this.master.encrypt(this.options.passphrase);
|
this.initialized = true;
|
||||||
}
|
|
||||||
|
|
||||||
utils.inherits(Wallet, EventEmitter);
|
if (options.passphrase)
|
||||||
|
this.master.encrypt(options.passphrase);
|
||||||
|
|
||||||
/**
|
this.createAccount(options, function(err, account) {
|
||||||
* Open the wallet, register with the database.
|
if (err)
|
||||||
* @param {Function} callback
|
return callback(err);
|
||||||
*/
|
|
||||||
|
assert(account);
|
||||||
|
|
||||||
|
self.account = account;
|
||||||
|
|
||||||
|
return callback();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Wallet.prototype.open = function open(callback) {
|
Wallet.prototype.open = function open(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
assert(this.initialized);
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
this.getAccount(0, function(err, account) {
|
||||||
|
if (err)
|
||||||
if (this.loaded)
|
|
||||||
return utils.nextTick(callback);
|
|
||||||
|
|
||||||
if (this.loading)
|
|
||||||
return this.once('open', callback);
|
|
||||||
|
|
||||||
this.loading = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.db.register(this);
|
|
||||||
} catch (e) {
|
|
||||||
this.emit('error', e);
|
|
||||||
return callback(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.init(function(err) {
|
|
||||||
if (err) {
|
|
||||||
self.emit('error', err);
|
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
|
||||||
|
|
||||||
self.loading = false;
|
if (!account)
|
||||||
self.loaded = true;
|
return callback(new Error('Default account not found.'));
|
||||||
self.emit('open');
|
|
||||||
|
self.account = account;
|
||||||
|
|
||||||
return callback();
|
return callback();
|
||||||
});
|
});
|
||||||
@ -129,15 +132,9 @@ Wallet.prototype.open = function open(callback) {
|
|||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.close =
|
|
||||||
Wallet.prototype.destroy = function destroy(callback) {
|
Wallet.prototype.destroy = function destroy(callback) {
|
||||||
callback = utils.ensure(callback);
|
callback = utils.ensure(callback);
|
||||||
|
|
||||||
if (!this.loaded)
|
|
||||||
return utils.nextTick(callback);
|
|
||||||
|
|
||||||
assert(!this.loading);
|
|
||||||
|
|
||||||
this.master.destroy();
|
this.master.destroy();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -147,8 +144,6 @@ Wallet.prototype.destroy = function destroy(callback) {
|
|||||||
return callback(e);
|
return callback(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loaded = false;
|
|
||||||
|
|
||||||
return utils.nextTick(callback);
|
return utils.nextTick(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -160,33 +155,6 @@ Wallet.prototype.destroy = function destroy(callback) {
|
|||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.init = function init(callback) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
function done(err, account) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
if (!account)
|
|
||||||
return callback(new Error('Account not found.'));
|
|
||||||
|
|
||||||
self.account = account;
|
|
||||||
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.db.open(function(err) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
if (self.initialized)
|
|
||||||
return self.getAccount(0, done);
|
|
||||||
|
|
||||||
self.initialized = true;
|
|
||||||
self.createAccount(self.options, done);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a public account key to the wallet (multisig).
|
* Add a public account key to the wallet (multisig).
|
||||||
* Saves the key in the wallet database.
|
* Saves the key in the wallet database.
|
||||||
@ -686,6 +654,34 @@ Wallet.prototype.deriveInputs = function deriveInputs(tx, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Wallet.prototype.getKeyring = function getKeyring(hash, callback) {
|
||||||
|
var self = this;
|
||||||
|
var address;
|
||||||
|
|
||||||
|
if (!hash)
|
||||||
|
return callback();
|
||||||
|
|
||||||
|
this.getPath(hash, function(err, path) {
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
return callback();
|
||||||
|
|
||||||
|
self.getAccount(path.account, function(err, account) {
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
if (!account)
|
||||||
|
return callback();
|
||||||
|
|
||||||
|
address = account.deriveAddress(path.change, path.index);
|
||||||
|
|
||||||
|
return callback(null, address);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map input addresses to paths.
|
* Map input addresses to paths.
|
||||||
* @param {TX|Input} tx
|
* @param {TX|Input} tx
|
||||||
@ -1419,14 +1415,13 @@ Wallet.prototype.toJSON = function toJSON() {
|
|||||||
* @throws Error on bad decrypt
|
* @throws Error on bad decrypt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.parseJSON = function parseJSON(json) {
|
Wallet.prototype.fromJSON = function fromJSON(json) {
|
||||||
return {
|
this.network = bcoin.network.get(json.network);
|
||||||
network: json.network,
|
this.id = json.id;
|
||||||
id: json.id,
|
this.initialized = json.initialized;
|
||||||
initialized: json.initialized,
|
this.accountDepth = json.accountDepth;
|
||||||
accountDepth: json.accountDepth,
|
this.master = MasterKey.fromJSON(json.master);
|
||||||
master: MasterKey.fromJSON(json.master)
|
return this;
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1457,21 +1452,14 @@ Wallet.prototype.toRaw = function toRaw(writer) {
|
|||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.parseRaw = function parseRaw(data) {
|
Wallet.prototype.fromRaw = function fromRaw(data) {
|
||||||
var p = new BufferReader(data);
|
var p = new BufferReader(data);
|
||||||
var network = bcoin.network.fromMagic(p.readU32());
|
this.network = bcoin.network.fromMagic(p.readU32());
|
||||||
var id = p.readVarString('utf8');
|
this.id = p.readVarString('utf8');
|
||||||
var initialized = p.readU8() === 1;
|
this.initialized = p.readU8() === 1;
|
||||||
var accountDepth = p.readU32();
|
this.accountDepth = p.readU32();
|
||||||
var master = MasterKey.fromRaw(p.readVarBytes());
|
this.master = MasterKey.fromRaw(p.readVarBytes());
|
||||||
|
return this;
|
||||||
return {
|
|
||||||
network: network.type,
|
|
||||||
id: id,
|
|
||||||
initialized: initialized,
|
|
||||||
accountDepth: accountDepth,
|
|
||||||
master: master
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1480,8 +1468,8 @@ Wallet.parseRaw = function parseRaw(data) {
|
|||||||
* @returns {Wallet}
|
* @returns {Wallet}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.fromRaw = function fromRaw(data) {
|
Wallet.fromRaw = function fromRaw(db, data) {
|
||||||
return new Wallet(Wallet.parseRaw(data));
|
return new Wallet(db).fromRaw(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1491,8 +1479,8 @@ Wallet.fromRaw = function fromRaw(data) {
|
|||||||
* @returns {Wallet}
|
* @returns {Wallet}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.fromJSON = function fromJSON(json) {
|
Wallet.fromJSON = function fromJSON(db, json) {
|
||||||
return new Wallet(Wallet.parseJSON(json));
|
return new Wallet(db).fromJSON(json);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1531,28 +1519,60 @@ Wallet.isWallet = function isWallet(obj) {
|
|||||||
* @param {String?} options.name - Account name
|
* @param {String?} options.name - Account name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Account(options) {
|
function Account(db, options) {
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
if (!(this instanceof Account))
|
if (!(this instanceof Account))
|
||||||
return new Account(options);
|
return new Account(db, options);
|
||||||
|
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
|
assert(db, 'Database is required.');
|
||||||
|
|
||||||
|
this.db = db;
|
||||||
|
this.network = db.network;
|
||||||
|
this.lookahead = Account.LOOKAHEAD;
|
||||||
|
this.cache = new bcoin.lru(20, 1);
|
||||||
|
|
||||||
|
this.loaded = false;
|
||||||
|
this.loading = false;
|
||||||
|
this.receiveAddress = null;
|
||||||
|
this.changeAddress = null;
|
||||||
|
|
||||||
|
this.id = null;
|
||||||
|
this.name = null;
|
||||||
|
this.witness = false;
|
||||||
|
this.accountKey = null;
|
||||||
|
this.accountIndex = 0;
|
||||||
|
this.receiveDepth = 0;
|
||||||
|
this.changeDepth = 0;
|
||||||
|
this.type = null;
|
||||||
|
this.keys = [];
|
||||||
|
this.m = 1;
|
||||||
|
this.n = 1;
|
||||||
|
this.initialized = false;
|
||||||
|
|
||||||
|
if (options)
|
||||||
|
this.fromOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.inherits(Account, EventEmitter);
|
||||||
|
|
||||||
|
Account.fromOptions = function fromOptions(db, options) {
|
||||||
|
return new Account(db).fromOptions(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
Account.prototype.fromOptions = function fromOptions(options) {
|
||||||
assert(options, 'Options are required.');
|
assert(options, 'Options are required.');
|
||||||
assert(options.db, 'Database is required.');
|
|
||||||
assert(options.id, 'Wallet ID is required.');
|
assert(options.id, 'Wallet ID is required.');
|
||||||
assert(options.accountKey, 'Account key is required.');
|
assert(options.accountKey, 'Account key is required.');
|
||||||
assert(utils.isNumber(options.accountIndex), 'Account index is required.');
|
assert(utils.isNumber(options.accountIndex), 'Account index is required.');
|
||||||
|
|
||||||
this.options = options;
|
|
||||||
this.network = bcoin.network.get(options.network);
|
|
||||||
this.db = options.db;
|
|
||||||
this.lookahead = Account.LOOKAHEAD;
|
|
||||||
|
|
||||||
this.id = options.id;
|
this.id = options.id;
|
||||||
this.name = options.name;
|
this.name = options.name;
|
||||||
this.witness = options.witness || false;
|
this.witness = options.witness != null
|
||||||
|
? options.witness
|
||||||
|
: this.network.witness;
|
||||||
this.accountKey = options.accountKey;
|
this.accountKey = options.accountKey;
|
||||||
this.accountIndex = options.accountIndex;
|
this.accountIndex = options.accountIndex;
|
||||||
this.receiveDepth = options.receiveDepth || 0;
|
this.receiveDepth = options.receiveDepth || 0;
|
||||||
@ -1563,13 +1583,6 @@ function Account(options) {
|
|||||||
this.n = options.n || 1;
|
this.n = options.n || 1;
|
||||||
this.initialized = options.initialized || false;
|
this.initialized = options.initialized || false;
|
||||||
|
|
||||||
this.loaded = false;
|
|
||||||
this.loading = false;
|
|
||||||
this.receiveAddress = null;
|
|
||||||
this.changeAddress = null;
|
|
||||||
|
|
||||||
this.cache = new bcoin.lru(20, 1);
|
|
||||||
|
|
||||||
if (this.n > 1)
|
if (this.n > 1)
|
||||||
this.type = 'multisig';
|
this.type = 'multisig';
|
||||||
|
|
||||||
@ -1588,9 +1601,9 @@ function Account(options) {
|
|||||||
for (i = 0; i < options.keys.length; i++)
|
for (i = 0; i < options.keys.length; i++)
|
||||||
this.pushKey(options.keys[i]);
|
this.pushKey(options.keys[i]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
utils.inherits(Account, EventEmitter);
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default address lookahead.
|
* Default address lookahead.
|
||||||
@ -1599,58 +1612,6 @@ utils.inherits(Account, EventEmitter);
|
|||||||
|
|
||||||
Account.LOOKAHEAD = 5;
|
Account.LOOKAHEAD = 5;
|
||||||
|
|
||||||
/**
|
|
||||||
* Open the account, register with the database.
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
Account.prototype.open = function open(callback) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
if (this.loaded)
|
|
||||||
return utils.nextTick(callback);
|
|
||||||
|
|
||||||
if (this.loading)
|
|
||||||
return this.once('open', callback);
|
|
||||||
|
|
||||||
this.loading = true;
|
|
||||||
|
|
||||||
this.init(function(err) {
|
|
||||||
if (err) {
|
|
||||||
self.emit('error', err);
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.loading = false;
|
|
||||||
self.loaded = true;
|
|
||||||
self.emit('open');
|
|
||||||
|
|
||||||
return callback();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the account, unregister with the database.
|
|
||||||
* @method
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
Account.prototype.close =
|
|
||||||
Account.prototype.destroy = function destroy(callback) {
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
if (!this.loaded)
|
|
||||||
return utils.nextTick(callback);
|
|
||||||
|
|
||||||
assert(!this.loading);
|
|
||||||
|
|
||||||
this.loaded = false;
|
|
||||||
|
|
||||||
return utils.nextTick(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to intialize the account (generating
|
* Attempt to intialize the account (generating
|
||||||
* the first addresses along with the lookahead
|
* the first addresses along with the lookahead
|
||||||
@ -1666,12 +1627,6 @@ Account.prototype.init = function init(callback) {
|
|||||||
return this.save(callback);
|
return this.save(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.initialized) {
|
|
||||||
this.receiveAddress = this.deriveReceive(this.receiveDepth - 1);
|
|
||||||
this.changeAddress = this.deriveChange(this.changeDepth - 1);
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
|
|
||||||
assert(this.receiveDepth === 0);
|
assert(this.receiveDepth === 0);
|
||||||
@ -1680,6 +1635,16 @@ Account.prototype.init = function init(callback) {
|
|||||||
this.setDepth(1, 1, callback);
|
this.setDepth(1, 1, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Account.prototype.open = function open(callback) {
|
||||||
|
if (!this.initialized)
|
||||||
|
return callback();
|
||||||
|
|
||||||
|
this.receiveAddress = this.deriveReceive(this.receiveDepth - 1);
|
||||||
|
this.changeAddress = this.deriveChange(this.changeDepth - 1);
|
||||||
|
|
||||||
|
return callback();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a public account key to the account (multisig).
|
* Add a public account key to the account (multisig).
|
||||||
* Does not update the database.
|
* Does not update the database.
|
||||||
@ -1809,6 +1774,7 @@ Account.prototype.addKey = function addKey(key, callback) {
|
|||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to initialize again.
|
||||||
this.init(function(err) {
|
this.init(function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
@ -2186,24 +2152,27 @@ Account.prototype.toJSON = function toJSON() {
|
|||||||
* @throws Error on bad decrypt
|
* @throws Error on bad decrypt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.parseJSON = function parseJSON(json) {
|
Account.prototype.fromJSON = function fromJSON(json) {
|
||||||
return {
|
var i;
|
||||||
network: json.network,
|
|
||||||
id: json.id,
|
this.network = bcoin.network.get(json.network);
|
||||||
name: json.name,
|
this.id = json.id;
|
||||||
initialized: json.initialized,
|
this.name = json.name;
|
||||||
type: json.type,
|
this.initialized = json.initialized;
|
||||||
m: json.m,
|
this.type = json.type;
|
||||||
n: json.n,
|
this.m = json.m;
|
||||||
witness: json.witness,
|
this.n = json.n;
|
||||||
accountIndex: json.accountIndex,
|
this.witness = json.witness;
|
||||||
receiveDepth: json.receiveDepth,
|
this.accountIndex = json.accountIndex;
|
||||||
changeDepth: json.changeDepth,
|
this.receiveDepth = json.receiveDepth;
|
||||||
accountKey: bcoin.hd.fromBase58(json.accountKey),
|
this.changeDepth = json.changeDepth;
|
||||||
keys: json.keys.map(function(key) {
|
this.accountKey = bcoin.hd.fromBase58(json.accountKey);
|
||||||
return bcoin.hd.fromBase58(key);
|
this.keys = [];
|
||||||
})
|
|
||||||
};
|
for (i = 0; i < json.keys.length; i++)
|
||||||
|
this.keys.push(bcoin.hd.fromBase58(key));
|
||||||
|
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2246,42 +2215,30 @@ Account.prototype.toRaw = function toRaw(writer) {
|
|||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.parseRaw = function parseRaw(data) {
|
Account.prototype.fromRaw = function fromRaw(data) {
|
||||||
var p = new BufferReader(data);
|
var p = new BufferReader(data);
|
||||||
var network = bcoin.network.fromMagic(p.readU32());
|
var i, count;
|
||||||
var id = p.readVarString('utf8');
|
|
||||||
var name = p.readVarString('utf8');
|
this.network = bcoin.network.fromMagic(p.readU32());
|
||||||
var initialized = p.readU8() === 1;
|
this.id = p.readVarString('utf8');
|
||||||
var type = p.readU8() === 0 ? 'pubkeyhash' : 'multisig';
|
this.name = p.readVarString('utf8');
|
||||||
var m = p.readU8();
|
this.initialized = p.readU8() === 1;
|
||||||
var n = p.readU8();
|
this.type = p.readU8() === 0 ? 'pubkeyhash' : 'multisig';
|
||||||
var witness = p.readU8() === 1;
|
this.m = p.readU8();
|
||||||
var accountIndex = p.readU32();
|
this.n = p.readU8();
|
||||||
var receiveDepth = p.readU32();
|
this.witness = p.readU8() === 1;
|
||||||
var changeDepth = p.readU32();
|
this.accountIndex = p.readU32();
|
||||||
var accountKey = bcoin.hd.fromRaw(p.readBytes(82));
|
this.receiveDepth = p.readU32();
|
||||||
var count = p.readU8();
|
this.changeDepth = p.readU32();
|
||||||
var keys = [];
|
this.accountKey = bcoin.hd.fromRaw(p.readBytes(82));
|
||||||
var i;
|
this.keys = [];
|
||||||
|
|
||||||
|
count = p.readU8();
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
keys.push(bcoin.hd.fromRaw(p.readBytes(82)));
|
this.keys.push(bcoin.hd.fromRaw(p.readBytes(82)));
|
||||||
|
|
||||||
return {
|
return this;
|
||||||
network: network.type,
|
|
||||||
id: id,
|
|
||||||
name: name,
|
|
||||||
initialized: initialized,
|
|
||||||
type: type,
|
|
||||||
m: m,
|
|
||||||
n: n,
|
|
||||||
witness: witness,
|
|
||||||
accountIndex: accountIndex,
|
|
||||||
receiveDepth: receiveDepth,
|
|
||||||
changeDepth: changeDepth,
|
|
||||||
accountKey: accountKey,
|
|
||||||
keys: keys
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2290,8 +2247,8 @@ Account.parseRaw = function parseRaw(data) {
|
|||||||
* @returns {Account}
|
* @returns {Account}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.fromRaw = function fromRaw(data) {
|
Account.fromRaw = function fromRaw(db, data) {
|
||||||
return new Account(Account.parseRaw(data));
|
return new Account(db).fromRaw(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2301,8 +2258,8 @@ Account.fromRaw = function fromRaw(data) {
|
|||||||
* @returns {Account}
|
* @returns {Account}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.fromJSON = function fromJSON(json) {
|
Account.fromJSON = function fromJSON(db, json) {
|
||||||
return new Account(Account.parseJSON(json));
|
return new Account(db).fromJSON(json);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -45,7 +45,7 @@ function WalletDB(options) {
|
|||||||
|
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
this.watchers = [];
|
this.watchers = {};
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.network = bcoin.network.get(options.network);
|
this.network = bcoin.network.get(options.network);
|
||||||
@ -249,19 +249,18 @@ WalletDB.prototype.destroy = function destroy(callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a wallet with the walletdb.
|
* Register an object with the walletdb.
|
||||||
* @param {WalletID} id
|
* @param {Object} object
|
||||||
* @param {Wallet} wallet
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.register = function register(wallet) {
|
WalletDB.prototype.register = function register(object) {
|
||||||
var id = wallet.id;
|
var id = object.id;
|
||||||
|
|
||||||
if (!this.watchers[id])
|
if (!this.watchers[id])
|
||||||
this.watchers[id] = { wallet: wallet, refs: 0 };
|
this.watchers[id] = { object: object, refs: 0 };
|
||||||
|
|
||||||
// Should never happen, and if it does, I will cry.
|
// Should never happen, and if it does, I will cry.
|
||||||
assert(this.watchers[id].wallet === wallet, 'I\'m crying.');
|
assert(this.watchers[id].object === object, 'I\'m crying.');
|
||||||
|
|
||||||
// We do some reference counting here
|
// We do some reference counting here
|
||||||
// because we're thug like that (police
|
// because we're thug like that (police
|
||||||
@ -270,27 +269,41 @@ WalletDB.prototype.register = function register(wallet) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregister a wallet with the walletdb.
|
* Unregister a object with the walletdb.
|
||||||
* @param {WalletID} id
|
* @param {Object} object
|
||||||
* @param {Wallet} wallet
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.unregister = function unregister(wallet) {
|
WalletDB.prototype.unregister = function unregister(object) {
|
||||||
var id = wallet.id;
|
var id = object.id;
|
||||||
var watcher = this.watchers[id];
|
var watcher = this.watchers[id];
|
||||||
|
|
||||||
if (!watcher)
|
if (!watcher)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(watcher.wallet === wallet);
|
assert(watcher.object === object);
|
||||||
assert(watcher.refs !== 0, '`wallet.destroy()` called twice!');
|
assert(watcher.refs !== 0, '`destroy()` called twice!');
|
||||||
|
|
||||||
if (--watcher.refs === 0)
|
if (--watcher.refs === 0)
|
||||||
delete this.watchers[id];
|
delete this.watchers[id];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fire an event for a registered wallet.
|
* Watch an object (increment reference count).
|
||||||
|
* @param {Object} object
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletDB.prototype.watch = function watch(object) {
|
||||||
|
var id = object.id;
|
||||||
|
var watcher = this.watchers[id];
|
||||||
|
|
||||||
|
if (!watcher)
|
||||||
|
return;
|
||||||
|
|
||||||
|
watcher.refs++;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fire an event for a registered object.
|
||||||
* @param {WalletID} id
|
* @param {WalletID} id
|
||||||
* @param {...Object} args
|
* @param {...Object} args
|
||||||
*/
|
*/
|
||||||
@ -307,11 +320,11 @@ WalletDB.prototype.fire = function fire(id) {
|
|||||||
for (i = 1; i < arguments.length; i++)
|
for (i = 1; i < arguments.length; i++)
|
||||||
args[i - 1] = arguments[i];
|
args[i - 1] = arguments[i];
|
||||||
|
|
||||||
watcher.wallet.emit.apply(watcher.wallet, args);
|
watcher.object.emit.apply(watcher.object, args);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for a listener on a registered wallet.
|
* Test for a listener on a registered object.
|
||||||
* @param {WalletID} id
|
* @param {WalletID} id
|
||||||
* @param {String} event
|
* @param {String} event
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
@ -323,7 +336,7 @@ WalletDB.prototype.hasListener = function hasListener(id, event) {
|
|||||||
if (!watcher)
|
if (!watcher)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (watcher.wallet.listeners(event).length !== 0)
|
if (watcher.object.listeners(event).length !== 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -337,14 +350,16 @@ WalletDB.prototype.hasListener = function hasListener(id, event) {
|
|||||||
|
|
||||||
WalletDB.prototype.get = function get(id, callback) {
|
WalletDB.prototype.get = function get(id, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var wallet;
|
var watcher, wallet;
|
||||||
|
|
||||||
if (!id)
|
if (!id)
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
if (this.watchers[id]) {
|
watcher = this.watchers[id];
|
||||||
this.watchers[id].refs++;
|
|
||||||
return callback(null, this.watchers[id].wallet);
|
if (watcher) {
|
||||||
|
watcher.refs++;
|
||||||
|
return callback(null, watcher.object);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.db.get('w/' + id, function(err, data) {
|
this.db.get('w/' + id, function(err, data) {
|
||||||
@ -355,9 +370,13 @@ WalletDB.prototype.get = function get(id, callback) {
|
|||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
data = bcoin.wallet.parseRaw(data);
|
wallet = bcoin.wallet.fromRaw(self, data);
|
||||||
data.db = self;
|
} catch (e) {
|
||||||
wallet = new bcoin.wallet(data);
|
return callback(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
self.register(wallet);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return callback(e);
|
return callback(e);
|
||||||
}
|
}
|
||||||
@ -371,33 +390,6 @@ WalletDB.prototype.get = function get(id, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Get raw wallet from the database, do not instantiate.
|
|
||||||
* @param {WalletID} id
|
|
||||||
* @param {Function} callback - Returns [Error, {@link Wallet}].
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletDB.prototype.getRaw = function getRaw(id, callback) {
|
|
||||||
if (!id)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
this.db.get('w/' + id, function(err, data) {
|
|
||||||
if (err && err.type !== 'NotFoundError')
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
if (!data)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
try {
|
|
||||||
data = bcoin.wallet.parseRaw(data);
|
|
||||||
} catch (e) {
|
|
||||||
return callback(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback(null, data);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a wallet to the database.
|
* Save a wallet to the database.
|
||||||
* @param {Wallet} wallet
|
* @param {Wallet} wallet
|
||||||
@ -436,13 +428,19 @@ WalletDB.prototype.create = function create(options, callback) {
|
|||||||
if (exists)
|
if (exists)
|
||||||
return callback(new Error('Wallet already exists.'));
|
return callback(new Error('Wallet already exists.'));
|
||||||
|
|
||||||
options = utils.merge({}, options);
|
try {
|
||||||
|
wallet = bcoin.wallet.fromOptions(self, options);
|
||||||
|
} catch (e) {
|
||||||
|
return callback(e);
|
||||||
|
}
|
||||||
|
|
||||||
options.network = self.network;
|
try {
|
||||||
options.db = self;
|
self.register(wallet);
|
||||||
wallet = new bcoin.wallet(options);
|
} catch (e) {
|
||||||
|
return callback(e);
|
||||||
|
}
|
||||||
|
|
||||||
wallet.open(function(err) {
|
wallet.init(options, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -510,9 +508,7 @@ WalletDB.prototype.getAccount = function getAccount(id, name, callback) {
|
|||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
data = bcoin.account.parseRaw(data);
|
account = bcoin.account.fromRaw(self, data);
|
||||||
data.db = self;
|
|
||||||
account = new bcoin.account(data);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return callback(e);
|
return callback(e);
|
||||||
}
|
}
|
||||||
@ -620,16 +616,9 @@ WalletDB.prototype.createAccount = function createAccount(options, callback) {
|
|||||||
if (exists)
|
if (exists)
|
||||||
return callback(new Error('Account already exists.'));
|
return callback(new Error('Account already exists.'));
|
||||||
|
|
||||||
options = utils.merge({}, options);
|
account = bcoin.account.fromOptions(self, options);
|
||||||
|
|
||||||
if (self.network.witness)
|
account.init(function(err) {
|
||||||
options.witness = options.witness !== false;
|
|
||||||
|
|
||||||
options.network = self.network;
|
|
||||||
options.db = self;
|
|
||||||
account = new bcoin.account(options);
|
|
||||||
|
|
||||||
account.open(function(err) {
|
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user