Merge pull request #739 from maraoz/optimize/redeemscriptmap

optimize redeemscript map generation
This commit is contained in:
Yemel Jardi 2014-06-25 09:58:25 -03:00
commit 139f6f8e18
9 changed files with 66 additions and 35 deletions

View File

@ -232,8 +232,6 @@ Insight.prototype._requestNode = function(options, callback) {
return callback(e, ret); return callback(e, ret);
}); });
response.on('error', function(e) { response.on('error', function(e) {
console.log('[Insight.js.201]'); //TODO
return callback(e, ret); return callback(e, ret);
}); });
}); });
@ -284,7 +282,6 @@ Insight.prototype._requestBrowser = function(options, callback) {
} else { } else {
errTxt = 'Error code: ' + request.status + ' - Status: ' + request.statusText + ' - Description: ' + request.responseText; errTxt = 'Error code: ' + request.status + ' - Status: ' + request.statusText + ' - Description: ' + request.responseText;
setTimeout(function() { setTimeout(function() {
console.log('### Retrying Insight Request....');
return self._request(options, callback); return self._request(options, callback);
}, self.retryDelay); }, self.retryDelay);
} }

View File

@ -233,19 +233,17 @@ PublicKeyRing.prototype.getAddressesInfo = function(opts) {
}; };
// TODO this could be cached // TODO this could be cached
PublicKeyRing.prototype._addScriptMap = function(map, index, isChange) { PublicKeyRing.prototype._addScriptMap = function(map, path) {
var script = this.getRedeemScript(index, isChange); var p = Structure.indicesForPath(path);
var script = this.getRedeemScript(p.index, p.isChange);
map[Address.fromScript(script, this.network.name).toString()] = script.getBuffer().toString('hex'); map[Address.fromScript(script, this.network.name).toString()] = script.getBuffer().toString('hex');
}; };
PublicKeyRing.prototype.getRedeemScriptMap = function() { PublicKeyRing.prototype.getRedeemScriptMap = function(paths) {
var ret = {}; var ret = {};
for (var i = 0; i < paths.length; i++) {
for (var i = 0; i < this.indexes.getChangeIndex(); i++) { var path = paths[i];
this._addScriptMap(ret, i, true); this._addScriptMap(ret, path);
}
for (var i = 0; i < this.indexes.getReceiveIndex(); i++) {
this._addScriptMap(ret, i, false);
} }
return ret; return ret;
}; };

View File

