http: more wallet api calls.

This commit is contained in:
Christopher Jeffrey 2016-11-02 01:53:44 -07:00
parent ace4c89391
commit aa79d92a83
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
10 changed files with 265 additions and 206 deletions

64
bin/cli
View File

@ -66,21 +66,44 @@ CLI.prototype.createWallet = co(function* createWallet() {
this.log(wallet);
});
CLI.prototype.addKey = co(function* addKey() {
CLI.prototype.getMaster = co(function* getMaster() {
var master = yield this.wallet.getMaster();
this.log(master);
});
CLI.prototype.getKey = co(function* getKey() {
var address = this.argv[0];
var key = yield this.wallet.getKey(address);
this.log(key);
});
CLI.prototype.getWIF = co(function* getWIF() {
var address = this.argv[0];
var key = yield this.wallet.getWIF(address, this.config.passphrase);
this.log(key.privateKey);
});
CLI.prototype.addSharedKey = co(function* addSharedKey() {
var key = this.argv[0];
yield this.wallet.addKey(this.config.account, key);
yield this.wallet.addSharedKey(this.config.account, key);
this.log('Added key.');
});
CLI.prototype.removeKey = co(function* removeKey() {
CLI.prototype.removeSharedKey = co(function* removeSharedKey() {
var key = this.argv[0];
yield this.wallet.removeKey(this.config.account, key);
yield this.wallet.removeSharedKey(this.config.account, key);
this.log('Removed key.');
});
CLI.prototype.getSharedKeys = co(function* getSharedKeys() {
var acct = this.argv[0] || this.config.account;
var account = yield this.wallet.getAccount(acct);
this.log(account.keys);
});
CLI.prototype.getAccount = co(function* getAccount() {
var account = this.argv[0] || this.config.account;
yield this.wallet.getAccount(account);
var acct = this.argv[0] || this.config.account;
var account = yield this.wallet.getAccount(acct);
this.log(account);
});
@ -409,10 +432,20 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
return yield this.listenWallet();
case 'get':
return yield this.getWallet();
case 'addkey':
return yield this.addKey();
case 'rmkey':
return yield this.removeKey();
case 'master':
return yield this.getMaster();
case 'shared':
if (this.argv[0] === 'add') {
this.argv.shift();
return yield this.addSharedKey();
}
if (this.argv[0] === 'remove') {
this.argv.shift();
return yield this.removeSharedKey();
}
if (this.argv[0] === 'list')
this.argv.shift();
return yield this.getSharedKeys();
case 'balance':
return yield this.getBalance();
case 'history':
@ -453,6 +486,10 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
return yield this.importKey();
case 'watch':
return yield this.importAddress();
case 'key':
return yield this.getKey();
case 'dump':
return yield this.getWIF();
case 'lock':
return yield this.lock();
case 'unlock':
@ -464,8 +501,9 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
this.log('Commands:');
this.log(' $ listen: Listen for events.');
this.log(' $ get: View wallet.');
this.log(' $ addkey [xpubkey]: Add key to wallet.');
this.log(' $ rmkey [xpubkey]: Remove key from wallet.');
this.log(' $ master: View wallet master key.');
this.log(' $ shared add [xpubkey]: Add key to wallet.');
this.log(' $ shared remove [xpubkey]: Remove key from wallet.');
this.log(' $ balance: Get wallet balance.');
this.log(' $ history: View wallet TX history.');
this.log(' $ coins: View wallet coins.');
@ -483,6 +521,8 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
this.log(' $ view [tx-hex]: Parse and view transaction.');
this.log(' $ import [wif|hex]: Import private or public key.');
this.log(' $ watch [address]: Import an address.');
this.log(' $ key [address]: Get wallet key by address.');
this.log(' $ dump [address]: Get wallet key WIF by address.');
this.log(' $ lock: Lock wallet.');
this.log(' $ unlock [passphrase] [timeout?]: Unlock wallet.');
this.log(' $ resend: Resend pending transactions.');

View File

@ -677,32 +677,56 @@ HTTPClient.prototype.zapWallet = function zapWallet(id, account, age) {
return this._post('/wallet/' + id + '/zap', body);
};
/**
* Get wallet key.
* @param {WalletID} id
* @param {Base58Address} address
* @returns {Promise}
*/
HTTPClient.prototype.getKey = function getKey(id, address) {
return this._get('/wallet/' + id + '/key/' + address);
};
/**
* Get wallet key WIF dump.
* @param {WalletID} id
* @param {Base58Address} address
* @param {String?} passphrase
* @returns {Promise}
*/
HTTPClient.prototype.getWIF = function getWIF(id, address, passphrase) {
var options = { passphrase: passphrase };
return this._get('/wallet/' + id + '/wif/' + address, options);
};
/**
* Add a public account/purpose key to the wallet for multisig.
* @param {WalletID} id
* @param {(String|Number)?} account
* @param {HDPublicKey|Base58String} key - Account (bip44) or
* @param {Base58String} key - Account (bip44) or
* Purpose (bip45) key (can be in base58 form).
* @returns {Promise}
*/
HTTPClient.prototype.addKey = function addKey(id, account, key) {
HTTPClient.prototype.addSharedKey = function addSharedKey(id, account, key) {
var options = { account: account, accountKey: key };
return this._put('/wallet/' + id + '/key', options);
return this._put('/wallet/' + id + '/shared-key', options);
};
/**
* Remove a public account/purpose key to the wallet for multisig.
* @param {WalletID} id
* @param {(String|Number)?} account
* @param {HDPublicKey|Base58String} key - Account (bip44) or Purpose
* @param {Base58String} key - Account (bip44) or Purpose
* (bip45) key (can be in base58 form).
* @returns {Promise}
*/
HTTPClient.prototype.removeKey = function removeKey(id, account, key) {
HTTPClient.prototype.removeSharedKey = function removeSharedKey(id, account, key) {
var options = { account: account, accountKey: key };
return this._del('/wallet/' + id + '/key', options);
return this._del('/wallet/' + id + '/shared-key', options);
};
/**
@ -823,6 +847,17 @@ HTTPClient.prototype.getAccounts = function getAccounts(id) {
return this._get(path);
};
/**
* Get wallet master key.
* @param {WalletID} id
* @returns {Promise}
*/
HTTPClient.prototype.getMaster = function getMaster(id) {
var path = '/wallet/' + id + '/master';
return this._get(path);
};
/**
* Get wallet account.
* @param {WalletID} id

View File

@ -415,10 +415,10 @@ RPC.prototype.addnode = function addnode(args) {
}
break;
case 'onetry':
if (this.pool.peers.get(addr))
break;
peer = this.createPeer(addr);
this.peers.addPending(peer);
if (!this.pool.peers.get(addr)) {
peer = this.pool.createPeer(addr);
this.pool.peers.addPending(peer);
}
break;
}

View File

@ -756,6 +756,11 @@ HTTPServer.prototype._init = function _init() {
send(200, req.wallet.toJSON());
});
// Get wallet master key
this.get('/wallet/:id/master', function(req, res, send, next) {
send(200, req.wallet.master.toJSON(true));
});
// Create wallet
this.post('/wallet/:id?', con(function* (req, res, send, next) {
var wallet = yield this.walletdb.create(req.options);
@ -913,25 +918,58 @@ HTTPServer.prototype._init = function _init() {
}));
// Add key
this.put('/wallet/:id/key', con(function* (req, res, send, next) {
this.put('/wallet/:id/shared-key', con(function* (req, res, send, next) {
var options = req.options;
var acct = options.name || options.account;
var key = options.accountKey;
enforce(key, 'Key is required.');
yield req.wallet.addKey(acct, key);
yield req.wallet.addSharedKey(acct, key);
send(200, { success: true });
}));
// Remove key
this.del('/wallet/:id/key', con(function* (req, res, send, next) {
this.del('/wallet/:id/shared-key', con(function* (req, res, send, next) {
var options = req.options;
var acct = options.name || options.account;
var key = options.accountKey;
enforce(key, 'Key is required.');
yield req.wallet.removeKey(acct, key);
yield req.wallet.removeSharedKey(acct, key);
send(200, { success: true });
}));
// Get key by address
this.get('/wallet/:id/key/:address', con(function* (req, res, send, next) {
var options = req.options;
var address = options.address;
var key;
enforce(address instanceof Address, 'Address is required.');
key = yield req.wallet.getKey(address);
if (!key)
return send(404);
send(200, key.toJSON());
}));
// Get private key
this.get('/wallet/:id/wif/:address', con(function* (req, res, send, next) {
var options = req.options;
var address = options.address;
var passphrase = options.passphrase;
var key;
enforce(address instanceof Address, 'Address is required.');
key = yield req.wallet.getPrivateKey(address, passphrase);
if (!key)
return send(404);
send(200, { privateKey: key.toSecret() });
}));
// Create address
this.post('/wallet/:id/address', con(function* (req, res, send, next) {
var options = req.options;

View File

@ -105,7 +105,7 @@ HTTPWallet.prototype.open = co(function* open(options) {
wallet = yield this.client.getWallet(this.id);
yield this.client.join(this.id, wallet.token);
yield this.client.join(this.id, this.token);
return wallet;
});
@ -118,12 +118,18 @@ HTTPWallet.prototype.open = co(function* open(options) {
HTTPWallet.prototype.create = co(function* create(options) {
var wallet;
yield this.client.open();
wallet = yield this.client.createWallet(options);
return yield this.open({
id: wallet.id,
token: wallet.token
});
this.id = wallet.id;
this.token = wallet.token;
this.client.token = this.token;
yield this.client.join(this.id, this.token);
return wallet;
});
/**
@ -244,7 +250,7 @@ HTTPWallet.prototype.fillCoins = function fillCoins(tx) {
* @see HTTPClient#getWallet
*/
HTTPWallet.prototype.getInfo = function getInfo(callback) {
HTTPWallet.prototype.getInfo = function getInfo() {
return this.client.getWallet(this.id);
};
@ -252,10 +258,18 @@ HTTPWallet.prototype.getInfo = function getInfo(callback) {
* @see Wallet#getAccounts
*/
HTTPWallet.prototype.getAccounts = function getAccounts(callback) {
HTTPWallet.prototype.getAccounts = function getAccounts() {
return this.client.getAccounts(this.id);
};
/**
* @see Wallet#master
*/
HTTPWallet.prototype.getMaster = function getMaster() {
return this.client.getMaster(this.id);
};
/**
* @see Wallet#getAccount
*/
@ -393,6 +407,51 @@ HTTPWallet.prototype.unlock = function unlock(passphrase, timeout) {
return this.client.unlock(this.id, passphrase, timeout);
};
/**
* Get wallet key.
* @param {Base58Address} address
* @returns {Promise}
*/
HTTPWallet.prototype.getKey = function getKey(address) {
return this.client.getKey(this.id, address);
};
/**
* Get wallet key WIF dump.
* @param {Base58Address} address
* @param {String?} passphrase
* @returns {Promise}
*/
HTTPWallet.prototype.getWIF = function getWIF(address, passphrase) {
return this.client.getWIF(this.id, address, passphrase);
};
/**
* Add a public account/purpose key to the wallet for multisig.
* @param {(String|Number)?} account
* @param {Base58String} key - Account (bip44) or
* Purpose (bip45) key (can be in base58 form).
* @returns {Promise}
*/
HTTPWallet.prototype.addSharedKey = function addSharedKey(account, key) {
return this.client.addSharedKey(this.id, account, key);
};
/**
* Remove a public account/purpose key to the wallet for multisig.
* @param {(String|Number)?} account
* @param {Base58String} key - Account (bip44) or Purpose
* (bip45) key (can be in base58 form).
* @returns {Promise}
*/
HTTPWallet.prototype.removeSharedKey = function removeSharedKey(account, key) {
return this.client.removeSharedKey(this.id, account, key);
};
/**
* Resend wallet transactions.
* @returns {Promise}

View File

@ -334,7 +334,7 @@ Account.prototype.spliceKey = function spliceKey(key) {
* @returns {Promise}
*/
Account.prototype.addKey = co(function* addKey(key) {
Account.prototype.addSharedKey = co(function* addSharedKey(key) {
var result = false;
var exists;
@ -385,7 +385,7 @@ Account.prototype._checkKeys = co(function* _checkKeys() {
* @returns {Promise}
*/
Account.prototype.removeKey = function removeKey(key) {
Account.prototype.removeSharedKey = function removeSharedKey(key) {
var result = false;
try {
@ -780,54 +780,6 @@ Account.prototype.toJSON = function toJSON(minimal) {
};
};
/**
* Inject properties from json object.
* @private
* @param {Object} json
*/
Account.prototype.fromJSON = function fromJSON(json) {
var i, key;
assert(utils.isNumber(json.wid));
assert(utils.isName(json.id), 'Bad wallet ID.');
assert(utils.isName(json.name), 'Bad account name.');
assert(typeof json.initialized === 'boolean');
assert(typeof json.watchOnly === 'boolean');
assert(typeof json.type === 'string');
assert(utils.isNumber(json.m));
assert(utils.isNumber(json.n));
assert(typeof json.witness === 'boolean');
assert(utils.isNumber(json.accountIndex));
assert(utils.isNumber(json.receiveDepth));
assert(utils.isNumber(json.changeDepth));
assert(utils.isNumber(json.nestedDepth));
assert(Array.isArray(json.keys));
this.wid = json.wid;
this.name = json.name;
this.initialized = json.initialized;
this.witness = json.witness;
this.watchOnly = json.watchOnly;
this.type = Account.types[json.type.toUpperCase()];
this.m = json.m;
this.n = json.n;
this.accountIndex = json.accountIndex;
this.receiveDepth = json.receiveDepth;
this.changeDepth = json.changeDepth;
this.nestedDepth = json.nestedDepth;
this.accountKey = HD.fromBase58(json.accountKey);
assert(this.type != null);
for (i = 0; i < json.keys.length; i++) {
key = HD.fromBase58(json.keys[i]);
this.pushKey(key);
}
return this;
};
/**
* Serialize the account.
* @returns {Buffer}
@ -907,18 +859,6 @@ Account.fromRaw = function fromRaw(db, data) {
return new Account(db).fromRaw(data);
};
/**
* Instantiate a Account from a
* jsonified account object.
* @param {WalletDB} db
* @param {Object} json - The jsonified account object.
* @returns {Account}
*/
Account.fromJSON = function fromJSON(db, json) {
return new Account(db).fromJSON(json);
};
/**
* Test an object to see if it is a Account.
* @param {Object} obj

View File

@ -530,16 +530,18 @@ MasterKey.fromKey = function fromKey(key) {
/**
* Convert master key to a jsonifiable object.
* @param {Boolean?} unsafe - Whether to include
* the key data in the JSON.
* @returns {Object}
*/
MasterKey.prototype.toJSON = function toJSON() {
MasterKey.prototype.toJSON = function toJSON(unsafe) {
if (this.encrypted) {
return {
encrypted: true,
until: this.until,
iv: this.iv.toString('hex'),
ciphertext: this.ciphertext.toString('hex'),
ciphertext: unsafe ? this.ciphertext.toString('hex') : undefined,
algorithm: MasterKey.algByVal[this.alg],
N: this.N,
r: this.r,
@ -549,59 +551,17 @@ MasterKey.prototype.toJSON = function toJSON() {
return {
encrypted: false,
key: this.key.toJSON()
key: unsafe ? this.key.toJSON() : undefined
};
};
/**
* Inject properties from JSON object.
* @private
* @param {Object} json
*/
MasterKey.prototype.fromJSON = function fromJSON(json) {
assert(typeof json.encrypted === 'boolean');
this.encrypted = json.encrypted;
if (json.encrypted) {
assert(typeof json.iv === 'string');
assert(typeof json.ciphertext === 'string');
assert(typeof json.algorithm === 'string');
assert(utils.isNumber(json.N));
assert(utils.isNumber(json.r));
assert(utils.isNumber(json.p));
this.iv = new Buffer(json.iv, 'hex');
this.ciphertext = new Buffer(json.ciphertext, 'hex');
this.alg = MasterKey.alg[json.algorithm];
assert(this.alg != null);
this.N = json.N;
this.r = json.r;
this.p = json.p;
} else {
this.key = HD.fromJSON(json.key);
}
return this;
};
/**
* Instantiate master key from jsonified object.
* @param {Object} json
* @returns {MasterKey}
*/
MasterKey.fromJSON = function fromJSON(json) {
return new MasterKey().fromJSON(json);
};
/**
* Inspect the key.
* @returns {Object}
*/
MasterKey.prototype.inspect = function inspect() {
var json = this.toJSON();
var json = this.toJSON(true);
if (this.key)
json.key = this.key.toJSON();
return json;

View File

@ -254,10 +254,10 @@ Wallet.prototype.destroy = co(function* destroy() {
* @returns {Promise}
*/
Wallet.prototype.addKey = co(function* addKey(acct, key) {
Wallet.prototype.addSharedKey = co(function* addSharedKey(acct, key) {
var unlock = yield this.writeLock.lock();
try {
return yield this._addKey(acct, key);
return yield this._addSharedKey(acct, key);
} finally {
unlock();
}
@ -271,7 +271,7 @@ Wallet.prototype.addKey = co(function* addKey(acct, key) {
* @returns {Promise}
*/
Wallet.prototype._addKey = co(function* addKey(acct, key) {
Wallet.prototype._addSharedKey = co(function* addSharedKey(acct, key) {
var account, result;
if (!key) {
@ -290,7 +290,7 @@ Wallet.prototype._addKey = co(function* addKey(acct, key) {
this.start();
try {
result = yield account.addKey(key);
result = yield account.addSharedKey(key);
} catch (e) {
this.drop();
throw e;
@ -308,10 +308,10 @@ Wallet.prototype._addKey = co(function* addKey(acct, key) {
* @returns {Promise}
*/
Wallet.prototype.removeKey = co(function* removeKey(acct, key) {
Wallet.prototype.removeSharedKey = co(function* removeSharedKey(acct, key) {
var unlock = yield this.writeLock.lock();
try {
return yield this._removeKey(acct, key);
return yield this._removeSharedKey(acct, key);
} finally {
unlock();
}
@ -325,7 +325,7 @@ Wallet.prototype.removeKey = co(function* removeKey(acct, key) {
* @returns {Promise}
*/
Wallet.prototype._removeKey = co(function* removeKey(acct, key) {
Wallet.prototype._removeSharedKey = co(function* removeSharedKey(acct, key) {
var account, result;
if (!key) {
@ -344,7 +344,7 @@ Wallet.prototype._removeKey = co(function* removeKey(acct, key) {
this.start();
try {
result = yield account.removeKey(key);
result = yield account.removeSharedKey(key);
} catch (e) {
this.drop();
throw e;
@ -1649,6 +1649,36 @@ Wallet.prototype.getKey = co(function* getKey(address) {
return account.derivePath(path, this.master);
});
/**
* Retrieve a single keyring by address
* (with the private key reference).
* @param {Address|Hash} hash
* @param {(Buffer|String)?} passphrase
* @returns {Promise}
*/
Wallet.prototype.getPrivateKey = co(function* getPrivateKey(address, passphrase) {
var hash = Address.getHash(address, 'hex');
var path, account;
if (!hash)
return;
path = yield this.getPath(hash);
if (!path)
return;
account = yield this.getAccount(path.account);
if (!account)
return;
yield this.unlock(passphrase);
return account.derivePath(path, this.master);
});
/**
* Map input addresses to paths.
* @param {TX} tx
@ -2457,12 +2487,13 @@ Wallet.prototype.inspect = function inspect() {
/**
* Convert the wallet to an object suitable for
* serialization. Will automatically encrypt the
* master key based on the `passphrase` option.
* serialization.
* @param {Boolean?} unsafe - Whether to include
* the master key in the JSON.
* @returns {Object}
*/
Wallet.prototype.toJSON = function toJSON() {
Wallet.prototype.toJSON = function toJSON(unsafe) {
return {
network: this.network.type,
wid: this.wid,
@ -2473,44 +2504,11 @@ Wallet.prototype.toJSON = function toJSON() {
token: this.token.toString('hex'),
tokenDepth: this.tokenDepth,
state: this.state.toJSON(true),
master: this.master.toJSON(),
account: this.account ? this.account.toJSON(true) : null
master: this.master.toJSON(unsafe),
account: this.account.toJSON(true)
};
};
/**
* Inject properties from json object.
* @private
* @param {Object} json
*/
Wallet.prototype.fromJSON = function fromJSON(json) {
var network;
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');
assert(json.token.length === 64);
assert(utils.isNumber(json.tokenDepth));
network = Network.get(json.network);
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.fromJSON(json.master);
assert(network === this.db.network, 'Wallet network mismatch.');
return this;
};
/**
* Serialize the wallet.
* @returns {Buffer}
@ -2571,17 +2569,6 @@ Wallet.fromRaw = function fromRaw(db, data) {
return new Wallet(db).fromRaw(data);
};
/**
* Instantiate a Wallet from a
* jsonified wallet object.
* @param {Object} json - The jsonified wallet object.
* @returns {Wallet}
*/
Wallet.fromJSON = function fromJSON(db, json) {
return new Wallet(db).fromJSON(json);
};
/**
* Test an object to see if it is a Wallet.
* @param {Object} obj

View File

@ -146,7 +146,7 @@ describe('HTTP', function() {
}));
it('should get a tx', cob(function* () {
var tx = yield wallet.getTX('default', hash);
var tx = yield wallet.getTX(hash);
assert(tx);
assert.equal(tx.hash, hash);
}));

View File

@ -170,7 +170,7 @@ describe('Wallet', function() {
k = bcoin.hd.fromMnemonic().deriveAccount44(0).hdPublicKey;
yield w.addKey(k);
yield w.addSharedKey(k);
keys = [
w.getPublicKey(),
@ -681,12 +681,12 @@ describe('Wallet', function() {
w3 = yield walletdb.create(options);
receive = yield walletdb.create();
yield w1.addKey(w2.accountKey);
yield w1.addKey(w3.accountKey);
yield w2.addKey(w1.accountKey);
yield w2.addKey(w3.accountKey);
yield w3.addKey(w1.accountKey);
yield w3.addKey(w2.accountKey);
yield w1.addSharedKey(w2.accountKey);
yield w1.addSharedKey(w3.accountKey);
yield w2.addSharedKey(w1.accountKey);
yield w2.addSharedKey(w3.accountKey);
yield w3.addSharedKey(w1.accountKey);
yield w3.addSharedKey(w2.accountKey);
// Our p2sh address
b58 = w1[rec].getAddress('base58');