wallet: move watchOnly flag to wallet for safety.

This commit is contained in:
Christopher Jeffrey 2016-10-03 03:03:10 -07:00
parent 25946b8909
commit 2097450b42
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 36 additions and 20 deletions

View File

@ -211,7 +211,7 @@ Account.fromOptions = function fromOptions(db, options) {
* @const {Number}
*/
Account.MAX_LOOKAHEAD = 5;
Account.MAX_LOOKAHEAD = 10;
/**
* Attempt to intialize the account (generating
@ -794,7 +794,6 @@ Account.prototype.toRaw = function toRaw(writer) {
p.writeU32(this.network.magic);
p.writeVarString(this.name, 'ascii');
p.writeU8(this.initialized ? 1 : 0);
p.writeU8(this.watchOnly ? 1 : 0);
p.writeU8(this.type);
p.writeU8(this.m);
p.writeU8(this.n);
@ -831,7 +830,6 @@ Account.prototype.fromRaw = function fromRaw(data) {
this.network = Network.fromMagic(p.readU32());
this.name = p.readVarString('ascii');
this.initialized = p.readU8() === 1;
this.watchOnly = p.readU8() === 1;
this.type = p.readU8();
this.m = p.readU8();
this.n = p.readU8();

View File

@ -71,6 +71,7 @@ function Wallet(db, options) {
this.id = null;
this.master = null;
this.initialized = false;
this.watchOnly = false;
this.accountDepth = 0;
this.token = constants.ZERO_HASH;
this.tokenDepth = 0;
@ -111,6 +112,11 @@ Wallet.prototype.fromOptions = function fromOptions(options) {
this.initialized = options.initialized;
}
if (options.watchOnly != null) {
assert(typeof options.watchOnly === 'boolean');
this.watchOnly = options.watchOnly;
}
if (options.accountDepth != null) {
assert(utils.isNumber(options.accountDepth));
this.accountDepth = options.accountDepth;
@ -633,7 +639,6 @@ Wallet.prototype._createAccount = co(function* createAccount(options) {
var passphrase = options.passphrase;
var timeout = options.timeout;
var name = options.name;
var watchOnly = options.watchOnly === true;
var key, master, account;
if (typeof options.account === 'string')
@ -644,7 +649,7 @@ Wallet.prototype._createAccount = co(function* createAccount(options) {
master = yield this.unlock(passphrase, timeout);
if (watchOnly && options.accountKey) {
if (this.watchOnly && options.accountKey) {
key = options.accountKey;
if (!HD.isHD(key))
key = HD.from(key, this.network);
@ -664,7 +669,7 @@ Wallet.prototype._createAccount = co(function* createAccount(options) {
keys: options.keys,
m: options.m,
n: options.n,
watchOnly: watchOnly
watchOnly: this.watchOnly
};
this.start();
@ -742,6 +747,7 @@ Wallet.prototype.getAccount = co(function* getAccount(account) {
account.wid = this.wid;
account.id = this.id;
account.watchOnly = this.watchOnly;
return account;
});
@ -976,6 +982,14 @@ Wallet.prototype._importKey = co(function* importKey(account, ring, passphrase)
if (account == null)
account = 0;
if (!this.watchOnly) {
if (!ring.privateKey)
throw new Error('Cannot import pubkey into non watch-only wallet.');
} else {
if (ring.privateKey)
throw new Error('Cannot import privkey into watch-only wallet.');
}
exists = yield this.getPath(ring.getHash('hex'));
if (exists)
@ -989,9 +1003,6 @@ Wallet.prototype._importKey = co(function* importKey(account, ring, passphrase)
if (account.type !== Account.types.PUBKEYHASH)
throw new Error('Cannot import into non-pkh account.');
if (!ring.privateKey && !account.watchOnly)
throw new Error('Cannot import pubkey into non-watchonly account.');
yield this.unlock(passphrase);
ring = WalletKey.fromRing(account, ring);
@ -1053,6 +1064,9 @@ Wallet.prototype._importAddress = co(function* importAddress(account, address) {
if (account == null)
account = 0;
if (!this.watchOnly)
throw new Error('Cannot import address into non watch-only wallet.');
exists = yield this.getPath(address);
if (exists)
@ -1066,9 +1080,6 @@ Wallet.prototype._importAddress = co(function* importAddress(account, address) {
if (account.type !== Account.types.PUBKEYHASH)
throw new Error('Cannot import into non-pkh account.');
if (!account.watchOnly)
throw new Error('Cannot import address into non-watchonly account.');
path = Path.fromAddress(account, address);
this.start();
@ -1132,6 +1143,9 @@ Wallet.prototype._fund = co(function* fund(tx, options) {
if (!this.initialized)
throw new Error('Wallet is not initialized.');
if (this.watchOnly)
throw new Error('Cannot fund from watch-only wallet.');
if (options.account != null) {
account = yield this.getAccount(options.account);
if (!account)
@ -1595,6 +1609,9 @@ Wallet.prototype.sign = co(function* sign(tx, options) {
if (typeof options === 'string' || Buffer.isBuffer(options))
options = { passphrase: options };
if (this.watchOnly)
throw new Error('Cannot sign from a watch-only wallet.');
yield this.unlock(options.passphrase, options.timeout);
rings = yield this.deriveInputs(tx);
@ -2073,6 +2090,7 @@ Wallet.prototype.toJSON = function toJSON() {
wid: this.wid,
id: this.id,
initialized: this.initialized,
watchOnly: this.watchOnly,
accountDepth: this.accountDepth,
token: this.token.toString('hex'),
tokenDepth: this.tokenDepth,
@ -2090,6 +2108,7 @@ Wallet.prototype.toJSON = function toJSON() {
Wallet.prototype.fromJSON = function fromJSON(json) {
assert(utils.isNumber(json.wid));
assert(typeof json.initialized === 'boolean');
assert(typeof json.watchOnly === 'boolean');
assert(utils.isName(json.id), 'Bad wallet ID.');
assert(utils.isNumber(json.accountDepth));
assert(typeof json.token === 'string');
@ -2100,6 +2119,7 @@ Wallet.prototype.fromJSON = function fromJSON(json) {
this.wid = json.wid;
this.id = json.id;
this.initialized = json.initialized;
this.watchOnly = json.watchOnly;
this.accountDepth = json.accountDepth;
this.token = new Buffer(json.token, 'hex');
this.master = MasterKey.fromJSON(json.master);
@ -2119,6 +2139,7 @@ Wallet.prototype.toRaw = function toRaw(writer) {
p.writeU32(this.wid);
p.writeVarString(this.id, 'ascii');
p.writeU8(this.initialized ? 1 : 0);
p.writeU8(this.watchOnly ? 1 : 0);
p.writeU32(this.accountDepth);
p.writeBytes(this.token);
p.writeU32(this.tokenDepth);
@ -2142,6 +2163,7 @@ Wallet.prototype.fromRaw = function fromRaw(data) {
this.wid = p.readU32();
this.id = p.readVarString('ascii');
this.initialized = p.readU8() === 1;
this.watchOnly = p.readU8() === 1;
this.accountDepth = p.readU32();
this.token = p.readBytes(32);
this.tokenDepth = p.readU32();

View File

@ -946,12 +946,10 @@ describe('Wallet', function() {
it('should import pubkey', cob(function *() {
var priv = bcoin.keyring.generate();
var key = new bcoin.keyring(priv.publicKey);
var w = yield walletdb.create();
var w = yield walletdb.create({ watchOnly: true });
var options, k, t1, t2, tx;
yield w.createAccount({ name: 'watchonly', watchOnly: true });
yield w.importKey('watchonly', key);
yield w.importKey('default', key);
k = yield w.getPath(key.getHash('hex'));
@ -963,12 +961,10 @@ describe('Wallet', function() {
it('should import address', cob(function *() {
var key = bcoin.keyring.generate();
var w = yield walletdb.create();
var w = yield walletdb.create({ watchOnly: true });
var options, k, t1, t2, tx;
yield w.createAccount({ name: 'watchonly', watchOnly: true });
yield w.importAddress('watchonly', key.getAddress());
yield w.importAddress('default', key.getAddress());
k = yield w.getPath(key.getHash('hex'));