wallet: more rewriting.

This commit is contained in:
Christopher Jeffrey 2016-10-01 18:18:02 -07:00
parent d2832f001d
commit 8c5c9de132
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
8 changed files with 340 additions and 303 deletions

View File

@ -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.');

View File

@ -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')
};
};

View File

@ -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';
};
/*

View File

@ -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;
};

View File

@ -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;
});
/**

View File

@ -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;

View File

@ -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
*/

View File

@ -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'));