@ -4,7 +4,6 @@ var imports = require('soop').imports();
function Structure() {} function Structure() {}
/* /*
* Based on https://github.com/maraoz/bips/blob/master/bip-NNNN.mediawiki * Based on https://github.com/maraoz/bips/blob/master/bip-NNNN.mediawiki
* m / purpose' / cosigner_index / change / address_index * m / purpose' / cosigner_index / change / address_index
@ -31,6 +30,15 @@ Structure.FullBranch = function(address_index, isChange, cosigner_index) {
sub = sub.substring(2); sub = sub.substring(2);
return BIP45_PUBLIC_PREFIX + '/' + sub; return BIP45_PUBLIC_PREFIX + '/' + sub;
}; };
Structure.indicesForPath = function(path) {
var s = path.split('/');
return {
isChange: s[3] === '1',
index: parseInt(s[4]),
};
};
Structure.IdFullBranch = Structure.FullBranch(0, 0, ID_INDEX); Structure.IdFullBranch = Structure.FullBranch(0, 0, ID_INDEX);
Structure.IdBranch = Structure.Branch(0, 0, ID_INDEX); Structure.IdBranch = Structure.Branch(0, 0, ID_INDEX);
Structure.PURPOSE = PURPOSE; Structure.PURPOSE = PURPOSE;

View File

@ -709,7 +709,6 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, comment, utxos
var b = new Builder(opts) var b = new Builder(opts)
.setUnspent(utxos) .setUnspent(utxos)
.setHashToScriptMap(pkr.getRedeemScriptMap())
.setOutputs([{ .setOutputs([{
address: toAddress, address: toAddress,
amountSat: amountSat amountSat: amountSat
@ -720,6 +719,8 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, comment, utxos
return pkr.pathForAddress(utxo.address); return pkr.pathForAddress(utxo.address);
}); });
b = b.setHashToScriptMap(pkr.getRedeemScriptMap(inputChainPaths));
if (priv) { if (priv) {
var keys = priv.getForPaths(inputChainPaths); var keys = priv.getForPaths(inputChainPaths);
var signed = b.sign(keys); var signed = b.sign(keys);

View File

@ -17,7 +17,6 @@ FakeBlockchain.prototype.fixUnspent = function(u) {
}; };
FakeBlockchain.prototype.getUnspent = function(addresses, cb) { FakeBlockchain.prototype.getUnspent = function(addresses, cb) {
if (!addresses || !addresses.length) return cb(null, []);
return cb(null, this.u || [{ return cb(null, this.u || [{
'address': 'mji7zocy8QzYywQakwWf99w9bCT6orY1C1', 'address': 'mji7zocy8QzYywQakwWf99w9bCT6orY1C1',
'txid': '0be0fb4579911be829e3077202e1ab47fcc12cf3ab8f8487ccceae768e1f95fa', 'txid': '0be0fb4579911be829e3077202e1ab47fcc12cf3ab8f8487ccceae768e1f95fa',
@ -31,7 +30,6 @@ FakeBlockchain.prototype.getUnspent = function(addresses, cb) {
}; };
FakeBlockchain.prototype.getUnspent2 = function(addresses, cb) { FakeBlockchain.prototype.getUnspent2 = function(addresses, cb) {
if (!addresses || !addresses.length) return cb(null, []);
return cb(null, this.u || [{ return cb(null, this.u || [{
'address': 'mji7zocy8QzYywQakwWf99w9bCT6orY1C1', 'address': 'mji7zocy8QzYywQakwWf99w9bCT6orY1C1',
'txid': '0be0fb4579911be829e3077202e1ab47fcc12cf3ab8f8487ccceae768e1f95fa', 'txid': '0be0fb4579911be829e3077202e1ab47fcc12cf3ab8f8487ccceae768e1f95fa',

View File

@ -381,13 +381,19 @@ describe('PublicKeyRing model', function() {
it('#getRedeemScriptMap check tests', function() { it('#getRedeemScriptMap check tests', function() {
var k = createW(); var k = createW();
var w = k.w; var w = k.w;
var amount = 2;
for (var i = 0; i < 2; i++) for (var i = 0; i < amount; i++)
w.generateAddress(true); w.generateAddress(true);
for (var i = 0; i < 2; i++) for (var i = 0; i < amount; i++)
w.generateAddress(false); w.generateAddress(false);
var m = w.getRedeemScriptMap(); var m = w.getRedeemScriptMap([
'm/45\'/2147483647/1/0',
'm/45\'/2147483647/1/1',
'm/45\'/2147483647/0/0',
'm/45\'/2147483647/0/1'
]);
Object.keys(m).length.should.equal(4); Object.keys(m).length.should.equal(4);
Object.keys(m).forEach(function(k) { Object.keys(m).forEach(function(k) {
should.exist(m[k]); should.exist(m[k]);

View File

@ -38,4 +38,22 @@ describe('Structure model', function() {
Structure.FullBranch(10, true, 7).should.equal('m/45\'/7/1/10'); Structure.FullBranch(10, true, 7).should.equal('m/45\'/7/1/10');
}); });
[
['m/45\'/0/0/0', {index: 0, isChange: false}],
['m/45\'/0/0/1', {index: 1, isChange: false}],
['m/45\'/0/0/2', {index: 2, isChange: false}],
['m/45\'/0/1/0', {index: 0, isChange: true}],
['m/45\'/0/1/1', {index: 1, isChange: true}],
['m/45\'/0/1/2', {index: 2, isChange: true}],
['m/45\'/0/0/900', {index: 900, isChange: false}],
].forEach(function(datum) {
var path = datum[0];
var result = datum[1];
it('should get the correct indices for path ' + path, function() {
var i = Structure.indicesForPath(path);
i.index.should.equal(result.index);
i.isChange.should.equal(result.isChange);
});
});
}); });

View File

@ -144,7 +144,6 @@ describe('TxProposals model', function() {
var b = new Builder(opts) var b = new Builder(opts)
.setUnspent(utxos) .setUnspent(utxos)
.setHashToScriptMap(pkr.getRedeemScriptMap())
.setOutputs([{ .setOutputs([{
address: toAddress, address: toAddress,
amountSat: amountSat amountSat: amountSat
@ -154,6 +153,12 @@ describe('TxProposals model', function() {
return pkr.pathForAddress(utxo.address); return pkr.pathForAddress(utxo.address);
}); });
var selectedUtxos = b.getSelectedUnspent();
var inputChainPaths = selectedUtxos.map(function(utxo) {
return pkr.pathForAddress(utxo.address);
});
b.setHashToScriptMap(pkr.getRedeemScriptMap(inputChainPaths));
var signRet; var signRet;
if (priv) { if (priv) {
var pkeys = priv.getForPaths(inputChainPaths); var pkeys = priv.getForPaths(inputChainPaths);

View File

@ -42,30 +42,36 @@ describe('Wallet model', function() {
w.getNetworkName().should.equal('testnet'); w.getNetworkName().should.equal('testnet');
}); });
var createW = function(netKey, N, conf) { var createW = function(netKey, N, conf) {
var c = JSON.parse(JSON.stringify(conf || config)); var c = JSON.parse(JSON.stringify(conf || config));
if (!N) N = c.totalCopayers; if (!N) N = c.totalCopayers;
if (netKey) c.netKey = netKey; if (netKey) c.netKey = netKey;
c.privateKey = new copay.PrivateKey({ var mainPrivateKey = new copay.PrivateKey({
networkName: c.networkName networkName: config.networkName
}); });
var mainCopayerEPK = mainPrivateKey.deriveBIP45Branch().extendedPublicKeyString();
c.privateKey = mainPrivateKey;
c.publicKeyRing = new copay.PublicKeyRing({ c.publicKeyRing = new copay.PublicKeyRing({
networkName: c.networkName, networkName: c.networkName,
requiredCopayers: Math.min(N, c.requiredCopayers), requiredCopayers: Math.min(N, c.requiredCopayers),
totalCopayers: N, totalCopayers: N,
}); });
var copayerEPK = c.privateKey.deriveBIP45Branch().extendedPublicKeyString() c.publicKeyRing.addCopayer(mainCopayerEPK);
c.publicKeyRing.addCopayer(copayerEPK);
c.txProposals = new copay.TxProposals({ c.txProposals = new copay.TxProposals({
networkName: c.networkName, networkName: c.networkName,
}); });
c.storage = new Storage(config.storage);
c.network = new Network(config.network); var storage = new Storage(config.storage);
c.blockchain = new Blockchain(config.blockchain); var network = new Network(config.network);
var blockchain = new Blockchain(config.blockchain);
c.storage = storage;
c.network = network;
c.blockchain = blockchain;
c.addressBook = { c.addressBook = {
'2NFR2kzH9NUdp8vsXTB4wWQtTtzhpKxsyoJ': { '2NFR2kzH9NUdp8vsXTB4wWQtTtzhpKxsyoJ': {
@ -138,13 +144,6 @@ describe('Wallet model', function() {
pkr.addCopayer(); pkr.addCopayer();
} }
} }
pkr.generateAddress(true);
pkr.generateAddress(true);
pkr.generateAddress(true);
pkr.generateAddress(false);
pkr.generateAddress(false);
pkr.generateAddress(false);
//3x3 indexes
return w; return w;
}; };
@ -234,7 +233,7 @@ describe('Wallet model', function() {
var w = createW2(); var w = createW2();
var ts = Date.now(); var ts = Date.now();
for (var isChange = 0; isChange < 2; isChange++) { for (var isChange = false; !isChange; isChange = true) {
for (var index = 0; index < 3; index++) { for (var index = 0; index < 3; index++) {
unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange).toString(); unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange).toString();
unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(index, isChange); unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(index, isChange);
@ -531,6 +530,7 @@ describe('Wallet model', function() {
it('should get balance', function(done) { it('should get balance', function(done) {
var w = createW(); var w = createW();
var spy = sinon.spy(w.blockchain, 'getUnspent'); var spy = sinon.spy(w.blockchain, 'getUnspent');
w.blockchain.fixUnspent([]);
w.getBalance(function(err, balance, balanceByAddr, safeBalance) { w.getBalance(function(err, balance, balanceByAddr, safeBalance) {
sinon.assert.callCount(spy, 1); sinon.assert.callCount(spy, 1);
balance.should.equal(0); balance.should.equal(0);