wallet: use separate branch for nested addrs.
This commit is contained in:
parent
19c8959c1a
commit
960393a53f
9
bin/cli
9
bin/cli
@ -88,6 +88,12 @@ CLI.prototype.createAddress = co(function* createAddress() {
|
|||||||
this.log(addr);
|
this.log(addr);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
CLI.prototype.createNested = co(function* createNested() {
|
||||||
|
var account = this.argv[0];
|
||||||
|
var addr = yield this.wallet.createNested(account);
|
||||||
|
this.log(addr);
|
||||||
|
});
|
||||||
|
|
||||||
CLI.prototype.getAccounts = co(function* getAccounts() {
|
CLI.prototype.getAccounts = co(function* getAccounts() {
|
||||||
var accounts = yield this.wallet.getAccounts();
|
var accounts = yield this.wallet.getAccounts();
|
||||||
this.log(accounts);
|
this.log(accounts);
|
||||||
@ -343,6 +349,8 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
|
|||||||
return yield this.getAccount();
|
return yield this.getAccount();
|
||||||
case 'address':
|
case 'address':
|
||||||
return yield this.createAddress();
|
return yield this.createAddress();
|
||||||
|
case 'nested':
|
||||||
|
return yield this.createNested();
|
||||||
case 'retoken':
|
case 'retoken':
|
||||||
return yield this.retoken();
|
return yield this.retoken();
|
||||||
case 'sign':
|
case 'sign':
|
||||||
@ -370,6 +378,7 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
|
|||||||
this.log(' $ account create [account-name]: Create account.');
|
this.log(' $ account create [account-name]: Create account.');
|
||||||
this.log(' $ account get [account-name]: Get account details.');
|
this.log(' $ account get [account-name]: Get account details.');
|
||||||
this.log(' $ address: Derive new address.');
|
this.log(' $ address: Derive new address.');
|
||||||
|
this.log(' $ nested: Derive new nested address.');
|
||||||
this.log(' $ retoken: Create new api key.');
|
this.log(' $ retoken: Create new api key.');
|
||||||
this.log(' $ send [address] [value]: Send transaction.');
|
this.log(' $ send [address] [value]: Send transaction.');
|
||||||
this.log(' $ mktx [address] [value]: Create transaction.');
|
this.log(' $ mktx [address] [value]: Create transaction.');
|
||||||
|
|||||||
@ -756,6 +756,27 @@ HTTPClient.prototype.createAddress = function createAddress(id, options) {
|
|||||||
return this._post(path, options);
|
return this._post(path, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create address.
|
||||||
|
* @param {WalletID} id
|
||||||
|
* @param {Object} options
|
||||||
|
* @returns {Promise} - Returns Array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
HTTPClient.prototype.createNested = function createNested(id, options) {
|
||||||
|
var path;
|
||||||
|
|
||||||
|
if (!options)
|
||||||
|
options = {};
|
||||||
|
|
||||||
|
if (typeof options === 'string')
|
||||||
|
options = { account: options };
|
||||||
|
|
||||||
|
path = '/wallet/' + id + '/nested';
|
||||||
|
|
||||||
|
return this._post(path, options);
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helpers
|
* Helpers
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -714,6 +714,13 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
send(200, address.toJSON());
|
send(200, address.toJSON());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Create nested address
|
||||||
|
this.post('/wallet/:id/nested', con(function *(req, res, send, next) {
|
||||||
|
var account = req.options.account;
|
||||||
|
var address = yield req.wallet.createNested(account);
|
||||||
|
send(200, address.toJSON());
|
||||||
|
}));
|
||||||
|
|
||||||
// Wallet Balance
|
// Wallet Balance
|
||||||
this.get('/wallet/:id/balance', con(function *(req, res, send, next) {
|
this.get('/wallet/:id/balance', con(function *(req, res, send, next) {
|
||||||
var account = req.options.account;
|
var account = req.options.account;
|
||||||
|
|||||||
@ -281,6 +281,14 @@ HTTPWallet.prototype.createAddress = function createAddress(account) {
|
|||||||
return this.client.createAddress(this.id, account);
|
return this.client.createAddress(this.id, account);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Wallet#createAddress
|
||||||
|
*/
|
||||||
|
|
||||||
|
HTTPWallet.prototype.createNested = function createNested(account) {
|
||||||
|
return this.client.createNested(this.id, account);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Wallet#setPassphrase
|
* @see Wallet#setPassphrase
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -37,6 +37,7 @@ function KeyRing(options, network) {
|
|||||||
|
|
||||||
this.network = bcoin.network.get();
|
this.network = bcoin.network.get();
|
||||||
this.witness = false;
|
this.witness = false;
|
||||||
|
this.nested = false;
|
||||||
this.publicKey = constants.ZERO_KEY;
|
this.publicKey = constants.ZERO_KEY;
|
||||||
this.privateKey = null;
|
this.privateKey = null;
|
||||||
this.script = null;
|
this.script = null;
|
||||||
@ -82,6 +83,11 @@ KeyRing.prototype.fromOptions = function fromOptions(options, network) {
|
|||||||
this.witness = options.witness;
|
this.witness = options.witness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.nested != null) {
|
||||||
|
assert(typeof options.nested === 'boolean');
|
||||||
|
this.nested = options.nested;
|
||||||
|
}
|
||||||
|
|
||||||
if (script)
|
if (script)
|
||||||
return this.fromScript(key, script, compressed, network);
|
return this.fromScript(key, script, compressed, network);
|
||||||
|
|
||||||
@ -572,6 +578,8 @@ KeyRing.prototype.compile = function compile(hash, type, version) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
KeyRing.prototype.getHash = function getHash(enc) {
|
KeyRing.prototype.getHash = function getHash(enc) {
|
||||||
|
if (this.nested)
|
||||||
|
return this.getNestedHash(enc);
|
||||||
if (this.script)
|
if (this.script)
|
||||||
return this.getScriptHash(enc);
|
return this.getScriptHash(enc);
|
||||||
return this.getKeyHash(enc);
|
return this.getKeyHash(enc);
|
||||||
@ -584,6 +592,8 @@ KeyRing.prototype.getHash = function getHash(enc) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
KeyRing.prototype.getAddress = function getAddress(enc) {
|
KeyRing.prototype.getAddress = function getAddress(enc) {
|
||||||
|
if (this.nested)
|
||||||
|
return this.getNestedAddress(enc);
|
||||||
if (this.script)
|
if (this.script)
|
||||||
return this.getScriptAddress(enc);
|
return this.getScriptAddress(enc);
|
||||||
return this.getKeyAddress(enc);
|
return this.getKeyAddress(enc);
|
||||||
@ -704,14 +714,14 @@ KeyRing.prototype.verify = function verify(msg, sig) {
|
|||||||
* @returns {ScriptType}
|
* @returns {ScriptType}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
KeyRing.prototype.getType = function getType() {
|
KeyRing.prototype.getVersion = function getVersion() {
|
||||||
if (this.program)
|
if (!this.witness)
|
||||||
return this.program.getType();
|
return -1;
|
||||||
|
|
||||||
if (this.script)
|
if (this.nested)
|
||||||
return this.script.getType();
|
return -1;
|
||||||
|
|
||||||
return scriptTypes.PUBKEYHASH;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -719,14 +729,19 @@ KeyRing.prototype.getType = function getType() {
|
|||||||
* @returns {ScriptType}
|
* @returns {ScriptType}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
KeyRing.prototype.getAddressType = function getAddressType() {
|
KeyRing.prototype.getType = function getType() {
|
||||||
|
if (this.nested)
|
||||||
|
return scriptTypes.SCRIPTHASH;
|
||||||
|
|
||||||
if (this.witness) {
|
if (this.witness) {
|
||||||
if (this.script)
|
if (this.script)
|
||||||
return scriptTypes.WITNESSSCRIPTHASH;
|
return scriptTypes.WITNESSSCRIPTHASH;
|
||||||
return scriptTypes.WITNESSPUBKEYHASH;
|
return scriptTypes.WITNESSPUBKEYHASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.script)
|
if (this.script)
|
||||||
return scriptTypes.SCRIPTHASH;
|
return scriptTypes.SCRIPTHASH;
|
||||||
|
|
||||||
return scriptTypes.PUBKEYHASH;
|
return scriptTypes.PUBKEYHASH;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -738,6 +753,10 @@ KeyRing.prototype.__defineGetter__('type', function() {
|
|||||||
return this.getType();
|
return this.getType();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
KeyRing.prototype.__defineGetter__('version', function() {
|
||||||
|
return this.getVersion();
|
||||||
|
});
|
||||||
|
|
||||||
KeyRing.prototype.__defineGetter__('scriptHash', function() {
|
KeyRing.prototype.__defineGetter__('scriptHash', function() {
|
||||||
return this.getScriptHash();
|
return this.getScriptHash();
|
||||||
});
|
});
|
||||||
@ -800,11 +819,12 @@ KeyRing.prototype.toJSON = function toJSON() {
|
|||||||
return {
|
return {
|
||||||
network: this.network.type,
|
network: this.network.type,
|
||||||
witness: this.witness,
|
witness: this.witness,
|
||||||
|
nested: this.nested,
|
||||||
publicKey: this.publicKey.toString('hex'),
|
publicKey: this.publicKey.toString('hex'),
|
||||||
script: this.script ? this.script.toRaw().toString('hex') : null,
|
script: this.script ? this.script.toRaw().toString('hex') : null,
|
||||||
|
program: this.program ? this.program.toRaw().toString('hex') : null,
|
||||||
type: constants.scriptTypesByVal[this.type].toLowerCase(),
|
type: constants.scriptTypesByVal[this.type].toLowerCase(),
|
||||||
address: this.getAddress('base58'),
|
address: this.getAddress('base58')
|
||||||
nestedAddress: this.getNestedAddress('base58')
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -818,11 +838,13 @@ KeyRing.prototype.fromJSON = function fromJSON(json) {
|
|||||||
assert(json);
|
assert(json);
|
||||||
assert(typeof json.network === 'string');
|
assert(typeof json.network === 'string');
|
||||||
assert(typeof json.witness === 'boolean');
|
assert(typeof json.witness === 'boolean');
|
||||||
|
assert(typeof json.nested === 'boolean');
|
||||||
assert(typeof json.publicKey === 'string');
|
assert(typeof json.publicKey === 'string');
|
||||||
assert(!json.script || typeof json.script === 'string');
|
assert(!json.script || typeof json.script === 'string');
|
||||||
|
|
||||||
this.nework = bcoin.network.get(json.network);
|
this.nework = bcoin.network.get(json.network);
|
||||||
this.witness = json.witness;
|
this.witness = json.witness;
|
||||||
|
this.nested = json.nested;
|
||||||
this.publicKey = new Buffer(json.publicKey, 'hex');
|
this.publicKey = new Buffer(json.publicKey, 'hex');
|
||||||
|
|
||||||
if (json.script)
|
if (json.script)
|
||||||
@ -850,6 +872,7 @@ KeyRing.prototype.toRaw = function toRaw(writer) {
|
|||||||
var p = new BufferWriter(writer);
|
var p = new BufferWriter(writer);
|
||||||
|
|
||||||
p.writeU8(this.witness ? 1 : 0);
|
p.writeU8(this.witness ? 1 : 0);
|
||||||
|
p.writeU8(this.nested ? 1 : 0);
|
||||||
|
|
||||||
if (this.privateKey) {
|
if (this.privateKey) {
|
||||||
p.writeVarBytes(this.privateKey);
|
p.writeVarBytes(this.privateKey);
|
||||||
@ -881,6 +904,7 @@ KeyRing.prototype.fromRaw = function fromRaw(data, network) {
|
|||||||
|
|
||||||
this.network = bcoin.network.get(network);
|
this.network = bcoin.network.get(network);
|
||||||
this.witness = p.readU8() === 1;
|
this.witness = p.readU8() === 1;
|
||||||
|
this.nested = p.readU8() === 1;
|
||||||
|
|
||||||
key = p.readVarBytes();
|
key = p.readVarBytes();
|
||||||
|
|
||||||
|
|||||||
@ -2344,7 +2344,9 @@ utils.isName = function isName(key) {
|
|||||||
if (typeof key !== 'string')
|
if (typeof key !== 'string')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Maximum worst case size: 80 bytes
|
if (!/^[\-\._0-9A-Za-z]+$/.test(key))
|
||||||
|
return false;
|
||||||
|
|
||||||
return key.length >= 1 && key.length <= 40;
|
return key.length >= 1 && key.length <= 40;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ var BufferWriter = require('../utils/writer');
|
|||||||
var Path = require('./path');
|
var Path = require('./path');
|
||||||
var Script = require('../script/script');
|
var Script = require('../script/script');
|
||||||
var WalletKey = require('./walletkey');
|
var WalletKey = require('./walletkey');
|
||||||
|
var HD = require('../hd/hd');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a BIP44 Account belonging to a {@link Wallet}.
|
* Represents a BIP44 Account belonging to a {@link Wallet}.
|
||||||
@ -53,6 +54,7 @@ function Account(db, options) {
|
|||||||
|
|
||||||
this.receive = null;
|
this.receive = null;
|
||||||
this.change = null;
|
this.change = null;
|
||||||
|
this.nested = null;
|
||||||
|
|
||||||
this.wid = 0;
|
this.wid = 0;
|
||||||
this.id = null;
|
this.id = null;
|
||||||
@ -62,6 +64,7 @@ function Account(db, options) {
|
|||||||
this.accountIndex = 0;
|
this.accountIndex = 0;
|
||||||
this.receiveDepth = 0;
|
this.receiveDepth = 0;
|
||||||
this.changeDepth = 0;
|
this.changeDepth = 0;
|
||||||
|
this.nestedDepth = 0;
|
||||||
this.type = Account.types.PUBKEYHASH;
|
this.type = Account.types.PUBKEYHASH;
|
||||||
this.m = 1;
|
this.m = 1;
|
||||||
this.n = 1;
|
this.n = 1;
|
||||||
@ -105,7 +108,7 @@ Account.prototype.fromOptions = function fromOptions(options) {
|
|||||||
assert(options, 'Options are required.');
|
assert(options, 'Options are required.');
|
||||||
assert(utils.isNumber(options.wid));
|
assert(utils.isNumber(options.wid));
|
||||||
assert(utils.isName(options.id), 'Bad Wallet ID.');
|
assert(utils.isName(options.id), 'Bad Wallet ID.');
|
||||||
assert(bcoin.hd.isHD(options.accountKey), 'Account key is required.');
|
assert(HD.isHD(options.accountKey), 'Account key is required.');
|
||||||
assert(utils.isNumber(options.accountIndex), 'Account index is required.');
|
assert(utils.isNumber(options.accountIndex), 'Account index is required.');
|
||||||
|
|
||||||
this.wid = options.wid;
|
this.wid = options.wid;
|
||||||
@ -138,6 +141,11 @@ Account.prototype.fromOptions = function fromOptions(options) {
|
|||||||
this.changeDepth = options.changeDepth;
|
this.changeDepth = options.changeDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.nestedDepth != null) {
|
||||||
|
assert(utils.isNumber(options.nestedDepth));
|
||||||
|
this.nestedDepth = options.nestedDepth;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.type != null) {
|
if (options.type != null) {
|
||||||
if (typeof options.type === 'string') {
|
if (typeof options.type === 'string') {
|
||||||
this.type = Account.types[options.type.toUpperCase()];
|
this.type = Account.types[options.type.toUpperCase()];
|
||||||
@ -218,9 +226,10 @@ Account.prototype.init = co(function* init() {
|
|||||||
|
|
||||||
assert(this.receiveDepth === 0);
|
assert(this.receiveDepth === 0);
|
||||||
assert(this.changeDepth === 0);
|
assert(this.changeDepth === 0);
|
||||||
|
assert(this.nestedDepth === 0);
|
||||||
|
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
yield this.setDepth(1, 1);
|
yield this.setDepth(1, 1, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -235,6 +244,9 @@ Account.prototype.open = function open() {
|
|||||||
this.receive = this.deriveReceive(this.receiveDepth - 1);
|
this.receive = this.deriveReceive(this.receiveDepth - 1);
|
||||||
this.change = this.deriveChange(this.changeDepth - 1);
|
this.change = this.deriveChange(this.changeDepth - 1);
|
||||||
|
|
||||||
|
if (this.witness)
|
||||||
|
this.nested = this.deriveReceive(this.nestedDepth - 1);
|
||||||
|
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -249,10 +261,10 @@ Account.prototype.open = function open() {
|
|||||||
Account.prototype.pushKey = function pushKey(key) {
|
Account.prototype.pushKey = function pushKey(key) {
|
||||||
var index;
|
var index;
|
||||||
|
|
||||||
if (bcoin.hd.isExtended(key))
|
if (HD.isExtended(key))
|
||||||
key = bcoin.hd.fromBase58(key);
|
key = HD.fromBase58(key);
|
||||||
|
|
||||||
if (!bcoin.hd.isPublic(key))
|
if (!HD.isPublic(key))
|
||||||
throw new Error('Must add HD keys to wallet.');
|
throw new Error('Must add HD keys to wallet.');
|
||||||
|
|
||||||
if (!key.isAccount44())
|
if (!key.isAccount44())
|
||||||
@ -283,10 +295,10 @@ Account.prototype.pushKey = function pushKey(key) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.spliceKey = function spliceKey(key) {
|
Account.prototype.spliceKey = function spliceKey(key) {
|
||||||
if (bcoin.hd.isExtended(key))
|
if (HD.isExtended(key))
|
||||||
key = bcoin.hd.fromBase58(key);
|
key = HD.fromBase58(key);
|
||||||
|
|
||||||
if (!bcoin.hd.isHDPublicKey(key))
|
if (!HD.isHDPublicKey(key))
|
||||||
throw new Error('Must add HD keys to wallet.');
|
throw new Error('Must add HD keys to wallet.');
|
||||||
|
|
||||||
if (!key.isAccount44())
|
if (!key.isAccount44())
|
||||||
@ -379,7 +391,7 @@ Account.prototype.removeKey = function removeKey(key) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.createReceive = function createReceive() {
|
Account.prototype.createReceive = function createReceive() {
|
||||||
return this.createKey(false);
|
return this.createKey(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -388,7 +400,16 @@ Account.prototype.createReceive = function createReceive() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.createChange = function createChange() {
|
Account.prototype.createChange = function createChange() {
|
||||||
return this.createKey(true);
|
return this.createKey(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new change address (increments receiveDepth).
|
||||||
|
* @returns {WalletKey}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Account.prototype.createNested = function createNested() {
|
||||||
|
return this.createKey(2);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -397,23 +418,36 @@ Account.prototype.createChange = function createChange() {
|
|||||||
* @returns {Promise} - Returns {@link WalletKey}.
|
* @returns {Promise} - Returns {@link WalletKey}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.createKey = co(function* createKey(change) {
|
Account.prototype.createKey = co(function* createKey(branch) {
|
||||||
var ring, lookahead;
|
var ring, lookahead;
|
||||||
|
|
||||||
if (change) {
|
switch (branch) {
|
||||||
ring = this.deriveChange(this.changeDepth);
|
case 0:
|
||||||
lookahead = this.deriveChange(this.changeDepth + this.lookahead);
|
ring = this.deriveReceive(this.receiveDepth);
|
||||||
yield this.saveKey(ring);
|
lookahead = this.deriveReceive(this.receiveDepth + this.lookahead);
|
||||||
yield this.saveKey(lookahead);
|
yield this.saveKey(ring);
|
||||||
this.changeDepth++;
|
yield this.saveKey(lookahead);
|
||||||
this.change = ring;
|
this.receiveDepth++;
|
||||||
} else {
|
this.receive = ring;
|
||||||
ring = this.deriveReceive(this.receiveDepth);
|
break;
|
||||||
lookahead = this.deriveReceive(this.receiveDepth + this.lookahead);
|
case 1:
|
||||||
yield this.saveKey(ring);
|
ring = this.deriveChange(this.changeDepth);
|
||||||
yield this.saveKey(lookahead);
|
lookahead = this.deriveChange(this.changeDepth + this.lookahead);
|
||||||
this.receiveDepth++;
|
yield this.saveKey(ring);
|
||||||
this.receive = ring;
|
yield this.saveKey(lookahead);
|
||||||
|
this.changeDepth++;
|
||||||
|
this.change = ring;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ring = this.deriveNested(this.nestedDepth);
|
||||||
|
lookahead = this.deriveNested(this.nestedDepth + this.lookahead);
|
||||||
|
yield this.saveKey(ring);
|
||||||
|
yield this.saveKey(lookahead);
|
||||||
|
this.nestedDepth++;
|
||||||
|
this.nested = ring;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Bad branch: ' + branch);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save();
|
this.save();
|
||||||
@ -428,7 +462,7 @@ Account.prototype.createKey = co(function* createKey(change) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.deriveReceive = function deriveReceive(index, master) {
|
Account.prototype.deriveReceive = function deriveReceive(index, master) {
|
||||||
return this.deriveKey(false, index, master);
|
return this.deriveKey(0, index, master);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -438,7 +472,20 @@ Account.prototype.deriveReceive = function deriveReceive(index, master) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.deriveChange = function deriveChange(index, master) {
|
Account.prototype.deriveChange = function deriveChange(index, master) {
|
||||||
return this.deriveKey(true, index, master);
|
return this.deriveKey(1, index, master);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive a nested address at `index`. Do not increment depth.
|
||||||
|
* @param {Number} index
|
||||||
|
* @returns {WalletKey}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Account.prototype.deriveNested = function deriveNested(index, master) {
|
||||||
|
if (!this.witness)
|
||||||
|
throw new Error('Cannot derive nested on non-witness account.');
|
||||||
|
|
||||||
|
return this.deriveKey(2, index, master);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -485,7 +532,7 @@ Account.prototype.deriveKey = function deriveKey(branch, index, master) {
|
|||||||
var keys = [];
|
var keys = [];
|
||||||
var i, key, shared, ring, hash;
|
var i, key, shared, ring, hash;
|
||||||
|
|
||||||
branch = +branch;
|
assert(typeof branch === 'number');
|
||||||
|
|
||||||
if (master && master.key) {
|
if (master && master.key) {
|
||||||
key = master.key.deriveAccount44(this.accountIndex);
|
key = master.key.deriveAccount44(this.accountIndex);
|
||||||
@ -516,22 +563,6 @@ Account.prototype.deriveKey = function deriveKey(branch, index, master) {
|
|||||||
return ring;
|
return ring;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Get address type.
|
|
||||||
* @returns {ScriptType}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Account.prototype.getAddressType = function getAddressType() {
|
|
||||||
if (this.witness) {
|
|
||||||
if (this.type === Account.types.MULTISIG)
|
|
||||||
return Script.types.WITNESSSCRIPTHASH;
|
|
||||||
return Script.types.WITNESSPUBKEYHASH;
|
|
||||||
}
|
|
||||||
if (this.type === Account.types.MULTISIG)
|
|
||||||
return Script.types.SCRIPTHASH;
|
|
||||||
return Script.types.PUBKEYHASH;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the account to the database. Necessary
|
* Save the account to the database. Necessary
|
||||||
* when address depth and keys change.
|
* when address depth and keys change.
|
||||||
@ -570,9 +601,9 @@ Account.prototype.savePath = function savePath(path) {
|
|||||||
* @returns {Promise} - Returns {@link WalletKey}, {@link WalletKey}.
|
* @returns {Promise} - Returns {@link WalletKey}, {@link WalletKey}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.setDepth = co(function* setDepth(receiveDepth, changeDepth) {
|
Account.prototype.setDepth = co(function* setDepth(receiveDepth, changeDepth, nestedDepth) {
|
||||||
var i = -1;
|
var i = -1;
|
||||||
var receive, change, lookahead;
|
var receive, change, nested, lookahead;
|
||||||
|
|
||||||
if (receiveDepth > this.receiveDepth) {
|
if (receiveDepth > this.receiveDepth) {
|
||||||
for (i = this.receiveDepth; i < receiveDepth; i++) {
|
for (i = this.receiveDepth; i < receiveDepth; i++) {
|
||||||
@ -604,12 +635,27 @@ Account.prototype.setDepth = co(function* setDepth(receiveDepth, changeDepth) {
|
|||||||
this.changeDepth = changeDepth;
|
this.changeDepth = changeDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.witness && nestedDepth > this.nestedDepth) {
|
||||||
|
for (i = this.nestedDepth; i < nestedDepth; i++) {
|
||||||
|
nested = this.deriveNested(i);
|
||||||
|
yield this.saveKey(nested);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = nestedDepth; i < nestedDepth + this.lookahead; i++) {
|
||||||
|
lookahead = this.deriveNested(i);
|
||||||
|
yield this.saveKey(lookahead);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.nested = nested;
|
||||||
|
this.nestedDepth = nestedDepth;
|
||||||
|
}
|
||||||
|
|
||||||
if (i === -1)
|
if (i === -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.save();
|
this.save();
|
||||||
|
|
||||||
return receive;
|
return receive || nested;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -629,13 +675,14 @@ Account.prototype.inspect = function inspect() {
|
|||||||
address: this.initialized
|
address: this.initialized
|
||||||
? this.receive.getAddress()
|
? this.receive.getAddress()
|
||||||
: null,
|
: null,
|
||||||
nestedAddress: this.initialized
|
nestedAddress: this.initialized && this.nested
|
||||||
? this.receive.getNestedAddress()
|
? this.nested.getAddress()
|
||||||
: null,
|
: null,
|
||||||
witness: this.witness,
|
witness: this.witness,
|
||||||
accountIndex: this.accountIndex,
|
accountIndex: this.accountIndex,
|
||||||
receiveDepth: this.receiveDepth,
|
receiveDepth: this.receiveDepth,
|
||||||
changeDepth: this.changeDepth,
|
changeDepth: this.changeDepth,
|
||||||
|
nestedDepth: this.nestedDepth,
|
||||||
accountKey: this.accountKey.xpubkey,
|
accountKey: this.accountKey.xpubkey,
|
||||||
keys: this.keys.map(function(key) {
|
keys: this.keys.map(function(key) {
|
||||||
return key.xpubkey;
|
return key.xpubkey;
|
||||||
@ -662,11 +709,12 @@ Account.prototype.toJSON = function toJSON() {
|
|||||||
accountIndex: this.accountIndex,
|
accountIndex: this.accountIndex,
|
||||||
receiveDepth: this.receiveDepth,
|
receiveDepth: this.receiveDepth,
|
||||||
changeDepth: this.changeDepth,
|
changeDepth: this.changeDepth,
|
||||||
|
nestedDepth: this.nestedDepth,
|
||||||
receiveAddress: this.receive
|
receiveAddress: this.receive
|
||||||
? this.receive.getAddress('base58')
|
? this.receive.getAddress('base58')
|
||||||
: null,
|
: null,
|
||||||
nestedAddress: this.receive
|
nestedAddress: this.nested
|
||||||
? this.receive.getNestedAddress('base58')
|
? this.nested.getAddress('base58')
|
||||||
: null,
|
: null,
|
||||||
changeAddress: this.change
|
changeAddress: this.change
|
||||||
? this.change.getAddress('base58')
|
? this.change.getAddress('base58')
|
||||||
@ -699,6 +747,7 @@ Account.prototype.fromJSON = function fromJSON(json) {
|
|||||||
assert(utils.isNumber(json.accountIndex));
|
assert(utils.isNumber(json.accountIndex));
|
||||||
assert(utils.isNumber(json.receiveDepth));
|
assert(utils.isNumber(json.receiveDepth));
|
||||||
assert(utils.isNumber(json.changeDepth));
|
assert(utils.isNumber(json.changeDepth));
|
||||||
|
assert(utils.isNumber(json.nestedDepth));
|
||||||
assert(Array.isArray(json.keys));
|
assert(Array.isArray(json.keys));
|
||||||
|
|
||||||
this.wid = json.wid;
|
this.wid = json.wid;
|
||||||
@ -711,12 +760,13 @@ Account.prototype.fromJSON = function fromJSON(json) {
|
|||||||
this.accountIndex = json.accountIndex;
|
this.accountIndex = json.accountIndex;
|
||||||
this.receiveDepth = json.receiveDepth;
|
this.receiveDepth = json.receiveDepth;
|
||||||
this.changeDepth = json.changeDepth;
|
this.changeDepth = json.changeDepth;
|
||||||
this.accountKey = bcoin.hd.fromBase58(json.accountKey);
|
this.nestedDepth = json.nestedDepth;
|
||||||
|
this.accountKey = HD.fromBase58(json.accountKey);
|
||||||
|
|
||||||
assert(this.type != null);
|
assert(this.type != null);
|
||||||
|
|
||||||
for (i = 0; i < json.keys.length; i++) {
|
for (i = 0; i < json.keys.length; i++) {
|
||||||
key = bcoin.hd.fromBase58(json.keys[i]);
|
key = HD.fromBase58(json.keys[i]);
|
||||||
this.pushKey(key);
|
this.pushKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,7 +783,7 @@ Account.prototype.toRaw = function toRaw(writer) {
|
|||||||
var i, key;
|
var i, key;
|
||||||
|
|
||||||
p.writeU32(this.network.magic);
|
p.writeU32(this.network.magic);
|
||||||
p.writeVarString(this.name, 'utf8');
|
p.writeVarString(this.name, 'ascii');
|
||||||
p.writeU8(this.initialized ? 1 : 0);
|
p.writeU8(this.initialized ? 1 : 0);
|
||||||
p.writeU8(this.type);
|
p.writeU8(this.type);
|
||||||
p.writeU8(this.m);
|
p.writeU8(this.m);
|
||||||
@ -742,6 +792,7 @@ Account.prototype.toRaw = function toRaw(writer) {
|
|||||||
p.writeU32(this.accountIndex);
|
p.writeU32(this.accountIndex);
|
||||||
p.writeU32(this.receiveDepth);
|
p.writeU32(this.receiveDepth);
|
||||||
p.writeU32(this.changeDepth);
|
p.writeU32(this.changeDepth);
|
||||||
|
p.writeU32(this.nestedDepth);
|
||||||
p.writeBytes(this.accountKey.toRaw());
|
p.writeBytes(this.accountKey.toRaw());
|
||||||
p.writeU8(this.keys.length);
|
p.writeU8(this.keys.length);
|
||||||
|
|
||||||
@ -768,7 +819,7 @@ Account.prototype.fromRaw = function fromRaw(data) {
|
|||||||
var i, count, key;
|
var i, count, key;
|
||||||
|
|
||||||
this.network = bcoin.network.fromMagic(p.readU32());
|
this.network = bcoin.network.fromMagic(p.readU32());
|
||||||
this.name = p.readVarString('utf8');
|
this.name = p.readVarString('ascii');
|
||||||
this.initialized = p.readU8() === 1;
|
this.initialized = p.readU8() === 1;
|
||||||
this.type = p.readU8();
|
this.type = p.readU8();
|
||||||
this.m = p.readU8();
|
this.m = p.readU8();
|
||||||
@ -777,14 +828,15 @@ Account.prototype.fromRaw = function fromRaw(data) {
|
|||||||
this.accountIndex = p.readU32();
|
this.accountIndex = p.readU32();
|
||||||
this.receiveDepth = p.readU32();
|
this.receiveDepth = p.readU32();
|
||||||
this.changeDepth = p.readU32();
|
this.changeDepth = p.readU32();
|
||||||
this.accountKey = bcoin.hd.fromRaw(p.readBytes(82));
|
this.nestedDepth = p.readU32();
|
||||||
|
this.accountKey = HD.fromRaw(p.readBytes(82));
|
||||||
|
|
||||||
assert(Account.typesByVal[this.type]);
|
assert(Account.typesByVal[this.type]);
|
||||||
|
|
||||||
count = p.readU8();
|
count = p.readU8();
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
key = bcoin.hd.fromRaw(p.readBytes(82));
|
key = HD.fromRaw(p.readBytes(82));
|
||||||
this.pushKey(key);
|
this.pushKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,10 +9,11 @@
|
|||||||
var bcoin = require('../env');
|
var bcoin = require('../env');
|
||||||
var utils = require('../utils/utils');
|
var utils = require('../utils/utils');
|
||||||
var assert = utils.assert;
|
var assert = utils.assert;
|
||||||
var constants = bcoin.constants;
|
var constants = require('../protocol/constants');
|
||||||
var BufferReader = require('../utils/reader');
|
var BufferReader = require('../utils/reader');
|
||||||
var BufferWriter = require('../utils/writer');
|
var BufferWriter = require('../utils/writer');
|
||||||
var Address = require('../primitives/address');
|
var Address = require('../primitives/address');
|
||||||
|
var Script = require('../script/script');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path
|
* Path
|
||||||
@ -43,7 +44,7 @@ function Path() {
|
|||||||
this.data = null;
|
this.data = null;
|
||||||
|
|
||||||
// Currently unused.
|
// Currently unused.
|
||||||
this.type = bcoin.script.types.PUBKEYHASH;
|
this.type = Script.types.PUBKEYHASH;
|
||||||
this.version = -1;
|
this.version = -1;
|
||||||
this.hash = null; // Passed in by caller.
|
this.hash = null; // Passed in by caller.
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,15 +7,19 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var bcoin = require('../env');
|
|
||||||
var utils = require('../utils/utils');
|
var utils = require('../utils/utils');
|
||||||
|
var Locker = require('../utils/locker');
|
||||||
|
var LRU = require('../utils/lru');
|
||||||
var spawn = require('../utils/spawn');
|
var spawn = require('../utils/spawn');
|
||||||
var co = spawn.co;
|
var co = spawn.co;
|
||||||
var assert = bcoin.utils.assert;
|
var assert = utils.assert;
|
||||||
var constants = bcoin.constants;
|
var constants = require('../protocol/constants');
|
||||||
var DUMMY = new Buffer([0]);
|
|
||||||
var BufferReader = require('../utils/reader');
|
var BufferReader = require('../utils/reader');
|
||||||
var BufferWriter = require('../utils/writer');
|
var BufferWriter = require('../utils/writer');
|
||||||
|
var TX = require('../primitives/tx');
|
||||||
|
var Coin = require('../primitives/coin');
|
||||||
|
var Outpoint = require('../primitives/outpoint');
|
||||||
|
var DUMMY = new Buffer([0]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Database Layout:
|
* Database Layout:
|
||||||
@ -211,8 +215,8 @@ function TXDB(wallet) {
|
|||||||
this.options = wallet.db.options;
|
this.options = wallet.db.options;
|
||||||
this.locked = {};
|
this.locked = {};
|
||||||
|
|
||||||
this.locker = new bcoin.locker();
|
this.locker = new Locker();
|
||||||
this.coinCache = new bcoin.lru(10000);
|
this.coinCache = new LRU(10000);
|
||||||
|
|
||||||
this.current = null;
|
this.current = null;
|
||||||
this.balance = null;
|
this.balance = null;
|
||||||
@ -446,7 +450,7 @@ TXDB.prototype.getOrphans = co(function* getOrphans(hash, index) {
|
|||||||
inputs = [];
|
inputs = [];
|
||||||
|
|
||||||
while (p.left())
|
while (p.left())
|
||||||
inputs.push(bcoin.outpoint.fromRaw(p));
|
inputs.push(Outpoint.fromRaw(p));
|
||||||
|
|
||||||
for (i = 0; i < inputs.length; i++) {
|
for (i = 0; i < inputs.length; i++) {
|
||||||
input = inputs[i];
|
input = inputs[i];
|
||||||
@ -558,7 +562,7 @@ TXDB.prototype.resolveOrphans = co(function* resolveOrphans(tx, index) {
|
|||||||
|
|
||||||
this.del(layout.o(hash, index));
|
this.del(layout.o(hash, index));
|
||||||
|
|
||||||
coin = bcoin.coin.fromTX(tx, index);
|
coin = Coin.fromTX(tx, index);
|
||||||
|
|
||||||
// Add input to orphan
|
// Add input to orphan
|
||||||
for (i = 0; i < orphans.length; i++) {
|
for (i = 0; i < orphans.length; i++) {
|
||||||
@ -677,7 +681,7 @@ TXDB.prototype._add = co(function* add(tx, info) {
|
|||||||
key = prevout.hash + prevout.index;
|
key = prevout.hash + prevout.index;
|
||||||
|
|
||||||
// s[outpoint-key] -> [spender-hash]|[spender-input-index]
|
// s[outpoint-key] -> [spender-hash]|[spender-input-index]
|
||||||
spender = bcoin.outpoint.fromTX(tx, i).toRaw();
|
spender = Outpoint.fromTX(tx, i).toRaw();
|
||||||
this.put(layout.s(prevout.hash, prevout.index), spender);
|
this.put(layout.s(prevout.hash, prevout.index), spender);
|
||||||
|
|
||||||
// Add orphan, if no parent transaction is yet known
|
// Add orphan, if no parent transaction is yet known
|
||||||
@ -722,7 +726,7 @@ TXDB.prototype._add = co(function* add(tx, info) {
|
|||||||
if (orphans)
|
if (orphans)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
coin = bcoin.coin.fromTX(tx, i);
|
coin = Coin.fromTX(tx, i);
|
||||||
this.balance.add(coin);
|
this.balance.add(coin);
|
||||||
coin = coin.toRaw();
|
coin = coin.toRaw();
|
||||||
|
|
||||||
@ -873,7 +877,7 @@ TXDB.prototype.isSpent = co(function* isSpent(hash, index) {
|
|||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
return bcoin.outpoint.fromRaw(data);
|
return Outpoint.fromRaw(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1103,7 +1107,7 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
|
|||||||
if (!path)
|
if (!path)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
coin = bcoin.coin.fromTX(tx, i);
|
coin = Coin.fromTX(tx, i);
|
||||||
|
|
||||||
this.balance.sub(coin);
|
this.balance.sub(coin);
|
||||||
|
|
||||||
@ -1321,7 +1325,7 @@ TXDB.prototype.getLocked = function getLocked() {
|
|||||||
key = keys[i];
|
key = keys[i];
|
||||||
hash = key.slice(0, 64);
|
hash = key.slice(0, 64);
|
||||||
index = +key.slice(64);
|
index = +key.slice(64);
|
||||||
outpoint = new bcoin.outpoint(hash, index);
|
outpoint = new Outpoint(hash, index);
|
||||||
outpoints.push(outpoint);
|
outpoints.push(outpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1395,10 +1399,10 @@ TXDB.prototype.getOutpoints = function getOutpoints(account) {
|
|||||||
parse: function(key) {
|
parse: function(key) {
|
||||||
if (account != null) {
|
if (account != null) {
|
||||||
key = layout.Cc(key);
|
key = layout.Cc(key);
|
||||||
return new bcoin.outpoint(key[1], key[2]);
|
return new Outpoint(key[1], key[2]);
|
||||||
}
|
}
|
||||||
key = layout.cc(key);
|
key = layout.cc(key);
|
||||||
return new bcoin.outpoint(key[0], key[1]);
|
return new Outpoint(key[0], key[1]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -1563,7 +1567,7 @@ TXDB.prototype.getHistory = function getHistory(account) {
|
|||||||
return this.values({
|
return this.values({
|
||||||
gte: layout.t(constants.NULL_HASH),
|
gte: layout.t(constants.NULL_HASH),
|
||||||
lte: layout.t(constants.HIGH_HASH),
|
lte: layout.t(constants.HIGH_HASH),
|
||||||
parse: bcoin.tx.fromExtended
|
parse: TX.fromExtended
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1638,7 +1642,7 @@ TXDB.prototype.getCoins = function getCoins(account) {
|
|||||||
var parts = layout.cc(key);
|
var parts = layout.cc(key);
|
||||||
var hash = parts[0];
|
var hash = parts[0];
|
||||||
var index = parts[1];
|
var index = parts[1];
|
||||||
var coin = bcoin.coin.fromRaw(value);
|
var coin = Coin.fromRaw(value);
|
||||||
coin.hash = hash;
|
coin.hash = hash;
|
||||||
coin.index = index;
|
coin.index = index;
|
||||||
key = hash + index;
|
key = hash + index;
|
||||||
@ -1691,7 +1695,7 @@ TXDB.prototype.fillHistory = function fillHistory(tx) {
|
|||||||
lte: layout.d(hash, 0xffffffff),
|
lte: layout.d(hash, 0xffffffff),
|
||||||
parse: function(key, value) {
|
parse: function(key, value) {
|
||||||
var index = layout.dd(key)[1];
|
var index = layout.dd(key)[1];
|
||||||
var coin = bcoin.coin.fromRaw(value);
|
var coin = Coin.fromRaw(value);
|
||||||
var input = tx.inputs[index];
|
var input = tx.inputs[index];
|
||||||
coin.hash = input.prevout.hash;
|
coin.hash = input.prevout.hash;
|
||||||
coin.index = input.prevout.index;
|
coin.index = input.prevout.index;
|
||||||
@ -1740,7 +1744,7 @@ TXDB.prototype.getTX = co(function* getTX(hash) {
|
|||||||
if (!tx)
|
if (!tx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
return bcoin.tx.fromExtended(tx);
|
return TX.fromExtended(tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1817,7 +1821,7 @@ TXDB.prototype.getCoin = co(function* getCoin(hash, index) {
|
|||||||
var coin;
|
var coin;
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
coin = bcoin.coin.fromRaw(data);
|
coin = Coin.fromRaw(data);
|
||||||
coin.hash = hash;
|
coin.hash = hash;
|
||||||
coin.index = index;
|
coin.index = index;
|
||||||
return coin;
|
return coin;
|
||||||
@ -1828,7 +1832,7 @@ TXDB.prototype.getCoin = co(function* getCoin(hash, index) {
|
|||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
coin = bcoin.coin.fromRaw(data);
|
coin = Coin.fromRaw(data);
|
||||||
coin.hash = hash;
|
coin.hash = hash;
|
||||||
coin.index = index;
|
coin.index = index;
|
||||||
|
|
||||||
@ -1851,7 +1855,7 @@ TXDB.prototype.getSpentCoin = co(function* getSpentCoin(spent, prevout) {
|
|||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
coin = bcoin.coin.fromRaw(data);
|
coin = Coin.fromRaw(data);
|
||||||
coin.hash = prevout.hash;
|
coin.hash = prevout.hash;
|
||||||
coin.index = prevout.index;
|
coin.index = prevout.index;
|
||||||
|
|
||||||
@ -1866,7 +1870,7 @@ TXDB.prototype.getSpentCoin = co(function* getSpentCoin(spent, prevout) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.updateSpentCoin = co(function* updateSpentCoin(tx, i) {
|
TXDB.prototype.updateSpentCoin = co(function* updateSpentCoin(tx, i) {
|
||||||
var prevout = bcoin.outpoint.fromTX(tx, i);
|
var prevout = Outpoint.fromTX(tx, i);
|
||||||
var spent = yield this.isSpent(prevout.hash, prevout.index);
|
var spent = yield this.isSpent(prevout.hash, prevout.index);
|
||||||
var coin;
|
var coin;
|
||||||
|
|
||||||
@ -2002,7 +2006,7 @@ TXDB.prototype._zap = co(function* zap(account, age) {
|
|||||||
|
|
||||||
txs = yield this.getRange(account, {
|
txs = yield this.getRange(account, {
|
||||||
start: 0,
|
start: 0,
|
||||||
end: bcoin.now() - age
|
end: utils.now() - age
|
||||||
});
|
});
|
||||||
|
|
||||||
for (i = 0; i < txs.length; i++) {
|
for (i = 0; i < txs.length; i++) {
|
||||||
|
|||||||
@ -9,8 +9,9 @@
|
|||||||
|
|
||||||
var bcoin = require('../env');
|
var bcoin = require('../env');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var constants = bcoin.constants;
|
var constants = require('../protocol/constants');
|
||||||
var utils = require('../utils/utils');
|
var utils = require('../utils/utils');
|
||||||
|
var Locker = require('../utils/locker');
|
||||||
var spawn = require('../utils/spawn');
|
var spawn = require('../utils/spawn');
|
||||||
var co = spawn.co;
|
var co = spawn.co;
|
||||||
var crypto = require('../crypto/crypto');
|
var crypto = require('../crypto/crypto');
|
||||||
@ -20,7 +21,12 @@ var BufferWriter = require('../utils/writer');
|
|||||||
var TXDB = require('./txdb');
|
var TXDB = require('./txdb');
|
||||||
var Path = require('./path');
|
var Path = require('./path');
|
||||||
var Address = require('../primitives/address');
|
var Address = require('../primitives/address');
|
||||||
|
var MTX = require('../primitives/mtx');
|
||||||
var WalletKey = require('./walletkey');
|
var WalletKey = require('./walletkey');
|
||||||
|
var HD = require('../hd/hd');
|
||||||
|
var Account = require('./account');
|
||||||
|
var Input = require('../primitives/input');
|
||||||
|
var Output = require('../primitives/output');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BIP44 Wallet
|
* BIP44 Wallet
|
||||||
@ -58,8 +64,8 @@ function Wallet(db, options) {
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
this.network = db.network;
|
this.network = db.network;
|
||||||
this.logger = db.logger;
|
this.logger = db.logger;
|
||||||
this.writeLock = new bcoin.locker();
|
this.writeLock = new Locker();
|
||||||
this.fundLock = new bcoin.locker();
|
this.fundLock = new Locker();
|
||||||
|
|
||||||
this.wid = 0;
|
this.wid = 0;
|
||||||
this.id = null;
|
this.id = null;
|
||||||
@ -89,12 +95,12 @@ Wallet.prototype.fromOptions = function fromOptions(options) {
|
|||||||
var id, token;
|
var id, token;
|
||||||
|
|
||||||
if (!master)
|
if (!master)
|
||||||
master = bcoin.hd.fromMnemonic(null, this.network);
|
master = HD.fromMnemonic(null, this.network);
|
||||||
|
|
||||||
if (!bcoin.hd.isHD(master) && !MasterKey.isMasterKey(master))
|
if (!HD.isHD(master) && !MasterKey.isMasterKey(master))
|
||||||
master = bcoin.hd.from(master, this.network);
|
master = HD.from(master, this.network);
|
||||||
|
|
||||||
if (bcoin.hd.isHD(master))
|
if (HD.isHD(master))
|
||||||
master = MasterKey.fromKey(master);
|
master = MasterKey.fromKey(master);
|
||||||
|
|
||||||
assert(MasterKey.isMasterKey(master));
|
assert(MasterKey.isMasterKey(master));
|
||||||
@ -681,7 +687,7 @@ Wallet.prototype.hasAccount = function hasAccount(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.createReceive = function createReceive(account) {
|
Wallet.prototype.createReceive = function createReceive(account) {
|
||||||
return this.createKey(account, false);
|
return this.createKey(account, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -691,7 +697,17 @@ Wallet.prototype.createReceive = function createReceive(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.createChange = function createChange(account) {
|
Wallet.prototype.createChange = function createChange(account) {
|
||||||
return this.createKey(account, true);
|
return this.createKey(account, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new nested address (increments receiveDepth).
|
||||||
|
* @param {(Number|String)?} account
|
||||||
|
* @returns {Promise} - Returns {@link WalletKey}.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Wallet.prototype.createNested = function createNested(account) {
|
||||||
|
return this.createKey(account, 2);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -893,7 +909,7 @@ Wallet.prototype._importKey = co(function* importKey(account, ring, passphrase)
|
|||||||
if (!account)
|
if (!account)
|
||||||
throw new Error('Account not found.');
|
throw new Error('Account not found.');
|
||||||
|
|
||||||
if (account.type !== bcoin.account.types.PUBKEYHASH)
|
if (account.type !== Account.types.PUBKEYHASH)
|
||||||
throw new Error('Cannot import into non-pkh account.');
|
throw new Error('Cannot import into non-pkh account.');
|
||||||
|
|
||||||
yield this.unlock(passphrase);
|
yield this.unlock(passphrase);
|
||||||
@ -949,7 +965,7 @@ Wallet.prototype.importAddress = co(function* importAddress(account, address) {
|
|||||||
Wallet.prototype._importAddress = co(function* importAddress(account, address) {
|
Wallet.prototype._importAddress = co(function* importAddress(account, address) {
|
||||||
var exists, path;
|
var exists, path;
|
||||||
|
|
||||||
if (account instanceof Address) {
|
if (!address) {
|
||||||
address = account;
|
address = account;
|
||||||
account = null;
|
account = null;
|
||||||
}
|
}
|
||||||
@ -957,7 +973,7 @@ Wallet.prototype._importAddress = co(function* importAddress(account, address) {
|
|||||||
if (account == null)
|
if (account == null)
|
||||||
account = 0;
|
account = 0;
|
||||||
|
|
||||||
exists = yield this.getPath(address.getHash('hex'));
|
exists = yield this.getPath(address);
|
||||||
|
|
||||||
if (exists)
|
if (exists)
|
||||||
throw new Error('Address already exists.');
|
throw new Error('Address already exists.');
|
||||||
@ -967,7 +983,7 @@ Wallet.prototype._importAddress = co(function* importAddress(account, address) {
|
|||||||
if (!account)
|
if (!account)
|
||||||
throw new Error('Account not found.');
|
throw new Error('Account not found.');
|
||||||
|
|
||||||
if (account.type !== bcoin.account.types.PUBKEYHASH)
|
if (account.type !== Account.types.PUBKEYHASH)
|
||||||
throw new Error('Cannot import into non-pkh account.');
|
throw new Error('Cannot import into non-pkh account.');
|
||||||
|
|
||||||
path = Path.fromAddress(account, address);
|
path = Path.fromAddress(account, address);
|
||||||
@ -1093,7 +1109,7 @@ Wallet.prototype.createTX = co(function* createTX(options, force) {
|
|||||||
throw new Error('No outputs.');
|
throw new Error('No outputs.');
|
||||||
|
|
||||||
// Create mutable tx
|
// Create mutable tx
|
||||||
tx = bcoin.mtx();
|
tx = new MTX();
|
||||||
|
|
||||||
// Add the outputs
|
// Add the outputs
|
||||||
for (i = 0; i < outputs.length; i++)
|
for (i = 0; i < outputs.length; i++)
|
||||||
@ -1255,7 +1271,7 @@ Wallet.prototype.getInputPaths = co(function* getInputPaths(tx) {
|
|||||||
var hashes = [];
|
var hashes = [];
|
||||||
var i, hash, path;
|
var i, hash, path;
|
||||||
|
|
||||||
if (tx instanceof bcoin.input) {
|
if (tx instanceof Input) {
|
||||||
if (!tx.coin)
|
if (!tx.coin)
|
||||||
throw new Error('Not all coins available.');
|
throw new Error('Not all coins available.');
|
||||||
|
|
||||||
@ -1293,7 +1309,7 @@ Wallet.prototype.getOutputPaths = co(function* getOutputPaths(tx) {
|
|||||||
var hashes = [];
|
var hashes = [];
|
||||||
var i, hash, path;
|
var i, hash, path;
|
||||||
|
|
||||||
if (tx instanceof bcoin.output) {
|
if (tx instanceof Output) {
|
||||||
hash = tx.getHash('hex');
|
hash = tx.getHash('hex');
|
||||||
if (hash)
|
if (hash)
|
||||||
hashes.push(hash);
|
hashes.push(hash);
|
||||||
@ -1337,10 +1353,10 @@ Wallet.prototype.syncOutputDepth = co(function* syncOutputDepth(info) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype._syncOutputDepth = co(function* syncOutputDepth(info) {
|
Wallet.prototype._syncOutputDepth = co(function* syncOutputDepth(info) {
|
||||||
var receive = [];
|
var derived = [];
|
||||||
var accounts = {};
|
var accounts = {};
|
||||||
var i, j, path, paths, account;
|
var i, j, path, paths, account;
|
||||||
var receiveDepth, changeDepth, ring;
|
var receive, change, nested, ring;
|
||||||
|
|
||||||
this.start();
|
this.start();
|
||||||
|
|
||||||
@ -1361,43 +1377,52 @@ Wallet.prototype._syncOutputDepth = co(function* syncOutputDepth(info) {
|
|||||||
for (i = 0; i < accounts.length; i++) {
|
for (i = 0; i < accounts.length; i++) {
|
||||||
paths = accounts[i];
|
paths = accounts[i];
|
||||||
account = paths[0].account;
|
account = paths[0].account;
|
||||||
receiveDepth = -1;
|
receive = -1;
|
||||||
changeDepth = -1;
|
change = -1;
|
||||||
|
nested = -1;
|
||||||
|
|
||||||
for (j = 0; j < paths.length; j++) {
|
for (j = 0; j < paths.length; j++) {
|
||||||
path = paths[j];
|
path = paths[j];
|
||||||
|
|
||||||
if (path.branch) {
|
switch (path.branch) {
|
||||||
if (path.index > changeDepth)
|
case 0:
|
||||||
changeDepth = path.index;
|
if (path.index > receive)
|
||||||
} else {
|
receive = path.index;
|
||||||
if (path.index > receiveDepth)
|
break;
|
||||||
receiveDepth = path.index;
|
case 1:
|
||||||
|
if (path.index > change)
|
||||||
|
change = path.index;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (path.index > nested)
|
||||||
|
nested = path.index;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveDepth += 2;
|
receive += 2;
|
||||||
changeDepth += 2;
|
change += 2;
|
||||||
|
nested += 2;
|
||||||
|
|
||||||
account = yield this.getAccount(account);
|
account = yield this.getAccount(account);
|
||||||
|
|
||||||
if (!account)
|
if (!account)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ring = yield account.setDepth(receiveDepth, changeDepth);
|
ring = yield account.setDepth(receive, change, nested);
|
||||||
|
|
||||||
if (ring)
|
if (ring)
|
||||||
receive.push(ring);
|
derived.push(ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield this.commit();
|
yield this.commit();
|
||||||
|
|
||||||
if (receive.length > 0) {
|
if (derived.length > 0) {
|
||||||
this.db.emit('address', this.id, receive);
|
this.db.emit('address', this.id, derived);
|
||||||
this.emit('address', receive);
|
this.emit('address', derived);
|
||||||
}
|
}
|
||||||
|
|
||||||
return receive;
|
return derived;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1773,9 +1798,9 @@ Wallet.prototype.getProgram = function getProgram() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.getNestedHash = function getNestedHash(enc) {
|
Wallet.prototype.getNestedHash = function getNestedHash(enc) {
|
||||||
if (!this.receive)
|
if (!this.nested)
|
||||||
return;
|
return;
|
||||||
return this.receive.getNestedHash(enc);
|
return this.nested.getHash(enc);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1786,9 +1811,9 @@ Wallet.prototype.getNestedHash = function getNestedHash(enc) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.getNestedAddress = function getNestedAddress(enc) {
|
Wallet.prototype.getNestedAddress = function getNestedAddress(enc) {
|
||||||
if (!this.receive)
|
if (!this.nested)
|
||||||
return;
|
return;
|
||||||
return this.receive.getNestedAddress(enc);
|
return this.nested.getAddress(enc);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1903,6 +1928,12 @@ Wallet.prototype.__defineGetter__('changeDepth', function() {
|
|||||||
return this.account.changeDepth;
|
return this.account.changeDepth;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Wallet.prototype.__defineGetter__('nestedDepth', function() {
|
||||||
|
if (!this.account)
|
||||||
|
return -1;
|
||||||
|
return this.account.nestedDepth;
|
||||||
|
});
|
||||||
|
|
||||||
Wallet.prototype.__defineGetter__('accountKey', function() {
|
Wallet.prototype.__defineGetter__('accountKey', function() {
|
||||||
if (!this.account)
|
if (!this.account)
|
||||||
return;
|
return;
|
||||||
@ -1921,6 +1952,12 @@ Wallet.prototype.__defineGetter__('change', function() {
|
|||||||
return this.account.change;
|
return this.account.change;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Wallet.prototype.__defineGetter__('nested', function() {
|
||||||
|
if (!this.account)
|
||||||
|
return;
|
||||||
|
return this.account.nested;
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the wallet to a more inspection-friendly object.
|
* Convert the wallet to a more inspection-friendly object.
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
@ -1997,7 +2034,7 @@ Wallet.prototype.toRaw = function toRaw(writer) {
|
|||||||
|
|
||||||
p.writeU32(this.network.magic);
|
p.writeU32(this.network.magic);
|
||||||
p.writeU32(this.wid);
|
p.writeU32(this.wid);
|
||||||
p.writeVarString(this.id, 'utf8');
|
p.writeVarString(this.id, 'ascii');
|
||||||
p.writeU8(this.initialized ? 1 : 0);
|
p.writeU8(this.initialized ? 1 : 0);
|
||||||
p.writeU32(this.accountDepth);
|
p.writeU32(this.accountDepth);
|
||||||
p.writeBytes(this.token);
|
p.writeBytes(this.token);
|
||||||
@ -2020,7 +2057,7 @@ Wallet.prototype.fromRaw = function fromRaw(data) {
|
|||||||
var p = new BufferReader(data);
|
var p = new BufferReader(data);
|
||||||
this.network = bcoin.network.fromMagic(p.readU32());
|
this.network = bcoin.network.fromMagic(p.readU32());
|
||||||
this.wid = p.readU32();
|
this.wid = p.readU32();
|
||||||
this.id = p.readVarString('utf8');
|
this.id = p.readVarString('ascii');
|
||||||
this.initialized = p.readU8() === 1;
|
this.initialized = p.readU8() === 1;
|
||||||
this.accountDepth = p.readU32();
|
this.accountDepth = p.readU32();
|
||||||
this.token = p.readBytes(32);
|
this.token = p.readBytes(32);
|
||||||
@ -2083,7 +2120,7 @@ function MasterKey(options) {
|
|||||||
this.timer = null;
|
this.timer = null;
|
||||||
this.until = 0;
|
this.until = 0;
|
||||||
this._destroy = this.destroy.bind(this);
|
this._destroy = this.destroy.bind(this);
|
||||||
this.locker = new bcoin.locker(this);
|
this.locker = new Locker(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2111,7 +2148,7 @@ MasterKey.prototype.fromOptions = function fromOptions(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.key) {
|
if (options.key) {
|
||||||
assert(bcoin.hd.isHD(options.key));
|
assert(HD.isHD(options.key));
|
||||||
this.key = options.key;
|
this.key = options.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2167,7 +2204,7 @@ MasterKey.prototype._unlock = co(function* _unlock(passphrase, timeout) {
|
|||||||
key = yield crypto.derive(passphrase);
|
key = yield crypto.derive(passphrase);
|
||||||
data = crypto.decipher(this.ciphertext, key, this.iv);
|
data = crypto.decipher(this.ciphertext, key, this.iv);
|
||||||
|
|
||||||
this.key = bcoin.hd.fromExtended(data);
|
this.key = HD.fromExtended(data);
|
||||||
|
|
||||||
this.start(timeout);
|
this.start(timeout);
|
||||||
|
|
||||||
@ -2305,7 +2342,7 @@ MasterKey.prototype._decrypt = co(function* decrypt(passphrase) {
|
|||||||
|
|
||||||
data = yield crypto.decrypt(this.ciphertext, passphrase, this.iv);
|
data = yield crypto.decrypt(this.ciphertext, passphrase, this.iv);
|
||||||
|
|
||||||
this.key = bcoin.hd.fromExtended(data);
|
this.key = HD.fromExtended(data);
|
||||||
this.encrypted = false;
|
this.encrypted = false;
|
||||||
this.iv = null;
|
this.iv = null;
|
||||||
this.ciphertext = null;
|
this.ciphertext = null;
|
||||||
@ -2418,7 +2455,7 @@ MasterKey.prototype.fromRaw = function fromRaw(raw) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.key = bcoin.hd.fromExtended(p.readVarBytes());
|
this.key = HD.fromExtended(p.readVarBytes());
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@ -2503,7 +2540,7 @@ MasterKey.prototype.fromJSON = function fromJSON(json) {
|
|||||||
this.iv = new Buffer(json.iv, 'hex');
|
this.iv = new Buffer(json.iv, 'hex');
|
||||||
this.ciphertext = new Buffer(json.ciphertext, 'hex');
|
this.ciphertext = new Buffer(json.ciphertext, 'hex');
|
||||||
} else {
|
} else {
|
||||||
this.key = bcoin.hd.fromJSON(json.key);
|
this.key = HD.fromJSON(json.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@ -11,15 +11,20 @@ var bcoin = require('../env');
|
|||||||
var AsyncObject = require('../utils/async');
|
var AsyncObject = require('../utils/async');
|
||||||
var utils = require('../utils/utils');
|
var utils = require('../utils/utils');
|
||||||
var spawn = require('../utils/spawn');
|
var spawn = require('../utils/spawn');
|
||||||
|
var Locker = require('../utils/locker');
|
||||||
|
var LRU = require('../utils/lru');
|
||||||
var co = spawn.co;
|
var co = spawn.co;
|
||||||
var crypto = require('../crypto/crypto');
|
var crypto = require('../crypto/crypto');
|
||||||
var assert = utils.assert;
|
var assert = utils.assert;
|
||||||
var constants = bcoin.constants;
|
var constants = require('../protocol/constants');
|
||||||
var BufferReader = require('../utils/reader');
|
var BufferReader = require('../utils/reader');
|
||||||
var BufferWriter = require('../utils/writer');
|
var BufferWriter = require('../utils/writer');
|
||||||
var Path = require('./path');
|
var Path = require('./path');
|
||||||
var Script = require('../script/script');
|
var Script = require('../script/script');
|
||||||
var MAX_POINT = String.fromCharCode(0xdbff, 0xdfff); // U+10FFFF
|
var Wallet = require('./wallet');
|
||||||
|
var Account = require('./account');
|
||||||
|
var ldb = require('../db/ldb');
|
||||||
|
var Bloom = require('../utils/bloom');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Database Layout:
|
* Database Layout:
|
||||||
@ -65,15 +70,15 @@ var layout = {
|
|||||||
return key.readUInt32BE(1, true);
|
return key.readUInt32BE(1, true);
|
||||||
},
|
},
|
||||||
l: function(id) {
|
l: function(id) {
|
||||||
var len = Buffer.byteLength(id, 'utf8');
|
var len = Buffer.byteLength(id, 'ascii');
|
||||||
var key = new Buffer(1 + len);
|
var key = new Buffer(1 + len);
|
||||||
key[0] = 0x6c;
|
key[0] = 0x6c;
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
key.write(id, 1, 'utf8');
|
key.write(id, 1, 'ascii');
|
||||||
return key;
|
return key;
|
||||||
},
|
},
|
||||||
ll: function(key) {
|
ll: function(key) {
|
||||||
return key.toString('utf8', 1);
|
return key.toString('ascii', 1);
|
||||||
},
|
},
|
||||||
a: function a(wid, index) {
|
a: function a(wid, index) {
|
||||||
var key = new Buffer(9);
|
var key = new Buffer(9);
|
||||||
@ -83,16 +88,16 @@ var layout = {
|
|||||||
return key;
|
return key;
|
||||||
},
|
},
|
||||||
i: function i(wid, name) {
|
i: function i(wid, name) {
|
||||||
var len = Buffer.byteLength(name, 'utf8');
|
var len = Buffer.byteLength(name, 'ascii');
|
||||||
var key = new Buffer(5 + len);
|
var key = new Buffer(5 + len);
|
||||||
key[0] = 0x69;
|
key[0] = 0x69;
|
||||||
key.writeUInt32BE(wid, 1, true);
|
key.writeUInt32BE(wid, 1, true);
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
key.write(name, 5, 'utf8');
|
key.write(name, 5, 'ascii');
|
||||||
return key;
|
return key;
|
||||||
},
|
},
|
||||||
ii: function ii(key) {
|
ii: function ii(key) {
|
||||||
return [key.readUInt32BE(1, true), key.toString('utf8', 5)];
|
return [key.readUInt32BE(1, true), key.toString('ascii', 5)];
|
||||||
},
|
},
|
||||||
R: new Buffer([0x52]),
|
R: new Buffer([0x52]),
|
||||||
b: function b(hash) {
|
b: function b(hash) {
|
||||||
@ -147,15 +152,15 @@ function WalletDB(options) {
|
|||||||
|
|
||||||
// We need one read lock for `get` and `create`.
|
// We need one read lock for `get` and `create`.
|
||||||
// It will hold locks specific to wallet ids.
|
// It will hold locks specific to wallet ids.
|
||||||
this.readLock = new bcoin.locker.mapped();
|
this.readLock = new Locker.mapped();
|
||||||
this.writeLock = new bcoin.locker();
|
this.writeLock = new Locker();
|
||||||
this.txLock = new bcoin.locker();
|
this.txLock = new Locker();
|
||||||
|
|
||||||
this.widCache = new bcoin.lru(10000);
|
this.widCache = new LRU(10000);
|
||||||
this.indexCache = new bcoin.lru(10000);
|
this.indexCache = new LRU(10000);
|
||||||
this.accountCache = new bcoin.lru(10000);
|
this.accountCache = new LRU(10000);
|
||||||
this.pathCache = new bcoin.lru(100000);
|
this.pathCache = new LRU(100000);
|
||||||
this.pathMapCache = new bcoin.lru(100000);
|
this.pathMapCache = new LRU(100000);
|
||||||
|
|
||||||
// Try to optimize for up to 1m addresses.
|
// Try to optimize for up to 1m addresses.
|
||||||
// We use a regular bloom filter here
|
// We use a regular bloom filter here
|
||||||
@ -164,10 +169,10 @@ function WalletDB(options) {
|
|||||||
// degrades.
|
// degrades.
|
||||||
// Memory used: 1.7mb
|
// Memory used: 1.7mb
|
||||||
this.filter = this.options.useFilter !== false
|
this.filter = this.options.useFilter !== false
|
||||||
? bcoin.bloom.fromRate(1000000, 0.001, -1)
|
? Bloom.fromRate(1000000, 0.001, -1)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
this.db = bcoin.ldb({
|
this.db = ldb({
|
||||||
location: this.options.location,
|
location: this.options.location,
|
||||||
db: this.options.db,
|
db: this.options.db,
|
||||||
maxOpenFiles: this.options.maxFiles,
|
maxOpenFiles: this.options.maxFiles,
|
||||||
@ -489,7 +494,7 @@ WalletDB.prototype._get = co(function* get(wid) {
|
|||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wallet = bcoin.wallet.fromRaw(this, data);
|
wallet = Wallet.fromRaw(this, data);
|
||||||
|
|
||||||
this.register(wallet);
|
this.register(wallet);
|
||||||
|
|
||||||
@ -679,7 +684,7 @@ WalletDB.prototype._create = co(function* create(options) {
|
|||||||
if (exists)
|
if (exists)
|
||||||
throw new Error('Wallet already exists.');
|
throw new Error('Wallet already exists.');
|
||||||
|
|
||||||
wallet = bcoin.wallet.fromOptions(this, options);
|
wallet = Wallet.fromOptions(this, options);
|
||||||
wallet.wid = this.depth++;
|
wallet.wid = this.depth++;
|
||||||
|
|
||||||
this.register(wallet);
|
this.register(wallet);
|
||||||
@ -760,7 +765,7 @@ WalletDB.prototype._getAccount = co(function* getAccount(wid, index) {
|
|||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
account = bcoin.account.fromRaw(this, data);
|
account = Account.fromRaw(this, data);
|
||||||
|
|
||||||
this.accountCache.set(key, account);
|
this.accountCache.set(key, account);
|
||||||
|
|
||||||
@ -778,8 +783,8 @@ WalletDB.prototype.getAccounts = co(function* getAccounts(wid) {
|
|||||||
var i, items, item, name, index, accounts;
|
var i, items, item, name, index, accounts;
|
||||||
|
|
||||||
items = yield this.db.range({
|
items = yield this.db.range({
|
||||||
gte: layout.i(wid, ''),
|
gte: layout.i(wid, '\x00'),
|
||||||
lte: layout.i(wid, MAX_POINT)
|
lte: layout.i(wid, '\xff')
|
||||||
});
|
});
|
||||||
|
|
||||||
for (i = 0; i < items.length; i++) {
|
for (i = 0; i < items.length; i++) {
|
||||||
@ -888,7 +893,7 @@ WalletDB.prototype.createAccount = co(function* createAccount(options) {
|
|||||||
if (exists)
|
if (exists)
|
||||||
throw new Error('Account already exists.');
|
throw new Error('Account already exists.');
|
||||||
|
|
||||||
account = bcoin.account.fromOptions(this, options);
|
account = Account.fromOptions(this, options);
|
||||||
|
|
||||||
yield account.init();
|
yield account.init();
|
||||||
|
|
||||||
@ -959,14 +964,9 @@ WalletDB.prototype.getWalletsByHash = co(function* getWalletsByHash(hash) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.saveKey = co(function* saveKey(wid, ring) {
|
WalletDB.prototype.saveKey = function saveKey(wid, ring) {
|
||||||
yield this.savePath(wid, ring.toPath());
|
return this.savePath(wid, ring.toPath());
|
||||||
|
};
|
||||||
if (!ring.witness)
|
|
||||||
return;
|
|
||||||
|
|
||||||
yield this.savePath(wid, ring.toNestedPath());
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a path to the path map.
|
* Save a path to the path map.
|
||||||
@ -1143,8 +1143,8 @@ WalletDB.prototype.getWalletPaths = co(function* getWalletPaths(wid) {
|
|||||||
|
|
||||||
WalletDB.prototype.getWallets = function getWallets() {
|
WalletDB.prototype.getWallets = function getWallets() {
|
||||||
return this.db.keys({
|
return this.db.keys({
|
||||||
gte: layout.l(''),
|
gte: layout.l('\x00'),
|
||||||
lte: layout.l(MAX_POINT),
|
lte: layout.l('\xff'),
|
||||||
parse: layout.ll
|
parse: layout.ll
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -1255,7 +1255,7 @@ WalletDB.prototype.resend = co(function* resend() {
|
|||||||
if (!data)
|
if (!data)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tx = bcoin.tx.fromExtended(data);
|
tx = TX.fromExtended(data);
|
||||||
|
|
||||||
this.emit('send', tx);
|
this.emit('send', tx);
|
||||||
}
|
}
|
||||||
@ -1852,7 +1852,7 @@ Details.prototype._insert = function _insert(vector, target, table) {
|
|||||||
io = vector[i];
|
io = vector[i];
|
||||||
member = new DetailsMember();
|
member = new DetailsMember();
|
||||||
|
|
||||||
if (io instanceof bcoin.input)
|
if (io.prevout)
|
||||||
member.value = io.coin ? io.coin.value : 0;
|
member.value = io.coin ? io.coin.value : 0;
|
||||||
else
|
else
|
||||||
member.value = io.value;
|
member.value = io.value;
|
||||||
|
|||||||
@ -129,8 +129,10 @@ WalletKey.prototype.toJSON = function toJSON() {
|
|||||||
return {
|
return {
|
||||||
network: this.network.type,
|
network: this.network.type,
|
||||||
witness: this.witness,
|
witness: this.witness,
|
||||||
|
nested: this.nested,
|
||||||
publicKey: this.publicKey.toString('hex'),
|
publicKey: this.publicKey.toString('hex'),
|
||||||
script: this.script ? this.script.toRaw().toString('hex') : null,
|
script: this.script ? this.script.toRaw().toString('hex') : null,
|
||||||
|
program: this.program ? this.program.toRaw().toString('hex') : null,
|
||||||
type: constants.scriptTypesByVal[this.type].toLowerCase(),
|
type: constants.scriptTypesByVal[this.type].toLowerCase(),
|
||||||
wid: this.wid,
|
wid: this.wid,
|
||||||
id: this.id,
|
id: this.id,
|
||||||
@ -138,8 +140,7 @@ WalletKey.prototype.toJSON = function toJSON() {
|
|||||||
account: this.account,
|
account: this.account,
|
||||||
branch: this.branch,
|
branch: this.branch,
|
||||||
index: this.index,
|
index: this.index,
|
||||||
address: this.getAddress('base58'),
|
address: this.getAddress('base58')
|
||||||
nestedAddress: this.getNestedAddress('base58')
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -178,6 +179,7 @@ WalletKey.prototype.fromHD = function fromHD(account, key, branch, index) {
|
|||||||
this.branch = branch;
|
this.branch = branch;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.witness = account.witness;
|
this.witness = account.witness;
|
||||||
|
this.nested = branch === 2;
|
||||||
|
|
||||||
if (key.privateKey)
|
if (key.privateKey)
|
||||||
return this.fromPrivate(key.privateKey, key.network);
|
return this.fromPrivate(key.privateKey, key.network);
|
||||||
@ -266,7 +268,7 @@ WalletKey.isWalletKey = function isWalletKey(obj) {
|
|||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletKey.prototype.toPath = function toPath(nested) {
|
WalletKey.prototype.toPath = function toPath() {
|
||||||
var path = new Path();
|
var path = new Path();
|
||||||
|
|
||||||
path.id = this.id;
|
path.id = this.id;
|
||||||
@ -286,30 +288,13 @@ WalletKey.prototype.toPath = function toPath(nested) {
|
|||||||
|
|
||||||
path.keyType = this.keyType;
|
path.keyType = this.keyType;
|
||||||
|
|
||||||
if (nested) {
|
path.version = this.getVersion();
|
||||||
assert(this.witness);
|
path.type = this.getType();
|
||||||
path.version = -1;
|
path.hash = this.getHash('hex');
|
||||||
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;
|
return path;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether an object is a WalletKey.
|
|
||||||
* @param {Object} obj
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletKey.prototype.toNestedPath = function toNestedPath() {
|
|
||||||
return this.toPath(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -507,6 +507,9 @@ describe('Wallet', function() {
|
|||||||
var flags = bcoin.constants.flags.STANDARD_VERIFY_FLAGS;
|
var flags = bcoin.constants.flags.STANDARD_VERIFY_FLAGS;
|
||||||
var options, w1, w2, w3, receive, b58, addr, paddr, utx, send, change;
|
var options, w1, w2, w3, receive, b58, addr, paddr, utx, send, change;
|
||||||
|
|
||||||
|
var rec = bullshitNesting ? 'nested' : 'receive';
|
||||||
|
var depth = bullshitNesting ? 'nestedDepth' : 'receiveDepth';
|
||||||
|
|
||||||
if (witness)
|
if (witness)
|
||||||
flags |= bcoin.constants.flags.VERIFY_WITNESS;
|
flags |= bcoin.constants.flags.VERIFY_WITNESS;
|
||||||
|
|
||||||
@ -531,17 +534,21 @@ describe('Wallet', function() {
|
|||||||
yield w3.addKey(w2.accountKey);
|
yield w3.addKey(w2.accountKey);
|
||||||
|
|
||||||
// Our p2sh address
|
// Our p2sh address
|
||||||
b58 = w1.getAddress('base58');
|
b58 = w1[rec].getAddress('base58');
|
||||||
addr = bcoin.address.fromBase58(b58);
|
addr = bcoin.address.fromBase58(b58);
|
||||||
|
|
||||||
if (witness)
|
if (witness) {
|
||||||
assert.equal(addr.type, scriptTypes.WITNESSSCRIPTHASH);
|
if (bullshitNesting)
|
||||||
else
|
assert.equal(addr.type, scriptTypes.SCRIPTHASH);
|
||||||
|
else
|
||||||
|
assert.equal(addr.type, scriptTypes.WITNESSSCRIPTHASH);
|
||||||
|
} else {
|
||||||
assert.equal(addr.type, scriptTypes.SCRIPTHASH);
|
assert.equal(addr.type, scriptTypes.SCRIPTHASH);
|
||||||
|
}
|
||||||
|
|
||||||
assert.equal(w1.getAddress('base58'), b58);
|
assert.equal(w1[rec].getAddress('base58'), b58);
|
||||||
assert.equal(w2.getAddress('base58'), b58);
|
assert.equal(w2[rec].getAddress('base58'), b58);
|
||||||
assert.equal(w3.getAddress('base58'), b58);
|
assert.equal(w3[rec].getAddress('base58'), b58);
|
||||||
|
|
||||||
paddr = w1.getNestedAddress('base58');
|
paddr = w1.getNestedAddress('base58');
|
||||||
assert.equal(w1.getNestedAddress('base58'), paddr);
|
assert.equal(w1.getNestedAddress('base58'), paddr);
|
||||||
@ -563,20 +570,21 @@ describe('Wallet', function() {
|
|||||||
utx.ts = 1;
|
utx.ts = 1;
|
||||||
utx.height = 1;
|
utx.height = 1;
|
||||||
|
|
||||||
assert.equal(w1.receiveDepth, 1);
|
assert.equal(w1[depth], 1);
|
||||||
|
|
||||||
yield walletdb.addTX(utx);
|
yield walletdb.addTX(utx);
|
||||||
yield walletdb.addTX(utx);
|
yield walletdb.addTX(utx);
|
||||||
yield walletdb.addTX(utx);
|
yield walletdb.addTX(utx);
|
||||||
|
|
||||||
assert.equal(w1.receiveDepth, 2);
|
assert.equal(w1[depth], 2);
|
||||||
|
|
||||||
assert.equal(w1.changeDepth, 1);
|
assert.equal(w1.changeDepth, 1);
|
||||||
|
|
||||||
assert(w1.getAddress('base58') !== b58);
|
assert(w1[rec].getAddress('base58') !== b58);
|
||||||
b58 = w1.getAddress('base58');
|
b58 = w1[rec].getAddress('base58');
|
||||||
assert.equal(w1.getAddress('base58'), b58);
|
assert.equal(w1[rec].getAddress('base58'), b58);
|
||||||
assert.equal(w2.getAddress('base58'), b58);
|
assert.equal(w2[rec].getAddress('base58'), b58);
|
||||||
assert.equal(w3.getAddress('base58'), b58);
|
assert.equal(w3[rec].getAddress('base58'), b58);
|
||||||
|
|
||||||
// Create a tx requiring 2 signatures
|
// Create a tx requiring 2 signatures
|
||||||
send = bcoin.mtx();
|
send = bcoin.mtx();
|
||||||
@ -609,10 +617,10 @@ describe('Wallet', function() {
|
|||||||
yield walletdb.addTX(send);
|
yield walletdb.addTX(send);
|
||||||
yield walletdb.addTX(send);
|
yield walletdb.addTX(send);
|
||||||
|
|
||||||
assert.equal(w1.receiveDepth, 2);
|
assert.equal(w1[depth], 2);
|
||||||
assert.equal(w1.changeDepth, 2);
|
assert.equal(w1.changeDepth, 2);
|
||||||
|
|
||||||
assert(w1.getAddress('base58') === b58);
|
assert(w1[rec].getAddress('base58') === b58);
|
||||||
assert(w1.change.getAddress('base58') !== change);
|
assert(w1.change.getAddress('base58') !== change);
|
||||||
change = w1.change.getAddress('base58');
|
change = w1.change.getAddress('base58');
|
||||||
assert.equal(w1.change.getAddress('base58'), change);
|
assert.equal(w1.change.getAddress('base58'), change);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user