diff --git a/lib/http/rpc.js b/lib/http/rpc.js index 4c6a5214..fa4fc6ae 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -2364,7 +2364,7 @@ RPC.prototype._createRedeem = co(function* _createRedeem(args) { if (!hash) throw new RPCError('Invalid key.'); - ring = yield this.node.wallet.getKeyRing(hash); + ring = yield this.node.wallet.getKey(hash); if (!ring) throw new RPCError('Invalid key.'); @@ -2724,7 +2724,7 @@ RPC.prototype.dumpprivkey = co(function* dumpprivkey(args) { if (!hash) throw new RPCError('Invalid address.'); - ring = yield this.wallet.getKeyRing(hash); + ring = yield this.wallet.getKey(hash); if (!ring) throw new RPCError('Key not found.'); @@ -2760,7 +2760,7 @@ RPC.prototype.dumpwallet = co(function* dumpwallet(args) { for (i = 0; i < hashes.length; i++) { hash = hashes[i]; - ring = yield this.wallet.getKeyRing(hash); + ring = yield this.wallet.getKey(hash); if (!ring) continue; @@ -2828,7 +2828,7 @@ RPC.prototype.getaccountaddress = co(function* getaccountaddress(args) { if (!account) return ''; - return account.receiveAddress.getAddress('base58'); + return account.receive.getAddress('base58'); }); RPC.prototype.getaccount = co(function* getaccount(args) { @@ -3697,13 +3697,13 @@ RPC.prototype.listunspent = co(function* listunspent(args) { continue; } - ring = yield this.wallet.getKeyRing(hash); + ring = yield this.wallet.getKey(hash); out.push({ txid: utils.revHex(coin.hash), vout: coin.index, address: address ? address.toBase58(this.network) : null, - account: ring ? ring.path.name : undefined, + account: ring ? ring.name : undefined, redeemScript: ring && ring.script ? ring.script.toJSON() : undefined, @@ -3918,7 +3918,7 @@ RPC.prototype.signmessage = co(function* signmessage(args) { if (!address) throw new RPCError('Invalid address.'); - ring = yield this.wallet.getKeyRing(address); + ring = yield this.wallet.getKey(address); if (!ring) throw new RPCError('Address not found.'); diff --git a/lib/primitives/keyring.js b/lib/primitives/keyring.js index cd411c19..9e1974f4 100644 --- a/lib/primitives/keyring.js +++ b/lib/primitives/keyring.js @@ -44,8 +44,8 @@ function KeyRing(options, network) { this._keyHash = null; this._keyAddress = null; this._program = null; - this._programHash = null; - this._programAddress = null; + this._nestedHash = null; + this._nestedAddress = null; this._scriptHash160 = null; this._scriptHash256 = null; this._scriptAddress = null; @@ -399,16 +399,16 @@ KeyRing.prototype.getProgram = function getProgram() { * @returns {Buffer} */ -KeyRing.prototype.getProgramHash = function getProgramHash(enc) { +KeyRing.prototype.getNestedHash = function getNestedHash(enc) { if (!this.witness) return; - if (!this._programHash) - this._programHash = this.getProgram().hash160(); + if (!this._nestedHash) + this._nestedHash = this.getProgram().hash160(); return enc === 'hex' - ? this._programHash.toString('hex') - : this._programHash; + ? this._nestedHash.toString('hex') + : this._nestedHash; }; /** @@ -417,22 +417,22 @@ KeyRing.prototype.getProgramHash = function getProgramHash(enc) { * @returns {Address|Base58Address} */ -KeyRing.prototype.getProgramAddress = function getProgramAddress(enc) { +KeyRing.prototype.getNestedAddress = function getNestedAddress(enc) { var hash, address; if (!this.witness) return; - if (!this._programAddress) { - hash = this.getProgramHash(); + if (!this._nestedAddress) { + hash = this.getNestedHash(); address = this.compile(hash, scriptTypes.SCRIPTHASH); - this._programAddress = address; + this._nestedAddress = address; } if (enc === 'base58') - return this._programAddress.toBase58(); + return this._nestedAddress.toBase58(); - return this._programAddress; + return this._nestedAddress; }; /** @@ -606,7 +606,7 @@ KeyRing.prototype.ownHash = function ownHash(hash) { return true; if (this.witness) { - if (utils.equal(hash, this.programHash)) + if (utils.equal(hash, this.nestedHash)) return true; } @@ -662,7 +662,7 @@ KeyRing.prototype.ownOutput = function ownOutput(tx, index) { KeyRing.prototype.getRedeem = function(hash) { if (this.program) { - if (utils.equal(hash, this.programHash)) + if (utils.equal(hash, this.nestedHash)) return this.program; } @@ -758,12 +758,12 @@ KeyRing.prototype.__defineGetter__('program', function() { return this.getProgram(); }); -KeyRing.prototype.__defineGetter__('programHash', function() { - return this.getProgramHash(); +KeyRing.prototype.__defineGetter__('nestedHash', function() { + return this.getNestedHash(); }); -KeyRing.prototype.__defineGetter__('programAddress', function() { - return this.getProgramAddress(); +KeyRing.prototype.__defineGetter__('nestedAddress', function() { + return this.getNestedAddress(); }); KeyRing.prototype.__defineGetter__('keyHash', function() { @@ -804,7 +804,7 @@ KeyRing.prototype.toJSON = function toJSON() { script: this.script ? this.script.toRaw().toString('hex') : null, type: constants.scriptTypesByVal[this.type].toLowerCase(), address: this.getAddress('base58'), - programAddress: this.getProgramAddress('base58') + nestedAddress: this.getNestedAddress('base58') }; }; diff --git a/lib/wallet/account.js b/lib/wallet/account.js index 3fd2e5bf..bf3cabf8 100644 --- a/lib/wallet/account.js +++ b/lib/wallet/account.js @@ -15,7 +15,7 @@ var BufferReader = require('../utils/reader'); var BufferWriter = require('../utils/writer'); var Path = require('./path'); var Script = require('../script/script'); -var KeyRing = require('./kr'); +var WalletKey = require('./walletkey'); /** * Represents a BIP44 Account belonging to a {@link Wallet}. @@ -51,8 +51,8 @@ function Account(db, options) { this.network = db.network; this.lookahead = Account.MAX_LOOKAHEAD; - this.receiveAddress = null; - this.changeAddress = null; + this.receive = null; + this.change = null; this.wid = 0; this.id = null; @@ -232,8 +232,8 @@ Account.prototype.open = function open() { if (!this.initialized) return Promise.resolve(null); - this.receiveAddress = this.deriveReceive(this.receiveDepth - 1); - this.changeAddress = this.deriveChange(this.changeDepth - 1); + this.receive = this.deriveReceive(this.receiveDepth - 1); + this.change = this.deriveChange(this.changeDepth - 1); return Promise.resolve(null); }; @@ -375,45 +375,47 @@ Account.prototype.removeKey = function removeKey(key) { /** * Create a new receiving address (increments receiveDepth). - * @returns {KeyRing} + * @returns {WalletKey} */ Account.prototype.createReceive = function createReceive() { - return this.createAddress(false); + return this.createKey(false); }; /** * Create a new change address (increments receiveDepth). - * @returns {KeyRing} + * @returns {WalletKey} */ Account.prototype.createChange = function createChange() { - return this.createAddress(true); + return this.createKey(true); }; /** * Create a new address (increments depth). * @param {Boolean} change - * @returns {Promise} - Returns {@link KeyRing}. + * @returns {Promise} - Returns {@link WalletKey}. */ -Account.prototype.createAddress = co(function* createAddress(change) { +Account.prototype.createKey = co(function* createKey(change) { var ring, lookahead; if (change) { ring = this.deriveChange(this.changeDepth); lookahead = this.deriveChange(this.changeDepth + this.lookahead); + yield this.saveKey(ring); + yield this.saveKey(lookahead); this.changeDepth++; - this.changeAddress = ring; + this.change = ring; } else { ring = this.deriveReceive(this.receiveDepth); lookahead = this.deriveReceive(this.receiveDepth + this.lookahead); + yield this.saveKey(ring); + yield this.saveKey(lookahead); this.receiveDepth++; - this.receiveAddress = ring; + this.receive = ring; } - yield this.saveAddress([ring, lookahead]); - this.save(); return ring; @@ -422,28 +424,28 @@ Account.prototype.createAddress = co(function* createAddress(change) { /** * Derive a receiving address at `index`. Do not increment depth. * @param {Number} index - * @returns {KeyRing} + * @returns {WalletKey} */ Account.prototype.deriveReceive = function deriveReceive(index, master) { - return this.deriveAddress(false, index, master); + return this.deriveKey(false, index, master); }; /** * Derive a change address at `index`. Do not increment depth. * @param {Number} index - * @returns {KeyRing} + * @returns {WalletKey} */ Account.prototype.deriveChange = function deriveChange(index, master) { - return this.deriveAddress(true, index, master); + return this.deriveKey(true, index, master); }; /** * Derive an address from `path` object. * @param {Path} path * @param {MasterKey} master - * @returns {KeyRing} + * @returns {WalletKey} */ Account.prototype.derivePath = function derivePath(path, master) { @@ -452,7 +454,7 @@ Account.prototype.derivePath = function derivePath(path, master) { switch (path.keyType) { case Path.types.HD: - return this.deriveAddress(path.change, path.index, master); + return this.deriveKey(path.change, path.index, master); case Path.types.KEY: assert(this.type === Account.types.PUBKEYHASH); @@ -462,8 +464,7 @@ Account.prototype.derivePath = function derivePath(path, master) { return; } - ring = KeyRing.fromRaw(data, this.network); - ring.path = path; + ring = WalletKey.fromImport(this, data, this.network); return ring; case Path.types.ADDRESS: @@ -477,10 +478,10 @@ Account.prototype.derivePath = function derivePath(path, master) { * Derive an address at `index`. Do not increment depth. * @param {Boolean} change - Whether the address on the change branch. * @param {Number} index - * @returns {KeyRing} + * @returns {WalletKey} */ -Account.prototype.deriveAddress = function deriveAddress(change, index, master) { +Account.prototype.deriveKey = function deriveKey(change, index, master) { var keys = []; var i, key, shared, ring, hash; @@ -493,8 +494,7 @@ Account.prototype.deriveAddress = function deriveAddress(change, index, master) key = this.accountKey.derive(change).derive(index); } - ring = KeyRing.fromPublic(key.publicKey, this.network); - ring.witness = this.witness; + ring = WalletKey.fromHD(this, key, change, index); switch (this.type) { case Account.types.PUBKEYHASH: @@ -513,13 +513,6 @@ Account.prototype.deriveAddress = function deriveAddress(change, index, master) break; } - if (key.privateKey) - ring.privateKey = key.privateKey; - - hash = ring.getHash('hex'); - - ring.path = Path.fromHD(this, hash, change, index); - return ring; }; @@ -551,12 +544,12 @@ Account.prototype.save = function save() { /** * Save addresses to path map. - * @param {KeyRing[]} rings + * @param {WalletKey[]} rings * @returns {Promise} */ -Account.prototype.saveAddress = function saveAddress(rings) { - return this.db.saveAddress(this.wid, rings); +Account.prototype.saveKey = function saveKey(ring) { + return this.db.saveKey(this.wid, ring); }; /** @@ -565,8 +558,8 @@ Account.prototype.saveAddress = function saveAddress(rings) { * @returns {Promise} */ -Account.prototype.savePath = function savePath(paths) { - return this.db.savePath(this.wid, paths); +Account.prototype.savePath = function savePath(path) { + return this.db.savePath(this.wid, path); }; /** @@ -574,44 +567,46 @@ Account.prototype.savePath = function savePath(paths) { * Allocate all addresses up to depth. Note that this also allocates * new lookahead addresses. * @param {Number} depth - * @returns {Promise} - Returns {@link KeyRing}, {@link KeyRing}. + * @returns {Promise} - Returns {@link WalletKey}, {@link WalletKey}. */ Account.prototype.setDepth = co(function* setDepth(receiveDepth, changeDepth) { - var rings = []; - var i, receive, change; + var i = -1; + var receive, change, lookahead; if (receiveDepth > this.receiveDepth) { for (i = this.receiveDepth; i < receiveDepth; i++) { receive = this.deriveReceive(i); - rings.push(receive); + yield this.saveKey(receive); } - for (i = receiveDepth; i < receiveDepth + this.lookahead; i++) - rings.push(this.deriveReceive(i)); + for (i = receiveDepth; i < receiveDepth + this.lookahead; i++) { + lookahead = this.deriveReceive(i); + yield this.saveKey(lookahead); + } - this.receiveAddress = receive; + this.receive = receive; this.receiveDepth = receiveDepth; } if (changeDepth > this.changeDepth) { for (i = this.changeDepth; i < changeDepth; i++) { change = this.deriveChange(i); - rings.push(change); + yield this.saveKey(change); } - for (i = changeDepth; i < changeDepth + this.lookahead; i++) - rings.push(this.deriveChange(i)); + for (i = changeDepth; i < changeDepth + this.lookahead; i++) { + lookahead = this.deriveChange(i); + yield this.saveKey(lookahead); + } - this.changeAddress = change; + this.change = change; this.changeDepth = changeDepth; } - if (rings.length === 0) + if (i === -1) return; - yield this.saveAddress(rings); - this.save(); return receive; @@ -632,10 +627,10 @@ Account.prototype.inspect = function inspect() { m: this.m, n: this.n, address: this.initialized - ? this.receiveAddress.getAddress() + ? this.receive.getAddress() : null, - programAddress: this.initialized - ? this.receiveAddress.getProgramAddress() + nestedAddress: this.initialized + ? this.receive.getNestedAddress() : null, witness: this.witness, accountIndex: this.accountIndex, @@ -667,14 +662,14 @@ Account.prototype.toJSON = function toJSON() { accountIndex: this.accountIndex, receiveDepth: this.receiveDepth, changeDepth: this.changeDepth, - receiveAddress: this.receiveAddress - ? this.receiveAddress.getAddress('base58') + receiveAddress: this.receive + ? this.receive.getAddress('base58') : null, - programAddress: this.receiveAddress - ? this.receiveAddress.getProgramAddress('base58') + nestedAddress: this.receive + ? this.receive.getNestedAddress('base58') : null, - changeAddress: this.changeAddress - ? this.changeAddress.getAddress('base58') + changeAddress: this.change + ? this.change.getAddress('base58') : null, accountKey: this.accountKey.xpubkey, keys: this.keys.map(function(key) { @@ -828,7 +823,7 @@ Account.fromJSON = function fromJSON(db, json) { Account.isAccount = function isAccount(obj) { return obj && typeof obj.receiveDepth === 'number' - && obj.deriveAddress === 'function'; + && obj.deriveKey === 'function'; }; /* diff --git a/lib/wallet/path.js b/lib/wallet/path.js index 3d918013..dba15746 100644 --- a/lib/wallet/path.js +++ b/lib/wallet/path.js @@ -30,14 +30,14 @@ function Path() { if (!(this instanceof Path)) return new Path(); - // Passed in by caller. - this.wid = null; - this.name = null; + this.keyType = Path.types.HD; + this.id = null; // Passed in by caller. + this.wid = -1; // Passed in by caller. + this.name = null; // Passed in by caller. this.account = 0; this.change = -1; this.index = -1; - this.keyType = -1; this.encrypted = false; this.data = null; @@ -45,10 +45,7 @@ function Path() { // Currently unused. this.type = bcoin.script.types.PUBKEYHASH; this.version = -1; - - // Passed in by caller. - this.id = null; - this.hash = null; + this.hash = null; // Passed in by caller. } /** @@ -71,20 +68,20 @@ Path.types = { Path.prototype.clone = function clone() { var path = new Path(); + path.keyType = this.keyType; + + path.id = this.id; path.wid = this.wid; path.name = this.name; path.account = this.account; path.change = this.change; path.index = this.index; - path.keyType = this.keyType; path.encrypted = this.encrypted; path.data = this.data; path.type = this.type; path.version = this.version; - - path.id = this.id; path.hash = this.hash; return path; @@ -177,77 +174,6 @@ Path.prototype.toRaw = function toRaw(writer) { return p; }; -/** - * Inject properties from hd account. - * @private - * @param {Account} account - * @param {KeyRing} ring - * @param {Number} change - * @param {Number} index - */ - -Path.prototype.fromHD = function fromHD(account, hash, change, index) { - this.wid = account.wid; - this.name = account.name; - this.account = account.accountIndex; - this.change = change; - this.index = index; - - this.keyType = Path.types.HD; - - this.version = account.witness ? 0 : -1; - this.type = account.getAddressType(); - - this.id = account.id; - this.hash = hash; - - return this; -}; - -/** - * Instantiate path from hd account and keyring. - * @param {Account} account - * @param {KeyRing} ring - * @param {Number} change - * @param {Number} index - * @returns {Path} - */ - -Path.fromHD = function fromHD(account, ring, change, index) { - return new Path().fromHD(account, ring, change, index); -}; - -/** - * Inject properties from keyring. - * @private - * @param {Account} account - * @param {KeyRing} ring - */ - -Path.prototype.fromKey = function fromKey(account, ring) { - this.wid = account.wid; - this.name = account.name; - this.account = account.accountIndex; - this.keyType = Path.types.KEY; - this.data = ring.toRaw(); - this.version = ring.witness ? 0 : -1; - this.type = ring.getAddressType(); - this.id = account.id; - this.hash = ring.getHash('hex'); - return this; -}; - -/** - * Instantiate path from keyring. - * @param {Account} account - * @param {KeyRing} ring - * @returns {Path} - */ - -Path.fromKey = function fromKey(account, ring) { - return new Path().fromKey(account, ring); -}; - /** * Inject properties from address. * @private @@ -256,13 +182,13 @@ Path.fromKey = function fromKey(account, ring) { */ Path.prototype.fromAddress = function fromAddress(account, address) { + this.keyType = Path.types.ADDRESS; + this.id = account.id; this.wid = account.wid; this.name = account.name; this.account = account.accountIndex; - this.keyType = Path.types.ADDRESS; this.version = address.version; this.type = address.type; - this.id = account.id; this.hash = address.getHash('hex'); return this; }; diff --git a/lib/wallet/wallet.js b/lib/wallet/wallet.js index ecd3f92a..02fac3d5 100644 --- a/lib/wallet/wallet.js +++ b/lib/wallet/wallet.js @@ -20,6 +20,7 @@ var BufferWriter = require('../utils/writer'); var TXDB = require('./txdb'); var Path = require('./path'); var Address = require('../primitives/address'); +var WalletKey = require('./walletkey'); /** * BIP44 Wallet @@ -676,34 +677,34 @@ Wallet.prototype.hasAccount = function hasAccount(account) { /** * Create a new receiving address (increments receiveDepth). * @param {(Number|String)?} account - * @returns {Promise} - Returns {@link KeyRing}. + * @returns {Promise} - Returns {@link WalletKey}. */ Wallet.prototype.createReceive = function createReceive(account) { - return this.createAddress(account, false); + return this.createKey(account, false); }; /** * Create a new change address (increments receiveDepth). * @param {(Number|String)?} account - * @returns {Promise} - Returns {@link KeyRing}. + * @returns {Promise} - Returns {@link WalletKey}. */ Wallet.prototype.createChange = function createChange(account) { - return this.createAddress(account, true); + return this.createKey(account, true); }; /** * Create a new address (increments depth). * @param {(Number|String)?} account * @param {Boolean} change - * @returns {Promise} - Returns {@link KeyRing}. + * @returns {Promise} - Returns {@link WalletKey}. */ -Wallet.prototype.createAddress = co(function* createAddress(account, change) { +Wallet.prototype.createKey = co(function* createKey(account, change) { var unlock = yield this.writeLock.lock(); try { - return yield this._createAddress(account, change); + return yield this._createKey(account, change); } finally { unlock(); } @@ -713,10 +714,10 @@ Wallet.prototype.createAddress = co(function* createAddress(account, change) { * Create a new address (increments depth) without a lock. * @param {(Number|String)?} account * @param {Boolean} change - * @returns {Promise} - Returns {@link KeyRing}. + * @returns {Promise} - Returns {@link WalletKey}. */ -Wallet.prototype._createAddress = co(function* createAddress(account, change) { +Wallet.prototype._createKey = co(function* createKey(account, change) { var result; if (typeof account === 'boolean') { @@ -735,7 +736,7 @@ Wallet.prototype._createAddress = co(function* createAddress(account, change) { this.start(); try { - result = yield account.createAddress(change); + result = yield account.createKey(change); } catch (e) { this.drop(); throw e; @@ -847,7 +848,7 @@ Wallet.prototype.getPaths = co(function* getPaths(account) { * Import a keyring (will not exist on derivation chain). * Rescanning must be invoked manually. * @param {(String|Number)?} account - * @param {KeyRing} ring + * @param {WalletKey} ring * @param {(String|Buffer)?} passphrase * @returns {Promise} */ @@ -865,7 +866,7 @@ Wallet.prototype.importKey = co(function* importKey(account, ring, passphrase) { * Import a keyring (will not exist on derivation chain) without a lock. * @private * @param {(String|Number)?} account - * @param {KeyRing} ring + * @param {WalletKey} ring * @param {(String|Buffer)?} passphrase * @returns {Promise} */ @@ -897,7 +898,8 @@ Wallet.prototype._importKey = co(function* importKey(account, ring, passphrase) yield this.unlock(passphrase); - path = Path.fromKey(account, ring); + ring = WalletKey.fromRing(account, ring); + path = ring.toPath(); if (this.master.encrypted) { path.data = this.master.encipher(path.data, path.hash); @@ -905,12 +907,10 @@ Wallet.prototype._importKey = co(function* importKey(account, ring, passphrase) path.encrypted = true; } - ring.path = path; - this.start(); try { - yield account.saveAddress([ring], true); + yield account.savePath(path); } catch (e) { this.drop(); throw e; @@ -923,7 +923,7 @@ Wallet.prototype._importKey = co(function* importKey(account, ring, passphrase) * Import a keyring (will not exist on derivation chain). * Rescanning must be invoked manually. * @param {(String|Number)?} account - * @param {KeyRing} ring + * @param {WalletKey} ring * @param {(String|Buffer)?} passphrase * @returns {Promise} */ @@ -941,7 +941,7 @@ Wallet.prototype.importAddress = co(function* importAddress(account, address) { * Import a keyring (will not exist on derivation chain) without a lock. * @private * @param {(String|Number)?} account - * @param {KeyRing} ring + * @param {WalletKey} ring * @param {(String|Buffer)?} passphrase * @returns {Promise} */ @@ -975,7 +975,7 @@ Wallet.prototype._importAddress = co(function* importAddress(account, address) { this.start(); try { - yield account.savePath([path], true); + yield account.savePath(path); } catch (e) { this.drop(); throw e; @@ -1065,14 +1065,14 @@ Wallet.prototype._fund = co(function* fund(tx, options) { free: options.free, hardFee: options.hardFee, subtractFee: options.subtractFee, - changeAddress: account.changeAddress.getAddress(), + changeAddress: account.change.getAddress(), height: this.db.height, rate: rate, maxFee: options.maxFee, m: account.m, n: account.n, witness: account.witness, - script: account.receiveAddress.script + script: account.receive.script }); }); @@ -1193,7 +1193,7 @@ Wallet.prototype.resend = co(function* resend() { * Derive necessary addresses for signing a transaction. * @param {TX|Input} tx * @param {Number?} index - Input index. - * @returns {Promise} - Returns {@link KeyRing}[]. + * @returns {Promise} - Returns {@link WalletKey}[]. */ Wallet.prototype.deriveInputs = co(function* deriveInputs(tx) { @@ -1224,7 +1224,7 @@ Wallet.prototype.deriveInputs = co(function* deriveInputs(tx) { * @returns {Promise} */ -Wallet.prototype.getKeyRing = co(function* getKeyRing(address) { +Wallet.prototype.getKey = co(function* getKey(address) { var hash = Address.getHash(address, 'hex'); var path, account; @@ -1447,7 +1447,7 @@ Wallet.prototype.getRedeem = co(function* getRedeem(hash) { if (typeof hash === 'string') hash = new Buffer(hash, 'hex'); - ring = yield this.getKeyRing(hash.toString('hex')); + ring = yield this.getKey(hash.toString('hex')); if (!ring) return; @@ -1690,9 +1690,9 @@ Wallet.prototype._getIndex = co(function* _getIndex(account) { */ Wallet.prototype.getPublicKey = function getPublicKey(enc) { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getPublicKey(enc); + return this.receive.getPublicKey(enc); }; /** @@ -1701,9 +1701,9 @@ Wallet.prototype.getPublicKey = function getPublicKey(enc) { */ Wallet.prototype.getScript = function getScript() { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getScript(); + return this.receive.getScript(); }; /** @@ -1713,9 +1713,9 @@ Wallet.prototype.getScript = function getScript() { */ Wallet.prototype.getScriptHash = function getScriptHash(enc) { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getScriptHash(enc); + return this.receive.getScriptHash(enc); }; /** @@ -1725,9 +1725,9 @@ Wallet.prototype.getScriptHash = function getScriptHash(enc) { */ Wallet.prototype.getScriptHash160 = function getScriptHash160(enc) { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getScriptHash160(enc); + return this.receive.getScriptHash160(enc); }; /** @@ -1737,9 +1737,9 @@ Wallet.prototype.getScriptHash160 = function getScriptHash160(enc) { */ Wallet.prototype.getScriptHash256 = function getScriptHash256(enc) { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getScriptHash256(enc); + return this.receive.getScriptHash256(enc); }; /** @@ -1749,9 +1749,9 @@ Wallet.prototype.getScriptHash256 = function getScriptHash256(enc) { */ Wallet.prototype.getScriptAddress = function getScriptAddress(enc) { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getScriptAddress(enc); + return this.receive.getScriptAddress(enc); }; /** @@ -1760,9 +1760,9 @@ Wallet.prototype.getScriptAddress = function getScriptAddress(enc) { */ Wallet.prototype.getProgram = function getProgram() { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getProgram(); + return this.receive.getProgram(); }; /** @@ -1772,10 +1772,10 @@ Wallet.prototype.getProgram = function getProgram() { * @returns {Buffer} */ -Wallet.prototype.getProgramHash = function getProgramHash(enc) { - if (!this.receiveAddress) +Wallet.prototype.getNestedHash = function getNestedHash(enc) { + if (!this.receive) return; - return this.receiveAddress.getProgramHash(enc); + return this.receive.getNestedHash(enc); }; /** @@ -1785,10 +1785,10 @@ Wallet.prototype.getProgramHash = function getProgramHash(enc) { * @returns {Address|Base58Address} */ -Wallet.prototype.getProgramAddress = function getProgramAddress(enc) { - if (!this.receiveAddress) +Wallet.prototype.getNestedAddress = function getNestedAddress(enc) { + if (!this.receive) return; - return this.receiveAddress.getProgramAddress(enc); + return this.receive.getNestedAddress(enc); }; /** @@ -1798,9 +1798,9 @@ Wallet.prototype.getProgramAddress = function getProgramAddress(enc) { */ Wallet.prototype.getKeyHash = function getKeyHash(enc) { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getKeyHash(enc); + return this.receive.getKeyHash(enc); }; /** @@ -1810,9 +1810,9 @@ Wallet.prototype.getKeyHash = function getKeyHash(enc) { */ Wallet.prototype.getKeyAddress = function getKeyAddress(enc) { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getKeyAddress(enc); + return this.receive.getKeyAddress(enc); }; /** @@ -1822,9 +1822,9 @@ Wallet.prototype.getKeyAddress = function getKeyAddress(enc) { */ Wallet.prototype.getHash = function getHash(enc) { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getHash(enc); + return this.receive.getHash(enc); }; /** @@ -1834,9 +1834,9 @@ Wallet.prototype.getHash = function getHash(enc) { */ Wallet.prototype.getAddress = function getAddress(enc) { - if (!this.receiveAddress) + if (!this.receive) return; - return this.receiveAddress.getAddress(enc); + return this.receive.getAddress(enc); }; Wallet.prototype.__defineGetter__('publicKey', function() { @@ -1867,12 +1867,12 @@ Wallet.prototype.__defineGetter__('program', function() { return this.getProgram(); }); -Wallet.prototype.__defineGetter__('programHash', function() { - return this.getProgramHash(); +Wallet.prototype.__defineGetter__('nestedHash', function() { + return this.getNestedHash(); }); -Wallet.prototype.__defineGetter__('programAddress', function() { - return this.getProgramAddress(); +Wallet.prototype.__defineGetter__('nestedAddress', function() { + return this.getNestedAddress(); }); Wallet.prototype.__defineGetter__('keyHash', function() { @@ -1909,16 +1909,16 @@ Wallet.prototype.__defineGetter__('accountKey', function() { return this.account.accountKey; }); -Wallet.prototype.__defineGetter__('receiveAddress', function() { +Wallet.prototype.__defineGetter__('receive', function() { if (!this.account) return; - return this.account.receiveAddress; + return this.account.receive; }); -Wallet.prototype.__defineGetter__('changeAddress', function() { +Wallet.prototype.__defineGetter__('change', function() { if (!this.account) return; - return this.account.changeAddress; + return this.account.change; }); /** diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index c4e88f71..c908c5f9 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -953,62 +953,34 @@ WalletDB.prototype.getWalletsByHash = co(function* getWalletsByHash(hash) { }); /** - * Save addresses to the path map. + * Save an address to the path map. * @param {WalletID} wid - * @param {KeyRing[]} rings + * @param {KeyRing[]} ring * @returns {Promise} */ -WalletDB.prototype.saveAddress = co(function* saveAddress(wid, rings) { - var i, ring, path; +WalletDB.prototype.saveKey = co(function* saveKey(wid, ring) { + yield this.savePath(wid, ring.toPath()); - for (i = 0; i < rings.length; i++) { - ring = rings[i]; - path = ring.path; + if (!ring.witness) + return; - yield this.writePath(wid, path); - - if (!ring.witness) - continue; - - path = path.clone(); - path.hash = ring.getProgramHash('hex'); - path.version = -1; - path.type = Script.types.SCRIPTHASH; - - yield this.writePath(wid, path); - } + yield this.savePath(wid, ring.toNestedPath()); }); /** - * Save paths to the path map. + * Save a path to the path map. * * The path map exists in the form of: * - `p[address-hash] -> wids` * - `P[wid][address-hash] -> path` * * @param {WalletID} wid - * @param {Path[]} paths + * @param {Path[]} path * @returns {Promise} */ -WalletDB.prototype.savePath = co(function* savePath(wid, paths) { - var i, path; - - for (i = 0; i < paths.length; i++) { - path = paths[i]; - yield this.writePath(wid, path); - } -}); - -/** - * Save a single address to the path map. - * @param {WalletID} wid - * @param {Path} path - * @returns {Promise} - */ - -WalletDB.prototype.writePath = co(function* writePath(wid, path) { +WalletDB.prototype.savePath = co(function* savePath(wid, path) { var hash = path.hash; var batch = this.batch(wid); var key = wid + hash; diff --git a/lib/wallet/kr.js b/lib/wallet/walletkey.js similarity index 53% rename from lib/wallet/kr.js rename to lib/wallet/walletkey.js index b01443d0..6be70c10 100644 --- a/lib/wallet/kr.js +++ b/lib/wallet/walletkey.js @@ -10,6 +10,9 @@ var constants = require('../protocol/constants'); var KeyRing = require('../primitives/keyring'); var utils = require('../utils/utils'); +var Path = require('./path'); +var Script = require('../script/script'); +var assert = utils.assert; /** * Represents a key ring which amounts to an address. @@ -29,7 +32,14 @@ function WalletKey(options, network) { KeyRing.call(this, options, network); - this.path = null; + this.keyType = Path.types.HD; + + this.id = null; + this.wid = -1; + this.name = null; + this.account = -1; + this.change = -1; + this.index = -1; } utils.inherits(WalletKey, KeyRing); @@ -122,14 +132,14 @@ WalletKey.prototype.toJSON = function toJSON() { publicKey: this.publicKey.toString('hex'), script: this.script ? this.script.toRaw().toString('hex') : null, type: constants.scriptTypesByVal[this.type].toLowerCase(), - wid: this.path.wid, - id: this.path.id, - name: this.path.name, - account: this.path.account, - change: this.path.change, - index: this.path.index, + wid: this.wid, + id: this.id, + name: this.name, + account: this.account, + change: this.change, + index: this.index, address: this.getAddress('base58'), - programAddress: this.getProgramAddress('base58') + nestedAddress: this.getNestedAddress('base58') }; }; @@ -153,6 +163,90 @@ WalletKey.fromRaw = function fromRaw(data) { return new WalletKey().fromRaw(data); }; +/** + * Instantiate a keyring from serialized data. + * @param {Buffer} data + * @returns {WalletKey} + */ + +WalletKey.prototype.fromHD = function fromHD(account, key, change, index) { + this.keyType = Path.types.HD; + this.id = account.id; + this.wid = account.wid; + this.name = account.name; + this.account = account.accountIndex; + this.change = change; + this.index = index; + this.witness = account.witness; + + if (key.privateKey) + return this.fromPrivate(key.privateKey, key.network); + + return this.fromPublic(key.publicKey, key.network); +}; + +/** + * Instantiate a keyring from serialized data. + * @param {Buffer} data + * @returns {WalletKey} + */ + +WalletKey.fromHD = function fromHD(account, key, change, index) { + return new WalletKey().fromHD(account, key, change, index); +}; + +/** + * Instantiate a keyring from serialized data. + * @param {Buffer} data + * @returns {WalletKey} + */ + +WalletKey.prototype.fromImport = function fromImport(account, data, network) { + this.keyType = Path.types.KEY; + this.id = account.id; + this.wid = account.wid; + this.name = account.name; + this.account = account.accountIndex; + this.witness = account.witness; + return this.fromRaw(data, network); +}; + +/** + * Instantiate a keyring from serialized data. + * @param {Buffer} data + * @returns {WalletKey} + */ + +WalletKey.fromImport = function fromImport(account, data, network) { + return new WalletKey().fromImport(account, data, network); +}; + +/** + * Instantiate a keyring from serialized data. + * @param {Buffer} data + * @returns {WalletKey} + */ + +WalletKey.prototype.fromRing = function fromRing(account, ring) { + this.keyType = Path.types.KEY; + this.id = account.id; + this.wid = account.wid; + this.name = account.name; + this.account = account.accountIndex; + this.witness = account.witness; + return this.fromOptions(ring, ring.network); +}; + +/** + * Instantiate a keyring from serialized data. + * @param {Buffer} data + * @returns {WalletKey} + */ + +WalletKey.fromRing = function fromRing(account, ring) { + return new WalletKey().fromRing(account, ring); +}; + /** * Test whether an object is a WalletKey. * @param {Object} obj @@ -166,6 +260,56 @@ WalletKey.isWalletKey = function isWalletKey(obj) { && typeof obj.toSecret === 'function'; }; +/** + * Test whether an object is a WalletKey. + * @param {Object} obj + * @returns {Boolean} + */ + +WalletKey.prototype.toPath = function toPath(nested) { + var path = new Path(); + + path.id = this.id; + path.wid = this.wid; + path.name = this.name; + path.account = this.account; + + switch (this.keyType) { + case Path.types.HD: + path.change = this.change; + path.index = this.index; + break; + case Path.types.KEY: + path.data = this.toRaw(); + break; + } + + path.keyType = this.keyType; + + if (nested) { + assert(this.witness); + path.version = -1; + path.type = Script.types.SCRIPTHASH; + path.hash = this.getNestedHash('hex'); + } else { + path.version = this.witness ? 0 : -1; + path.type = this.getAddressType(); + path.hash = this.getHash('hex'); + } + + return path; +}; + +/** + * Test whether an object is a WalletKey. + * @param {Object} obj + * @returns {Boolean} + */ + +WalletKey.prototype.toNestedPath = function toNestedPath() { + return this.toPath(true); +}; + /* * Expose */ diff --git a/test/wallet-test.js b/test/wallet-test.js index 1d26acd4..9ae12d44 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -107,7 +107,7 @@ describe('Wallet', function() { outputs: [{ value: 5460 * 2, address: bullshitNesting - ? w.getProgramAddress() + ? w.getNestedAddress() : w.getAddress() }, { value: 5460 * 2, @@ -543,10 +543,10 @@ describe('Wallet', function() { assert.equal(w2.getAddress('base58'), b58); assert.equal(w3.getAddress('base58'), b58); - paddr = w1.getProgramAddress('base58'); - assert.equal(w1.getProgramAddress('base58'), paddr); - assert.equal(w2.getProgramAddress('base58'), paddr); - assert.equal(w3.getProgramAddress('base58'), paddr); + paddr = w1.getNestedAddress('base58'); + assert.equal(w1.getNestedAddress('base58'), paddr); + assert.equal(w2.getNestedAddress('base58'), paddr); + assert.equal(w3.getNestedAddress('base58'), paddr); // Add a shared unspent transaction to our wallets utx = bcoin.mtx(); @@ -595,10 +595,10 @@ describe('Wallet', function() { assert.equal(w1.changeDepth, 1); - change = w1.changeAddress.getAddress('base58'); - assert.equal(w1.changeAddress.getAddress('base58'), change); - assert.equal(w2.changeAddress.getAddress('base58'), change); - assert.equal(w3.changeAddress.getAddress('base58'), change); + change = w1.change.getAddress('base58'); + assert.equal(w1.change.getAddress('base58'), change); + assert.equal(w2.change.getAddress('base58'), change); + assert.equal(w3.change.getAddress('base58'), change); // Simulate a confirmation send.ps = 0; @@ -613,11 +613,11 @@ describe('Wallet', function() { assert.equal(w1.changeDepth, 2); assert(w1.getAddress('base58') === b58); - assert(w1.changeAddress.getAddress('base58') !== change); - change = w1.changeAddress.getAddress('base58'); - assert.equal(w1.changeAddress.getAddress('base58'), change); - assert.equal(w2.changeAddress.getAddress('base58'), change); - assert.equal(w3.changeAddress.getAddress('base58'), change); + assert(w1.change.getAddress('base58') !== change); + change = w1.change.getAddress('base58'); + assert.equal(w1.change.getAddress('base58'), change); + assert.equal(w2.change.getAddress('base58'), change); + assert.equal(w3.change.getAddress('base58'), change); if (witness) { send.inputs[0].witness.set(2, 0); @@ -654,7 +654,7 @@ describe('Wallet', function() { account = yield w1.getAccount('foo'); assert.equal(account.name, 'foo'); assert.equal(account.accountIndex, 1); - rec = account.receiveAddress; + rec = account.receive; // Coinbase t1 = bcoin.mtx() @@ -712,18 +712,18 @@ describe('Wallet', function() { assert(w.account.accountIndex === 0); assert.notEqual( - account.receiveAddress.getAddress('base58'), - w.account.receiveAddress.getAddress('base58')); + account.receive.getAddress('base58'), + w.account.receive.getAddress('base58')); assert.equal(w.getAddress('base58'), - w.account.receiveAddress.getAddress('base58')); + w.account.receive.getAddress('base58')); // Coinbase t1 = bcoin.mtx() .addOutput(w.getAddress(), 5460) .addOutput(w.getAddress(), 5460) .addOutput(w.getAddress(), 5460) - .addOutput(account.receiveAddress.getAddress(), 5460); + .addOutput(account.receive.getAddress(), 5460); t1.addInput(dummyInput); t1 = t1.toTX(); @@ -745,9 +745,9 @@ describe('Wallet', function() { // Coinbase t1 = bcoin.mtx() - .addOutput(account.receiveAddress.getAddress(), 5460) - .addOutput(account.receiveAddress.getAddress(), 5460) - .addOutput(account.receiveAddress.getAddress(), 5460); + .addOutput(account.receive.getAddress(), 5460) + .addOutput(account.receive.getAddress(), 5460) + .addOutput(account.receive.getAddress(), 5460); t1.ps = 0xdeadbeef; t1.addInput(dummyInput); @@ -901,7 +901,7 @@ describe('Wallet', function() { yield w.importKey('default', key, 'test'); - k = yield w.getKeyRing(key.getHash('hex')); + k = yield w.getKey(key.getHash('hex')); assert.equal(k.getHash('hex'), key.getHash('hex'));