keyring: refactor.

This commit is contained in:
Christopher Jeffrey 2016-08-15 07:37:26 -07:00
parent cfad740b09
commit 49f56f786f
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
9 changed files with 160 additions and 172 deletions

View File

@ -2062,7 +2062,7 @@ RPC.prototype._signrawtransaction = function signrawtransaction(merged, txs, arg
op = redeem.get(j);
key = keyMap[op.toString('hex')];
if (key) {
key.addr.type = 'multisig';
key.addr.type = bcoin.keyring.types.MULTISIG;
key.addr.m = redeem.getSmall(0);
key.addr.n = redeem.getSmall(redeem.length - 1);
key.addr.keys = redeem.slice(1, -2);

View File

@ -388,31 +388,6 @@ Input.prototype.isCoinbase = function isCoinbase() {
return this.prevout.isNull();
};
/**
* Test the input against an address, an
* array of addresses, or a map of hashes.
* @param {Hash|Hash[]|AddressHashMap} addressMap
* @returns {Boolean} Whether the input matched.
*/
Input.prototype.test = function test(addressMap) {
var hash = this.getHash('hex');
if (!hash)
return false;
if (typeof addressMap === 'string')
return hash === addressMap;
if (Array.isArray(addressMap))
return addressMap.indexOf(hash) !== -1;
if (addressMap[hash] != null)
return true;
return false;
};
/**
* Convert the input to a more user-friendly object.
* @returns {Object}

View File

@ -37,7 +37,7 @@ function KeyRing(options) {
return new KeyRing(options);
this.network = bcoin.network.get();
this.type = 'pubkeyhash';
this.type = KeyRing.types.PUBKEYHASH;
this.m = 1;
this.n = 1;
this.witness = false;
@ -65,6 +65,27 @@ function KeyRing(options) {
this.fromOptions(options);
}
/**
* KeyRing types.
* @enum {Number}
* @default
*/
KeyRing.types = {
PUBKEYHASH: 0,
MULTISIG: 1
};
/**
* KeyRing types by value.
* @const {RevMap}
*/
KeyRing.typesByVal = {
0: 'pubkeyhash',
1: 'multisig'
};
/**
* Inject properties from options object.
* @private
@ -79,9 +100,15 @@ KeyRing.prototype.fromOptions = function fromOptions(options) {
if (options.network)
this.network = bcoin.network.get(options.network);
if (options.type) {
assert(options.type === 'pubkeyhash' || options.type === 'multisig');
this.type = options.type;
if (options.type != null) {
if (typeof options.type === 'string') {
this.type = KeyRing.types[options.type.toUpperCase()];
assert(this.type != null);
} else {
assert(typeof options.type === 'number');
this.type = options.type;
assert(KeyRing.typesByVal[this.type]);
}
}
if (options.m != null) {
@ -137,7 +164,7 @@ KeyRing.prototype.fromOptions = function fromOptions(options) {
assert(Buffer.isBuffer(this.key));
if (this.n > 1)
this.type = 'multisig';
this.type = KeyRing.types.MULTISIG;
if (this.m < 1 || this.m > this.n)
throw new Error('m ranges between 1 and n');
@ -163,6 +190,54 @@ KeyRing.fromOptions = function fromOptions(options) {
return new KeyRing().fromOptions(options);
};
/**
* Inject properties from account object.
* @private
* @param {Account} account
* @param {Buffer} key
* @param {Buffer[]} keys
* @param {Number} change
* @param {Number} index
*/
KeyRing.prototype.fromAccount = function fromAccount(account, key, keys, change, index) {
var i;
this.network = account.network;
this.key = key.publicKey;
this.wid = account.wid;
this.id = account.id;
this.name = account.name;
this.account = account.accountIndex;
this.change = change;
this.index = index;
this.type = account.type;
this.witness = account.witness;
this.m = account.m;
this.n = account.n;
this.addKey(this.key);
for (i = 0; i < keys.length; i++)
this.addKey(keys[i]);
return this;
};
/**
* Instantiate key ring from an account.
* @param {Account} account
* @param {Buffer} key
* @param {Buffer[]} keys
* @param {Number} change
* @param {Number} index
* @returns {KeyRing}
*/
KeyRing.fromAccount = function fromAccount(account, key, keys, change, index) {
return new KeyRing().fromAccount(account, key, keys, change, index);
};
/**
* Add a key to shared keys.
* @param {Buffer} key
@ -218,7 +293,7 @@ KeyRing.prototype.getPublicKey = function getPublicKey(enc) {
KeyRing.prototype.getScript = function getScript() {
var redeem;
if (this.type !== 'multisig')
if (this.type !== KeyRing.types.MULTISIG)
return;
if (!this._script) {
@ -247,10 +322,10 @@ KeyRing.prototype.getProgram = function getProgram() {
return;
if (!this._program) {
if (this.type === 'pubkeyhash') {
if (this.type === KeyRing.types.PUBKEYHASH) {
hash = utils.hash160(this.getPublicKey());
program = bcoin.script.fromProgram(0, hash);
} else if (this.type === 'multisig') {
} else if (this.type === KeyRing.types.MULTISIG) {
hash = utils.sha256(this.getScript().toRaw());
program = bcoin.script.fromProgram(0, hash);
} else {
@ -324,7 +399,7 @@ KeyRing.prototype.getScriptHash = function getScriptHash(enc) {
*/
KeyRing.prototype.getScriptHash160 = function getScriptHash256(enc) {
if (this.type !== 'multisig')
if (this.type !== KeyRing.types.MULTISIG)
return;
if (!this._scriptHash160)
@ -342,7 +417,7 @@ KeyRing.prototype.getScriptHash160 = function getScriptHash256(enc) {
*/
KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) {
if (this.type !== 'multisig')
if (this.type !== KeyRing.types.MULTISIG)
return;
if (!this._scriptHash256)
@ -362,7 +437,7 @@ KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) {
KeyRing.prototype.getScriptAddress = function getScriptAddress(enc) {
var hash, address;
if (this.type !== 'multisig')
if (this.type !== KeyRing.types.MULTISIG)
return;
if (!this._scriptAddress) {
@ -442,7 +517,7 @@ KeyRing.prototype.compile = function compile(hash, type, version) {
*/
KeyRing.prototype.getHash = function getHash(enc) {
if (this.type === 'multisig')
if (this.type === KeyRing.types.MULTISIG)
return this.getScriptHash(enc);
return this.getKeyHash(enc);
};
@ -454,7 +529,7 @@ KeyRing.prototype.getHash = function getHash(enc) {
*/
KeyRing.prototype.getAddress = function getAddress(enc) {
if (this.type === 'multisig')
if (this.type === KeyRing.types.MULTISIG)
return this.getScriptAddress(enc);
return this.getKeyAddress(enc);
};
@ -470,7 +545,7 @@ KeyRing.prototype.getAddressMap = function getAddressMap() {
this._addressMap[this.getKeyHash('hex')] = true;
if (this.type === 'multisig')
if (this.type === KeyRing.types.MULTISIG)
this._addressMap[this.getScriptHash('hex')] = true;
if (this.witness)
@ -489,11 +564,21 @@ KeyRing.prototype.getAddressMap = function getAddressMap() {
KeyRing.prototype.ownInput = function ownInput(tx, index) {
var addressMap = this.getAddressMap();
var input, hash;
if (tx instanceof bcoin.input)
return tx.test(addressMap);
if (tx instanceof bcoin.input) {
input = tx;
} else {
input = tx.inputs[index];
assert(input, 'Input does not exist.');
}
return tx.testInputs(addressMap, index);
hash = input.getHash('hex');
if (!hash)
return false;
return addressMap[hash] === true;
};
/**
@ -505,11 +590,21 @@ KeyRing.prototype.ownInput = function ownInput(tx, index) {
KeyRing.prototype.ownOutput = function ownOutput(tx, index) {
var addressMap = this.getAddressMap();
var output, hash;
if (tx instanceof bcoin.output)
return tx.test(addressMap);
if (tx instanceof bcoin.output) {
output = tx;
} else {
output = tx.outputs[index];
assert(output, 'Output does not exist.');
}
return tx.testOutputs(addressMap, index);
hash = output.getHash('hex');
if (!hash)
return false;
return addressMap[hash] === true;
};
/**
@ -657,7 +752,7 @@ KeyRing.prototype.__defineGetter__('address', function() {
KeyRing.prototype.toJSON = function toJSON() {
return {
network: this.network.type,
type: this.type,
type: KeyRing.typesByVal[this.type].toLowerCase(),
m: this.m,
n: this.n,
witness: this.witness,
@ -667,8 +762,10 @@ KeyRing.prototype.toJSON = function toJSON() {
account: this.account,
change: this.change,
index: this.index,
key: utils.toBase58(this.key),
keys: this.keys.map(utils.toBase58),
key: this.key.toString('hex'),
keys: this.keys.map(function(key) {
return key.toString('hex');
}),
keyAddress: this.getKeyAddress('base58'),
scriptAddress: this.getScriptAddress('base58'),
programAddress: this.getProgramAddress('base58')
@ -686,7 +783,7 @@ KeyRing.prototype.fromJSON = function fromJSON(json) {
assert(json);
assert(typeof json.network === 'string');
assert(json.type === 'pubkeyhash' || json.type === 'multisig');
assert(typeof json.type === 'string');
assert(utils.isNumber(json.m));
assert(utils.isNumber(json.n));
assert(typeof json.witness === 'boolean');
@ -700,7 +797,7 @@ KeyRing.prototype.fromJSON = function fromJSON(json) {
assert(Array.isArray(json.keys));
this.nework = bcoin.network.get(json.network);
this.type = json.type;
this.type = KeyRing.types[json.type.toUpperCase()];
this.m = json.m;
this.n = json.n;
this.witness = json.witness;
@ -709,10 +806,12 @@ KeyRing.prototype.fromJSON = function fromJSON(json) {
this.account = json.account;
this.change = json.change;
this.index = json.index;
this.key = utils.fromBase58(json.key);
this.key = new Buffer(json.key, 'hex');
assert(this.type != null);
for (i = 0; i < json.keys.length; i++)
this.keys.push(utils.fromBase58(json.keys[i]));
this.keys.push(new Buffer(json.keys[i], 'hex'));
return this;
};
@ -737,7 +836,7 @@ KeyRing.prototype.toRaw = function toRaw(writer) {
var i;
p.writeU32(this.network.magic);
p.writeU8(this.type === 'pubkeyhash' ? 0 : 1);
p.writeU8(this.type);
p.writeU8(this.m);
p.writeU8(this.n);
p.writeU8(this.witness ? 1 : 0);
@ -770,7 +869,7 @@ KeyRing.prototype.fromRaw = function fromRaw(data) {
var i, count;
this.network = bcoin.network.fromMagic(p.readU32());
this.type = p.readU8() === 0 ? 'pubkeyhash' : 'multisig';
this.type = p.readU8();
this.m = p.readU8();
this.n = p.readU8();
this.witness = p.readU8() === 1;
@ -782,6 +881,8 @@ KeyRing.prototype.fromRaw = function fromRaw(data) {
this.index = p.readU32();
this.key = p.readVarBytes();
assert(KeyRing.typesByVal[this.type]);
count = p.readU8();
for (i = 0; i < count; i++)

View File

@ -27,7 +27,6 @@ var TX = bcoin.tx;
* @param {Number?} options.changeIndex
* @param {Input[]?} options.inputs
* @param {Output[]?} options.outputs
* @property {String} type - "tx" (inv type).
* @property {Number} version - Transaction version. Note that BCoin reads
* versions as unsigned even though they are signed at the protocol level.
* This value will never be negative.

View File

@ -106,31 +106,6 @@ Output.prototype.getHash = function getHash(enc) {
return address.getHash(enc);
};
/**
* Test the output against an address, an
* array of addresses, or a map of addresses.
* @param {Hash|Hash[]|AddressHashMap} addressMap
* @returns {Boolean} Whether the output matched.
*/
Output.prototype.test = function test(addressMap) {
var hash = this.getHash('hex');
if (!hash)
return false;
if (typeof addressMap === 'string')
return hash === addressMap;
if (Array.isArray(addressMap))
return addressMap.indexOf(hash) !== -1;
if (addressMap[hash] != null)
return true;
return false;
};
/**
* Convert the input to a more user-friendly object.
* @returns {Object}

View File

@ -928,68 +928,6 @@ TX.prototype.getHashes = function getHashes(enc) {
return hashes;
};
/**
* Test the inputs against an address, an
* array of address hashes, or a map of address hashes.
* @param {Hash|Hash[]|AddressHashMap} addressMap
* @param {Number?} index
* @returns {Boolean} Whether the transaction matched.
*/
TX.prototype.testInputs = function testInputs(addressMap, index) {
var i;
if (typeof addressMap === 'string')
addressMap = [addressMap];
if (Array.isArray(addressMap))
addressMap = utils.toMap(addressMap);
if (index && typeof index === 'object')
index = this.inputs.indexOf(index);
if (index != null)
return this.inputs[index].test(addressMap);
for (i = 0; i < this.inputs.length; i++) {
if (this.inputs[i].test(addressMap))
return true;
}
return false;
};
/**
* Test the outputs against an address, an
* array of address hashes, or a map of address hashes.
* @param {Hash|Hash[]|AddressHashMap} addressMap
* @param {Number?} index
* @returns {Boolean} Whether the transaction matched.
*/
TX.prototype.testOutputs = function testOutputs(addressMap, index) {
var i;
if (typeof addressMap === 'string')
addressMap = [addressMap];
if (Array.isArray(addressMap))
addressMap = utils.toMap(addressMap);
if (index && typeof index === 'object')
index = this.outputs.indexOf(index);
if (index != null)
return this.outputs[index].test(addressMap);
for (i = 0; i < this.outputs.length; i++) {
if (this.outputs[i].test(addressMap))
return true;
}
return false;
};
/**
* Test whether the transaction has
* all coins available/filled.

View File

@ -15,6 +15,8 @@ var assert = utils.assert;
var BufferReader = require('./reader');
var BufferWriter = require('./writer');
var TXDB = require('./txdb');
var keyTypes = bcoin.keyring.types;
var keyTypesByVal = bcoin.keyring.typesByVal;
/**
* BIP44 Wallet
@ -2070,7 +2072,7 @@ function Account(db, options) {
this.accountIndex = 0;
this.receiveDepth = 0;
this.changeDepth = 0;
this.type = 'pubkeyhash';
this.type = keyTypes.PUBKEYHASH;
this.m = 1;
this.n = 1;
this.keys = [];
@ -2127,9 +2129,15 @@ Account.prototype.fromOptions = function fromOptions(options) {
this.changeDepth = options.changeDepth;
}
if (options.type) {
assert(options.type === 'pubkeyhash' || options.type === 'multisig');
this.type = options.type;
if (options.type != null) {
if (typeof options.type === 'string') {
this.type = keyTypes[options.type.toUpperCase()];
assert(this.type != null);
} else {
assert(typeof options.type === 'number');
this.type = options.type;
assert(keyTypesByVal[this.type]);
}
}
if (options.m != null) {
@ -2148,7 +2156,7 @@ Account.prototype.fromOptions = function fromOptions(options) {
}
if (this.n > 1)
this.type = 'multisig';
this.type = keyTypes.MULTISIG;
if (this.m < 1 || this.m > this.n)
throw new Error('m ranges between 1 and n');
@ -2363,7 +2371,7 @@ Account.prototype._checkKeys = function _checkKeys(callback) {
var self = this;
var address;
if (this.initialized || this.type !== 'multisig')
if (this.initialized || this.type !== keyTypes.MULTISIG)
return callback(null, false);
if (this.keys.length !== this.n)
@ -2499,21 +2507,7 @@ Account.prototype.deriveAddress = function deriveAddress(change, index) {
keys.push(shared.publicKey);
}
return new bcoin.keyring({
network: this.network,
key: key.publicKey,
wid: this.wid,
id: this.id,
name: this.name,
account: this.accountIndex,
change: change,
index: index,
type: this.type,
witness: this.witness,
m: this.m,
n: this.n,
keys: keys
});
return bcoin.keyring.fromAccount(this, key, keys, change, index);
};
/**
@ -2599,7 +2593,7 @@ Account.prototype.inspect = function inspect() {
name: this.name,
network: this.network,
initialized: this.initialized,
type: this.type,
type: keyTypesByVal[this.type].toLowerCase(),
m: this.m,
n: this.n,
keyAddress: this.initialized
@ -2634,7 +2628,7 @@ Account.prototype.toJSON = function toJSON() {
wid: this.wid,
name: this.name,
initialized: this.initialized,
type: this.type,
type: keyTypesByVal[this.type].toLowerCase(),
m: this.m,
n: this.n,
witness: this.witness,
@ -2671,7 +2665,7 @@ Account.prototype.fromJSON = function fromJSON(json) {
assert(utils.isAlpha(json.id), 'Account name must be alphanumeric.');
assert(utils.isAlpha(json.name), 'Account name must be alphanumeric.');
assert(typeof json.initialized === 'boolean');
assert(json.type === 'pubkeyhash' || json.type === 'multisig');
assert(typeof json.type === 'string');
assert(utils.isNumber(json.m));
assert(utils.isNumber(json.n));
assert(typeof json.witness === 'boolean');
@ -2683,7 +2677,7 @@ Account.prototype.fromJSON = function fromJSON(json) {
this.wid = json.wid;
this.name = json.name;
this.initialized = json.initialized;
this.type = json.type;
this.type = keyTypes[json.type.toUpperCase()];
this.m = json.m;
this.n = json.n;
this.witness = json.witness;
@ -2692,6 +2686,8 @@ Account.prototype.fromJSON = function fromJSON(json) {
this.changeDepth = json.changeDepth;
this.accountKey = bcoin.hd.fromBase58(json.accountKey);
assert(this.type != null);
for (i = 0; i < json.keys.length; i++)
this.keys.push(bcoin.hd.fromBase58(json.keys[i]));
@ -2710,7 +2706,7 @@ Account.prototype.toRaw = function toRaw(writer) {
p.writeU32(this.network.magic);
p.writeVarString(this.name, 'utf8');
p.writeU8(this.initialized ? 1 : 0);
p.writeU8(this.type === 'pubkeyhash' ? 0 : 1);
p.writeU8(this.type);
p.writeU8(this.m);
p.writeU8(this.n);
p.writeU8(this.witness ? 1 : 0);
@ -2743,7 +2739,7 @@ Account.prototype.fromRaw = function fromRaw(data) {
this.network = bcoin.network.fromMagic(p.readU32());
this.name = p.readVarString('utf8');
this.initialized = p.readU8() === 1;
this.type = p.readU8() === 0 ? 'pubkeyhash' : 'multisig';
this.type = p.readU8();
this.m = p.readU8();
this.n = p.readU8();
this.witness = p.readU8() === 1;
@ -2752,6 +2748,8 @@ Account.prototype.fromRaw = function fromRaw(data) {
this.changeDepth = p.readU32();
this.accountKey = bcoin.hd.fromRaw(p.readBytes(82));
assert(keyTypesByVal[this.type]);
count = p.readU8();
for (i = 0; i < count; i++)

View File

@ -29,6 +29,7 @@ var constants = bcoin.protocol.constants;
var BufferReader = require('./reader');
var BufferWriter = require('./writer');
var TXDB = require('./txdb');
var keyTypes = bcoin.keyring.types;
/**
* WalletDB
@ -828,7 +829,7 @@ WalletDB.prototype.saveAddress = function saveAddress(wid, addresses, callback)
items.push([address.getKeyAddress(), path]);
if (address.type === 'multisig')
if (address.type === keyTypes.MULTISIG)
items.push([address.getScriptAddress(), path]);
if (address.witness)

View File

@ -150,7 +150,7 @@ describe('Wallet', function() {
p2pkh(true, true, cb);
});
it('should multisign/verify TX', function() {
it('should multisign/verify TX', function(cb) {
walletdb.create({
type: 'multisig',
m: 1,
@ -185,6 +185,7 @@ describe('Wallet', function() {
assert.ifError(err);
assert(tx.toRaw().length <= maxSize);
assert(tx.verify());
cb();
});
});
});