Browse Source

Merge pull request #346 from isocolsky/feat/p2pkh

Feat/p2pkh
activeAddress
Ivan Socolsky 9 years ago
parent
commit
8d026b85a5
  1. 2
      lib/expressapp.js
  2. 11
      lib/model/address.js
  3. 2
      lib/model/copayer.js
  4. 2
      lib/model/txproposal.js
  5. 5
      lib/model/wallet.js
  6. 14
      lib/server.js
  7. 4
      package.json
  8. 57
      test/integration/server.js

2
lib/expressapp.js

@ -133,6 +133,7 @@ ExpressApp.prototype.start = function(opts, cb) {
router.post('/v1/wallets/', function(req, res) {
var server = getServer(req, res);
req.body.supportBIP44 = false;
req.body.supportP2PKH = false;
server.createWallet(req.body, function(err, walletId) {
if (err) return returnError(err, res, req);
res.json({
@ -144,6 +145,7 @@ ExpressApp.prototype.start = function(opts, cb) {
router.post('/v2/wallets/', function(req, res) {
var server = getServer(req, res);
req.body.supportBIP44 = true;
req.body.supportP2PKH = true;
server.createWallet(req.body, function(err, walletId) {
if (err) return returnError(err, res, req);
res.json({

11
lib/model/address.js

@ -34,15 +34,4 @@ Address.fromObj = function(obj) {
return x;
};
/**
* getScriptPubKey
*
* @param {number} threshold - amount of required signatures to spend the output
* @return {Script}
*/
Address.prototype.getScriptPubKey = function(threshold) {
return Bitcore.Script.buildMultisigOut(this.publicKeys, threshold).toScriptHashOut();
};
module.exports = Address;

2
lib/model/copayer.js

@ -82,7 +82,7 @@ Copayer.prototype.createAddress = function(wallet, isChange) {
$.checkState(wallet.isComplete());
var path = this.addressManager.getNewAddressPath(isChange);
var raw = Address.create(WalletUtils.deriveAddress(wallet.publicKeyRing, path, wallet.m, wallet.network));
var raw = Address.create(WalletUtils.deriveAddress(wallet.addressType, wallet.publicKeyRing, path, wallet.m, wallet.network));
var address = Address.create(_.extend(raw, {
walletId: wallet.id,
}));

2
lib/model/txproposal.js

@ -72,6 +72,7 @@ TxProposal.create = function(opts) {
x.proposalSignaturePubKey = opts.proposalSignaturePubKey;
x.proposalSignaturePubKeySig = opts.proposalSignaturePubKeySig;
x.derivationStrategy = opts.derivationStrategy || WalletUtils.DERIVATION_STRATEGIES.BIP45;
x.addressType = opts.addressType || WalletUtils.SCRIPT_TYPES.P2SH;
x.customData = opts.customData;
if (_.isFunction(TxProposal._create[x.type])) {
@ -120,6 +121,7 @@ TxProposal.fromObj = function(obj) {
x.proposalSignaturePubKey = obj.proposalSignaturePubKey;
x.proposalSignaturePubKeySig = obj.proposalSignaturePubKeySig;
x.derivationStrategy = obj.derivationStrategy || WalletUtils.DERIVATION_STRATEGIES.BIP45;
x.addressType = obj.addressType || WalletUtils.SCRIPT_TYPES.P2SH;
x.customData = obj.customData;
return x;

5
lib/model/wallet.js

@ -30,6 +30,8 @@ Wallet.create = function(opts) {
x.pubKey = opts.pubKey;
x.network = opts.network;
x.derivationStrategy = opts.derivationStrategy || WalletUtils.DERIVATION_STRATEGIES.BIP45;
x.addressType = opts.addressType || WalletUtils.SCRIPT_TYPES.P2SH;
x.addressManager = AddressManager.create({
derivationStrategy: x.derivationStrategy,
});
@ -55,6 +57,7 @@ Wallet.fromObj = function(obj) {
x.pubKey = obj.pubKey;
x.network = obj.network;
x.derivationStrategy = obj.derivationStrategy || WalletUtils.DERIVATION_STRATEGIES.BIP45;
x.addressType = obj.addressType || WalletUtils.SCRIPT_TYPES.P2SH;
x.addressManager = AddressManager.fromObj(obj.addressManager);
x.scanStatus = obj.scanStatus;
@ -148,7 +151,7 @@ Wallet.prototype.createAddress = function(isChange) {
$.checkState(this.isComplete());
var path = this.addressManager.getNewAddressPath(isChange);
var raw = WalletUtils.deriveAddress(this.publicKeyRing, path, this.m, this.network);
var raw = WalletUtils.deriveAddress(this.addressType, this.publicKeyRing, path, this.m, this.network);
var address = Address.create(_.extend(raw, {
walletId: this.id,
}));

14
lib/server.js

@ -204,6 +204,7 @@ WalletService.prototype._runLocked = function(cb, task) {
* @param {string} opts.pubKey - Public key to verify copayers joining have access to the wallet secret.
* @param {string} [opts.network = 'livenet'] - The Bitcoin network for this wallet.
* @param {string} [opts.supportBIP44 = false] - Client supports BIP44 paths for 1-of-1 wallets.
* @param {string} [opts.supportP2PKH = false] - Client supports P2PKH address type for 1-of-1 wallets.
*/
WalletService.prototype.createWallet = function(opts, cb) {
var self = this,
@ -223,6 +224,9 @@ WalletService.prototype.createWallet = function(opts, cb) {
var derivationStrategy = (opts.n == 1 && opts.supportBIP44) ?
WalletUtils.DERIVATION_STRATEGIES.BIP44 : WalletUtils.DERIVATION_STRATEGIES.BIP45;
var addressType = (opts.n == 1 && opts.supportP2PKH) ?
WalletUtils.SCRIPT_TYPES.P2PKH : WalletUtils.SCRIPT_TYPES.P2SH;
try {
pubKey = new PublicKey.fromString(opts.pubKey);
} catch (ex) {
@ -250,6 +254,7 @@ WalletService.prototype.createWallet = function(opts, cb) {
network: opts.network,
pubKey: pubKey.toString(),
derivationStrategy: derivationStrategy,
addressType: addressType,
});
self.storage.storeWallet(wallet, function(err) {
log.debug('Wallet created', wallet.id, opts.network);
@ -537,14 +542,6 @@ WalletService.prototype._parseClientVersion = function() {
return this.parsedClientVersion;
};
WalletService.prototype._clientSupportsBIP44 = function() {
var version = this._parseClientVersion();
if (!version) return false;
if (version.agent != 'bwc') return true; // Asume 3rd party clients are up-to-date
if (version.major == 0 && version.minor <= 1) return false;
return true;
};
WalletService.prototype._clientSupportsTXPv2 = function() {
var version = this._parseClientVersion();
if (!version) return false;
@ -1211,6 +1208,7 @@ WalletService.prototype.createTx = function(opts, cb) {
walletN: wallet.n,
excludeUnconfirmedUtxos: !!opts.excludeUnconfirmedUtxos,
derivationStrategy: wallet.derivationStrategy,
addressType: wallet.addressType,
customData: opts.customData
};

4
package.json

@ -2,7 +2,7 @@
"name": "bitcore-wallet-service",
"description": "A service for Mutisig HD Bitcoin Wallets",
"author": "BitPay Inc",
"version": "0.2.0",
"version": "0.2.1",
"keywords": [
"bitcoin",
"copay",
@ -20,7 +20,7 @@
"dependencies": {
"async": "^0.9.0",
"bitcore": "0.13.0",
"bitcore-wallet-utils": "0.2.0",
"bitcore-wallet-utils": "0.2.1",
"body-parser": "^1.11.0",
"coveralls": "^2.11.2",
"email-validator": "^1.0.1",

57
test/integration/server.js

@ -97,12 +97,14 @@ helpers.createAndJoinWallet = function(m, n, opts, cb) {
var offset = opts.offset || 0;
var supportBIP44 = _.isBoolean(opts.supportBIP44) ? opts.supportBIP44 : true
var supportP2PKH = _.isBoolean(opts.supportP2PKH) ? opts.supportP2PKH : true
var walletOpts = {
name: 'a wallet',
m: m,
n: n,
pubKey: TestData.keyPair.pub,
supportBIP44: supportBIP44,
supportP2PKH: supportP2PKH,
};
server.createWallet(walletOpts, function(err, walletId) {
if (err) return cb(err);
@ -161,11 +163,23 @@ helpers.stubUtxos = function(server, wallet, amounts, cb) {
} else {
confirmations = Math.floor(Math.random() * 100 + 1);
}
var scriptPubKey;
switch (wallet.addressType) {
case WalletUtils.SCRIPT_TYPES.P2SH:
scriptPubKey = Bitcore.Script.buildMultisigOut(address.publicKeys, wallet.m).toScriptHashOut();
break;
case WalletUtils.SCRIPT_TYPES.P2PKH:
scriptPubKey = Bitcore.Script.buildPublicKeyHashOut(address.address);
break;
}
should.exist(scriptPubKey);
return {
txid: helpers.randomTXID(),
vout: Math.floor(Math.random() * 10 + 1),
satoshis: helpers.toSatoshi(amount).toString(),
scriptPubKey: address.getScriptPubKey(wallet.m).toBuffer().toString('hex'),
scriptPubKey: scriptPubKey.toBuffer().toString('hex'),
address: address.address,
confirmations: confirmations,
};
@ -1156,24 +1170,26 @@ describe('Wallet service', function() {
beforeEach(function() {
server = WalletService.getInstance();
});
it('should use BIP44 for 1-of-1 wallet if supported', function(done) {
it('should use BIP44 & P2PKH for 1-of-1 wallet if supported', function(done) {
var walletOpts = {
name: 'my wallet',
m: 1,
n: 1,
pubKey: TestData.keyPair.pub,
supportBIP44: true,
supportP2PKH: true,
};
server.createWallet(walletOpts, function(err, wid) {
should.not.exist(err);
server.storage.fetchWallet(wid, function(err, wallet) {
should.not.exist(err);
wallet.derivationStrategy.should.equal('BIP44');
wallet.addressType.should.equal('P2PKH');
done();
});
});
});
it('should use BIP45 for 1-of-1 wallet if BIP44 not supported', function(done) {
it('should use BIP45 & P2SH for 1-of-1 wallet if not supported', function(done) {
var walletOpts = {
name: 'my wallet',
m: 1,
@ -1185,22 +1201,26 @@ describe('Wallet service', function() {
server.storage.fetchWallet(wid, function(err, wallet) {
should.not.exist(err);
wallet.derivationStrategy.should.equal('BIP45');
wallet.addressType.should.equal('P2SH');
done();
});
});
});
it('should always use BIP45 for shared wallets', function(done) {
it('should always use BIP45 & P2SH for shared wallets', function(done) {
var walletOpts = {
name: 'my wallet',
m: 2,
n: 3,
pubKey: TestData.keyPair.pub,
supportBIP44: true,
supportP2PKH: true,
};
server.createWallet(walletOpts, function(err, wid) {
should.not.exist(err);
server.storage.fetchWallet(wid, function(err, wallet) {
should.not.exist(err);
wallet.derivationStrategy.should.equal('BIP45');
wallet.addressType.should.equal('P2SH');
done();
});
});
@ -1396,7 +1416,7 @@ describe('Wallet service', function() {
});
});
describe('1-of-1 (BIP44)', function() {
describe('1-of-1 (BIP44 & P2PKH)', function() {
beforeEach(function(done) {
helpers.createAndJoinWallet(1, 1, function(s, w) {
server = s;
@ -1412,7 +1432,7 @@ describe('Wallet service', function() {
should.exist(address);
address.walletId.should.equal(wallet.id);
address.network.should.equal('livenet');
address.address.should.equal('3J4J9nkFpzQjUGDh5hLKMKztFSPWMKejKE');
address.address.should.equal('1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG');
address.isChange.should.be.false;
address.path.should.equal('m/0/0');
server.getNotifications({}, function(err, notifications) {
@ -2797,18 +2817,20 @@ describe('Wallet service', function() {
});
describe('#signTx', function() {
describe('1-1', function() {
describe('1-of-1 (BIP44 & P2PKH)', function() {
var server, wallet, txid;
beforeEach(function(done) {
helpers.createAndJoinWallet(1, 1, function(s, w) {
server = s;
wallet = w;
helpers.stubUtxos(server, wallet, _.range(1, 9), function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 20, TestData.copayers[0].privKey_1H_0);
helpers.stubUtxos(server, wallet, [1, 2], function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 2.5, TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts, function(err, tx) {
should.not.exist(err);
should.exist(tx);
tx.derivationStrategy.should.equal('BIP44');
tx.addressType.should.equal('P2PKH');
txid = tx.id;
done();
});
@ -2842,10 +2864,9 @@ describe('Wallet service', function() {
});
});
});
});
describe('Multisign 2-3', function() {
describe('Multisig', function() {
var server, wallet, txid;
beforeEach(function(done) {
@ -4358,7 +4379,7 @@ describe('Wallet service', function() {
var server, wallet;
var scanConfigOld = WalletService.SCAN_CONFIG;
describe('1-of-1 wallet (BIP44)', function() {
describe('1-of-1 wallet (BIP44 & P2PKH)', function() {
beforeEach(function(done) {
this.timeout(5000);
WalletService.SCAN_CONFIG.scanWindow = 2;
@ -4376,9 +4397,9 @@ describe('Wallet service', function() {
it('should scan main addresses', function(done) {
helpers.stubAddressActivity(
['3J4J9nkFpzQjUGDh5hLKMKztFSPWMKejKE', // m/0/0
'384JHSf9kVBs3yXsPwCzEScRs395u8hwxj', // m/0/2
'3NgXBiMQvwcRU8khVoPFJ6gsbGg9ZYrRzH', // m/1/0
['1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG', // m/0/0
'1GdXraZ1gtoVAvBh49D4hK9xLm6SKgesoE', // m/0/2
'1FUzgKcyPJsYwDLUEVJYeE2N3KVaoxTjGS', // m/1/0
]);
var expectedPaths = [
'm/0/0',
@ -4562,7 +4583,9 @@ describe('Wallet service', function() {
WalletService.SCAN_CONFIG.scanWindow = 2;
WalletService.SCAN_CONFIG.derivationDelay = 0;
helpers.createAndJoinWallet(1, 1, function(s, w) {
helpers.createAndJoinWallet(1, 1, {
supportP2PKH: false
}, function(s, w) {
server = s;
wallet = w;
done();

Loading…
Cancel
Save