store by hash.

This commit is contained in:
Christopher Jeffrey 2016-05-13 12:01:06 -07:00
parent e51ae84f37
commit 8db6e1c9a6
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
10 changed files with 205 additions and 130 deletions

View File

@ -371,13 +371,13 @@ Address.prototype._getAddressMap = function _getAddressMap() {
if (!this.addressMap) {
this.addressMap = {};
this.addressMap[this.getKeyAddress()] = true;
this.addressMap[this.getKeyHash('hex')] = true;
if (this.type === 'multisig')
this.addressMap[this.getScriptAddress()] = true;
this.addressMap[this.getScriptHash('hex')] = true;
if (this.witness)
this.addressMap[this.getProgramAddress()] = true;
this.addressMap[this.getProgramHash('hex')] = true;
}
return this.addressMap;
@ -394,9 +394,9 @@ Address.prototype.ownInput = function ownInput(tx, index) {
var addressMap = this._getAddressMap();
if (tx instanceof bcoin.input)
return tx.test(addressMap, this.network);
return tx.test(addressMap);
return tx.testInputs(addressMap, index, this.network);
return tx.testInputs(addressMap, index);
};
/**
@ -410,9 +410,9 @@ Address.prototype.ownOutput = function ownOutput(tx, index) {
var addressMap = this._getAddressMap();
if (tx instanceof bcoin.output)
return tx.test(addressMap, this.network);
return tx.test(addressMap);
return tx.testOutputs(addressMap, index, this.network);
return tx.testOutputs(addressMap, index);
};
/**
@ -653,22 +653,7 @@ Address.parse = function parse(address) {
*/
Address.validate = function validate(address, type) {
if (!address)
return false;
if (!Buffer.isBuffer(address) && typeof address !== 'string')
return false;
try {
address = Address.parse(address);
} catch (e) {
return false;
}
if (type && address.type !== type)
return false;
return true;
return bcoin.script.Address.validate(address, type);
};
Address.prototype.compileHash = function compileHash(hash, type, version) {

View File

@ -801,7 +801,7 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
if (self.options.indexTX) {
batch.put('t/' + hash, tx.toExtended());
if (self.options.indexAddress) {
addresses = tx.getAddresses(self.network);
addresses = tx.getHashes();
for (j = 0; j < addresses.length; j++) {
address = addresses[j];
batch.put('T/' + address + '/' + hash, DUMMY);
@ -819,7 +819,7 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
assert(input.coin);
if (self.options.indexAddress) {
address = input.getAddress(self.network);
address = input.getHash();
if (address)
batch.del('C/' + address + '/' + key);
}
@ -841,7 +841,7 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
coin = bcoin.coin(tx, j);
if (self.options.indexAddress) {
address = output.getAddress(self.network);
address = output.getHash();
if (address)
batch.put('C/' + address + '/' + key, DUMMY);
}
@ -893,7 +893,7 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(block, batch, callb
if (self.options.indexTX) {
batch.del('t/' + hash);
if (self.options.indexAddress) {
addresses = tx.getAddresses(self.network);
addresses = tx.getHashes();
for (j = 0; j < addresses.length; j++) {
address = addresses[j];
batch.del('T/' + address + '/' + hash);
@ -911,7 +911,7 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(block, batch, callb
assert(input.coin);
if (self.options.indexAddress) {
address = input.getAddress(self.network);
address = input.getHash();
if (address)
batch.put('C/' + address + '/' + key, DUMMY);
}
@ -929,7 +929,7 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(block, batch, callb
continue;
if (self.options.indexAddress) {
address = output.getAddress(self.network);
address = output.getHash();
if (address)
batch.del('C/' + address + '/' + key);
}
@ -1110,6 +1110,9 @@ ChainDB.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, call
addresses = utils.uniq(addresses);
utils.forEachSerial(addresses, function(address, next) {
address = bcoin.script.Address.getHash(address);
if (!address)
return next();
self.db.lookup({
gte: 'C/' + address,
lte: 'C/' + address + '~',
@ -1149,7 +1152,10 @@ ChainDB.prototype.getTXByAddress = function getTXByAddress(addresses, callback)
addresses = utils.uniq(addresses);
utils.forEachSerial(addresses, function(address, done) {
utils.forEachSerial(addresses, function(address, next) {
address = bcoin.script.Address.getHash(address);
if (!address)
return next();
self.db.lookup({
gte: 'T/' + address,
lte: 'T/' + address + '~',

View File

@ -148,26 +148,26 @@ Input.prototype.getSubtype = function getSubtype() {
* Get the previous output script's address. Will "guess"
* based on the input script and/or witness if coin
* is not available.
* @returns {String?} address
* @returns {ScriptAddress?} address
*/
Input.prototype.getAddress = function getAddress(network) {
Input.prototype.getAddress = function getAddress() {
var address;
if (this.isCoinbase())
return;
if (this.coin)
return this.coin.getAddress(network);
return this.coin.getAddress();
if (this._address)
return this._address;
if (this.witness.items.length > 0)
address = this.witness.getInputAddress(network);
address = this.witness.getInputAddress();
if (!address)
address = this.script.getInputAddress(network);
address = this.script.getInputAddress();
if (!this.mutable)
this._address = address;
@ -175,6 +175,18 @@ Input.prototype.getAddress = function getAddress(network) {
return address;
};
/**
* Get the address hash.
* @returns {Hash} hash
*/
Input.prototype.getHash = function getHash(enc) {
var address = this.getAddress();
if (!address)
return;
return address.getHash('hex');
};
/**
* Test to see if nSequence is equal to uint32max.
* @returns {Boolean}
@ -200,19 +212,19 @@ Input.prototype.isCoinbase = function isCoinbase() {
* @returns {Boolean} Whether the input matched.
*/
Input.prototype.test = function test(addressMap, network) {
var address = this.getAddress(network);
Input.prototype.test = function test(addressMap) {
var hash = this.getHash('hex');
if (!address)
if (!hash)
return false;
if (typeof addressMap === 'string')
return address === addressMap;
return hash === addressMap;
if (Array.isArray(addressMap))
return addressMap.indexOf(address) !== -1;
return addressMap.indexOf(hash) !== -1;
if (addressMap[address] != null)
if (addressMap[hash] != null)
return true;
return false;

View File

@ -1543,7 +1543,7 @@ Mempool.prototype._addUnchecked = function _addUnchecked(entry, callback) {
batch.put('m/' + pad32(entry.ts) + '/' + hash, DUMMY);
if (this.options.indexAddress) {
addresses = tx.getAddresses(this.network);
addresses = tx.getHashes();
for (i = 0; i < addresses.length; i++)
batch.put('T/' + addresses[i] + '/' + hash, DUMMY);
}
@ -1561,7 +1561,7 @@ Mempool.prototype._addUnchecked = function _addUnchecked(entry, callback) {
batch.put('s/' + key, tx.hash());
if (this.options.indexAddress) {
address = input.getAddress(this.network);
address = input.getHash();
if (address)
batch.del('C/' + address + '/' + key);
}
@ -1579,7 +1579,7 @@ Mempool.prototype._addUnchecked = function _addUnchecked(entry, callback) {
batch.put('c/' + key, coin);
if (this.options.indexAddress) {
address = output.getAddress(this.network);
address = output.getHash();
if (address)
batch.put('C/' + address + '/' + key, DUMMY);
}
@ -1617,7 +1617,7 @@ Mempool.prototype._removeUnchecked = function _removeUnchecked(hash, limit, call
batch.del('m/' + pad32(entry.ts) + '/' + hash);
if (self.options.indexAddress) {
addresses = tx.getAddresses(self.network);
addresses = tx.getHashes();
for (i = 0; i < addresses.length; i++)
batch.del('T/' + addresses[i] + '/' + hash);
}
@ -1641,14 +1641,14 @@ Mempool.prototype._removeUnchecked = function _removeUnchecked(hash, limit, call
if (result) {
batch.put('c/' + key, input.coin.toRaw());
if (self.options.indexAddress) {
address = input.getAddress(self.network);
address = input.getHash();
if (address)
batch.put('C/' + address + '/' + key, DUMMY);
}
} else {
batch.del('c/' + key);
if (self.options.indexAddress) {
address = input.getAddress(self.network);
address = input.getHash();
if (address)
batch.del('C/' + address + '/' + key);
}
@ -1669,7 +1669,7 @@ Mempool.prototype._removeUnchecked = function _removeUnchecked(hash, limit, call
batch.del('c/' + key);
if (self.options.indexAddress) {
address = output.getAddress(self.network);
address = output.getHash();
if (address)
batch.del('C/' + address + '/' + key);
}

View File

@ -70,16 +70,16 @@ Output.prototype.getType = function getType() {
/**
* Get the address.
* @returns {String?} address
* @returns {ScriptAddress} address
*/
Output.prototype.getAddress = function getAddress(network) {
Output.prototype.getAddress = function getAddress() {
var address;
if (this._address)
return this._address;
address = this.script.getAddress(network);
address = this.script.getAddress();
if (!this.mutable)
this._address = address;
@ -87,6 +87,18 @@ Output.prototype.getAddress = function getAddress(network) {
return address;
};
/**
* Get the address hash.
* @returns {Hash} hash
*/
Output.prototype.getHash = function getHash() {
var address = this.getAddress();
if (!address)
return;
return address.getHash('hex');
};
/**
* Test the output against an address, an
* array of addresses, or a map of addresses.
@ -94,19 +106,19 @@ Output.prototype.getAddress = function getAddress(network) {
* @returns {Boolean} Whether the output matched.
*/
Output.prototype.test = function test(addressMap, network) {
var address = this.getAddress(network);
Output.prototype.test = function test(addressMap) {
var hash = this.getHash();
if (!address)
if (!hash)
return false;
if (typeof addressMap === 'string')
return address === addressMap;
return hash === addressMap;
if (Array.isArray(addressMap))
return addressMap.indexOf(address) !== -1;
return addressMap.indexOf(hash) !== -1;
if (addressMap[address] != null)
if (addressMap[hash] != null)
return true;
return false;

View File

@ -118,11 +118,7 @@ Witness.prototype.getInputType = function getInputType() {
*/
Witness.prototype.getInputAddress = function getInputAddress(network) {
var addr = Address.fromWitness(this);
if (!addr)
return;
return addr.toBase58(network);
return Address.fromWitness(this);
};
/**
@ -2359,12 +2355,8 @@ Script.prototype.getSize = function getSize() {
* @returns {Base58Address|null}
*/
Script.prototype.getInputAddress = function getInputAddress(network) {
var addr = Address.fromInputScript(this);
if (!addr)
return;
return addr.toBase58(network);
Script.prototype.getInputAddress = function getInputAddress() {
return Address.fromInputScript(this);
};
/**
@ -2374,12 +2366,8 @@ Script.prototype.getInputAddress = function getInputAddress(network) {
* @returns {Base58Address|null}
*/
Script.prototype.getAddress = function getAddress(network) {
var addr = Address.fromScript(this);
if (!addr)
return;
return addr.toBase58(network);
Script.prototype.getAddress = function getAddress() {
return Address.fromScript(this);
};
/**
@ -4464,4 +4452,52 @@ Address.toScript = function toScript() {
assert(false, 'Bad type.');
};
Address.validate = function validate(address, type) {
if (!address)
return false;
if (!Buffer.isBuffer(address) && typeof address !== 'string')
return false;
try {
address = Address.parseBase58(address);
} catch (e) {
return false;
}
if (type && address.type !== type)
return false;
return true;
};
Address.getHash = function getHash(data) {
var hash;
if (data instanceof Address) {
hash = data.hash;
} else {
try {
hash = Address.parseBase58(data).hash;
} catch (e) {
return;
}
}
return hash.toString('hex');
};
// Address.prototype.toString = function toString() {
// return this.toBase58();
// };
Address.prototype.inspect = function inspect() {
return {
hash: this.getHash('hex'),
type: this.type,
version: this.version,
address: this.toBase58()
};
};
Script.Address = Address;

View File

@ -694,16 +694,19 @@ TX.prototype.getOutputValue = function getOutputValue() {
* @returns {Base58Address[]} addresses
*/
TX.prototype.getInputAddresses = function getInputAddresses(network) {
TX.prototype.getInputAddresses = function getInputAddresses() {
var table = {};
var addresses = [];
var i, address;
var i, address, hash;
for (i = 0; i < this.inputs.length; i++) {
address = this.inputs[i].getAddress(network);
if (address && !table[address]) {
table[address] = true;
addresses.push(address);
address = this.inputs[i].getAddress();
if (address) {
hash = address.getHash('hex');
if (!table[hash]) {
table[hash] = true;
addresses.push(address);
}
}
}
@ -717,16 +720,19 @@ TX.prototype.getInputAddresses = function getInputAddresses(network) {
* @returns {Base58Address[]} addresses
*/
TX.prototype.getOutputAddresses = function getOutputAddresses(network) {
TX.prototype.getOutputAddresses = function getOutputAddresses() {
var table = {};
var addresses = [];
var i, address;
var i, address, hash;
for (i = 0; i < this.outputs.length; i++) {
address = this.outputs[i].getAddress(network);
if (address && !table[address]) {
table[address] = true;
addresses.push(address);
address = this.outputs[i].getAddress();
if (address) {
hash = address.getHash('hex');
if (!table[hash]) {
table[hash] = true;
addresses.push(address);
}
}
}
@ -740,14 +746,15 @@ TX.prototype.getOutputAddresses = function getOutputAddresses(network) {
* @returns {Base58Address[]} addresses
*/
TX.prototype.getAddresses = function getAddresses(network) {
var input = this.getInputAddresses(network);
var output = this.getOutputAddresses(network);
var i;
TX.prototype.getAddresses = function getAddresses() {
var input = this.getInputAddresses();
var output = this.getOutputAddresses();
var i, hash;
for (i = 0; i < output.length; i++) {
if (!input.table[output[i]]) {
input.table[output[i]] = true;
hash = output[i].getHash('hex');
if (!input.table[hash]) {
input.table[hash] = true;
input.push(output[i]);
}
}
@ -755,6 +762,33 @@ TX.prototype.getAddresses = function getAddresses(network) {
return input;
};
/**
* Get all input address hashes.
* @returns {Hash[]} hashes
*/
TX.prototype.getInputHashes = function getInputHashes() {
return Object.keys(this.getInputAddresses().table);
};
/**
* Get all output address hashes.
* @returns {Hash[]} hashes
*/
TX.prototype.getOutputHashes = function getOutputHashes() {
return Object.keys(this.getOutputAddresses().table);
};
/**
* Get all address hashes.
* @returns {Hash[]} hashes
*/
TX.prototype.getHashes = function getHashes() {
return Object.keys(this.getAddresses().table);
};
/**
* Test the inputs against an address, an
* array of addresses, or a map of addresses.
@ -763,7 +797,7 @@ TX.prototype.getAddresses = function getAddresses(network) {
* @returns {Boolean} Whether the transaction matched.
*/
TX.prototype.testInputs = function testInputs(addressMap, index, network) {
TX.prototype.testInputs = function testInputs(addressMap, index) {
var i;
if (typeof addressMap === 'string')
@ -776,10 +810,10 @@ TX.prototype.testInputs = function testInputs(addressMap, index, network) {
index = this.inputs.indexOf(index);
if (index != null)
return this.inputs[index].test(addressMap, network);
return this.inputs[index].test(addressMap);
for (i = 0; i < this.inputs.length; i++) {
if (this.inputs[i].test(addressMap, network))
if (this.inputs[i].test(addressMap))
return true;
}
@ -794,7 +828,7 @@ TX.prototype.testInputs = function testInputs(addressMap, index, network) {
* @returns {Boolean} Whether the transaction matched.
*/
TX.prototype.testOutputs = function testOutputs(addressMap, index, network) {
TX.prototype.testOutputs = function testOutputs(addressMap, index) {
var i;
if (typeof addressMap === 'string')
@ -807,10 +841,10 @@ TX.prototype.testOutputs = function testOutputs(addressMap, index, network) {
index = this.outputs.indexOf(index);
if (index != null)
return this.outputs[index].test(addressMap, network);
return this.outputs[index].test(addressMap);
for (i = 0; i < this.outputs.length; i++) {
if (this.outputs[i].test(addressMap, network))
if (this.outputs[i].test(addressMap))
return true;
}

View File

@ -82,8 +82,8 @@ TXDB.prototype.getMap = function getMap(tx, callback) {
if (!this.options.indexAddress)
return callback();
input = tx.getInputAddresses(this.network);
output = tx.getOutputAddresses(this.network);
input = tx.getInputHashes();
output = tx.getOutputHashes();
addresses = utils.uniq(input.concat(output));
function cb(err, table) {
@ -340,7 +340,7 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
if (tx.isCoinbase())
return next();
address = input.getAddress(self.network);
address = input.getHash();
// Only add orphans if this input is ours.
if (self.options.mapAddress) {
@ -434,7 +434,7 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
// Add unspent outputs or resolve orphans
utils.forEachSerial(tx.outputs, function(output, next, i) {
var address = output.getAddress(self.network);
var address = output.getHash();
var key, coin;
// Do not add unspents for outputs that aren't ours.
@ -688,7 +688,7 @@ TXDB.prototype._confirm = function _confirm(tx, map, callback, force) {
}
utils.forEachSerial(tx.outputs, function(output, next, i) {
var address = output.getAddress(self.network);
var address = output.getHash();
// Only update coins if this output is ours.
if (self.options.mapAddress) {
@ -849,7 +849,7 @@ TXDB.prototype._remove = function remove(tx, map, callback, force) {
tx.inputs.forEach(function(input) {
var key = input.prevout.hash + '/' + input.prevout.index;
var address = input.getAddress(self.network);
var address = input.getHash();
if (tx.isCoinbase())
return;
@ -875,7 +875,7 @@ TXDB.prototype._remove = function remove(tx, map, callback, force) {
tx.outputs.forEach(function(output, i) {
var key = hash + '/' + i;
var address = output.getAddress(self.network);
var address = output.getHash();
if (self.options.mapAddress) {
if (!address || !map.table[address].length)

View File

@ -508,13 +508,13 @@ Wallet.prototype.deriveAddress = function deriveAddress(change, index) {
address = new bcoin.address(options);
this.addressMap[address.getKeyAddress()] = data.path;
this.addressMap[address.getKeyHash('hex')] = data.path;
if (this.type === 'multisig')
this.addressMap[address.getScriptAddress()] = data.path;
this.addressMap[address.getScriptHash('hex')] = data.path;
if (this.witness)
this.addressMap[address.getProgramAddress()] = data.path;
this.addressMap[address.getProgramHash('hex')] = data.path;
// Update the DB with the new address.
if (this.provider && this.provider.update)
@ -648,9 +648,9 @@ Wallet.prototype.setChangeDepth = function setChangeDepth(depth) {
Wallet.prototype.ownInput = function ownInput(tx, index) {
if (tx instanceof bcoin.input)
return tx.test(this.addressMap, this.network);
return tx.test(this.addressMap);
return tx.testInputs(this.addressMap, index, this.network);
return tx.testInputs(this.addressMap, index);
};
/**
@ -662,9 +662,9 @@ Wallet.prototype.ownInput = function ownInput(tx, index) {
Wallet.prototype.ownOutput = function ownOutput(tx, index) {
if (tx instanceof bcoin.output)
return tx.test(this.addressMap, this.network);
return tx.test(this.addressMap);
return tx.testOutputs(this.addressMap, index, this.network);
return tx.testOutputs(this.addressMap, index);
};
/**
@ -878,7 +878,7 @@ Wallet.prototype.getInputPaths = function getInputPaths(tx, index) {
var i, input, address, path;
if (tx instanceof bcoin.input) {
path = this.getPath(tx.coin.getAddress(this.network));
path = this.getPath(tx.coin.getHash());
if (path)
paths.push(path);
return paths;
@ -892,7 +892,7 @@ Wallet.prototype.getInputPaths = function getInputPaths(tx, index) {
assert(input.coin, 'Not all coins available.');
address = input.coin.getAddress(this.network);
address = input.coin.getHash();
path = this.getPath(address);
if (!path)
@ -916,7 +916,7 @@ Wallet.prototype.getOutputPaths = function getOutputPaths(tx, index) {
var i, output, address, path;
if (tx instanceof bcoin.output) {
path = this.getPath(tx.getAddress(this.network));
path = this.getPath(tx.getHash());
if (path)
paths.push(path);
return paths;
@ -928,7 +928,7 @@ Wallet.prototype.getOutputPaths = function getOutputPaths(tx, index) {
if (index != null && i !== index)
continue;
address = output.getAddress(this.network);
address = output.getHash();
path = this.getPath(address);
if (!path)
@ -1002,17 +1002,7 @@ Wallet.prototype.getRedeem = function getRedeem(hash, prefix) {
if (typeof hash === 'string')
hash = new Buffer(hash, 'hex');
if (!prefix) {
if (hash.length === 20)
prefix = 'scripthash';
else if (hash.length === 32)
prefix = 'witnessscripthash';
else
return;
}
addr = bcoin.address.compileHash(hash, prefix, null, this.network);
address = this.deriveAddress(addr);
address = this.deriveAddress(hash.toString('hex'));
if (!address)
return;

View File

@ -699,18 +699,18 @@ WalletDB.prototype.update = function update(wallet, address) {
batch = this.db.batch();
batch.put(
'W/' + address.getKeyAddress() + '/' + wallet.id,
'W/' + address.getKeyHash('hex') + '/' + wallet.id,
DUMMY);
if (address.type === 'multisig') {
batch.put(
'W/' + address.getScriptAddress() + '/' + wallet.id,
'W/' + address.getScriptHash('hex') + '/' + wallet.id,
DUMMY);
}
if (address.witness) {
batch.put(
'W/' + address.getProgramAddress() + '/' + wallet.id,
'W/' + address.getProgramHash('hex') + '/' + wallet.id,
DUMMY);
}