From 2677b0eecd5ff8f03a661936da813aa845443237 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 28 Feb 2016 22:44:02 -0800 Subject: [PATCH] wallet refactoring. --- lib/bcoin/address.js | 23 +++++++++---------- lib/bcoin/block.js | 54 +------------------------------------------- lib/bcoin/chain.js | 11 ++++----- lib/bcoin/input.js | 4 ++-- lib/bcoin/pool.js | 2 +- lib/bcoin/tx.js | 5 ---- lib/bcoin/wallet.js | 36 ++++++++++++++++++++--------- test/wallet-test.js | 49 ++++++++++++++++++++++++---------------- 8 files changed, 75 insertions(+), 109 deletions(-) diff --git a/lib/bcoin/address.js b/lib/bcoin/address.js index 177160a9..9cb90260 100644 --- a/lib/bcoin/address.js +++ b/lib/bcoin/address.js @@ -42,6 +42,7 @@ function Address(options) { this.keys = []; this.m = options.m || 1; this.n = options.n || 1; + this.witness = options.witness || false; if (this.n > 1) this.type = 'multisig'; @@ -60,10 +61,6 @@ function Address(options) { utils.inherits(Address, EventEmitter); -Address.prototype.__defineGetter__('balance', function() { - return this.getBalance(); -}); - Address.prototype.getID = function getID() { return this.getKeyAddress(); }; @@ -142,7 +139,7 @@ Address.prototype.getScript = function getScript() { redeem = bcoin.script.createMultisig(this.keys, this.m, this.n); redeem = bcoin.script.encode(redeem); - if (this.options.program) { + if (this.witness) { if (redeem.length > 10000) throw new Error('Redeem script too large (10000 byte limit).'); } else { @@ -158,7 +155,7 @@ Address.prototype.getScript = function getScript() { Address.prototype.getProgram = function getProgram() { var program; - if (!this.options.program) + if (!this.witness) return; if (this._program) @@ -169,7 +166,7 @@ Address.prototype.getProgram = function getProgram() { 0, Address.hash160(this.getPublicKey())); } else if (this.type === 'multisig') { program = bcoin.script.createWitnessProgram( - 0, utils.sha256(this.getScript())); + 0, Address.sha256(this.getScript())); } assert(program); @@ -180,7 +177,7 @@ Address.prototype.getProgram = function getProgram() { }; Address.prototype.getProgramHash = function getProgramHash() { - if (!this.options.program) + if (!this.witness) return; if (this._programHash) @@ -192,7 +189,7 @@ Address.prototype.getProgramHash = function getProgramHash() { }; Address.prototype.getProgramAddress = function getProgramAddress() { - if (!this.options.program) + if (!this.witness) return; if (this._programAddress) @@ -238,7 +235,7 @@ Address.prototype.getScriptAddress = function getScriptAddress() { if (this._scriptAddress) return this._scriptAddress; - if (this.options.program) + if (this.witness) this._scriptAddress = Address.compileHash(this.getScriptHash256(), 'witnessscripthash'); else this._scriptAddress = Address.compileHash(this.getScriptHash160(), 'scripthash'); @@ -263,7 +260,7 @@ Address.prototype.getKeyAddress = function getKeyAddress() { if (this._address) return this._address; - if (this.options.program) + if (this.witness) this._address = Address.compileHash(this.getKeyHash(), 'witnesspubkeyhash'); else this._address = Address.compileHash(this.getKeyHash(), 'pubkeyhash'); @@ -294,7 +291,7 @@ Address.prototype._getAddressMap = function _getAddressMap() { if (this.type === 'multisig') this.addressMap[this.getScriptAddress()] = true; - if (this.options.program) + if (this.witness) this.addressMap[this.getProgramAddress()] = true; return this.addressMap; @@ -660,6 +657,7 @@ Address.prototype.toJSON = function toJSON(passphrase) { address: this.getAddress(), key: key.toJSON(passphrase), type: this.type, + witness: this.witness, redeem: this.redeem ? utils.toHex(this.redeem) : null, keys: this.keys.map(utils.toBase58), m: this.m, @@ -684,6 +682,7 @@ Address.fromJSON = function fromJSON(json, passphrase) { path: json.path, key: bcoin.keypair.fromJSON(json.key, passphrase), type: json.type, + witness: json.witness, redeem: json.redeem ? new Buffer(json.redeem, 'hex') : null, keys: json.keys.map(utils.fromBase58), m: json.m, diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index b34ac88f..8b2f316b 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -259,64 +259,12 @@ Block.reward = function reward(height) { if (halvings >= 64) return new bn(0); - reward = new bn(50).mul(constants.coin); + reward = new bn(5000000000); reward.iushrn(halvings); return reward; }; -Block.prototype._getReward = function _getReward() { - var reward, base, fee, height; - - if (this._reward) - return this._reward; - - base = Block.reward(this.height); - - if (this.height === -1) { - return this._reward = { - fee: new bn(0), - reward: base, - base: base - }; - } - - reward = this.txs[0].outputs.reduce(function(total, output) { - total.iadd(output.value); - return total; - }, new bn(0)); - - fee = reward.sub(base); - - return this._reward = { - fee: fee, - reward: reward, - base: base - }; -}; - -Block.prototype.getBaseReward = function getBaseReward() { - return this._getReward().base; -}; - -Block.prototype.getReward = function getReward() { - return this._getReward().reward; -}; - -Block.prototype.getFee = function getFee() { - return this._getReward().fee; -}; - -Block.prototype.getCoinbase = function getCoinbase() { - var tx; - - tx = this.txs[0]; - if (!tx || !tx.isCoinbase()) - return; - - return tx; -}; - Block.prototype.inspect = function inspect() { return { type: this.type, diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 367cafdf..b5d737aa 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -668,6 +668,11 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac tx = block.txs[i]; hash = tx.hash('hex'); + if (tx.getOutputValue().cmp(tx.getInputValue()) > 0) { + utils.debug('TX is spending funds it does not have: %s', tx.rhash); + return false; + } + for (j = 0; j < tx.inputs.length; j++) { input = tx.inputs[j]; @@ -1853,18 +1858,12 @@ Chain.prototype.getSize = function getSize() { return this.db.getSize(); }; -// Legacy -Chain.prototype.size = Chain.prototype.getSize; - Chain.prototype.getCurrentTarget = function getCurrentTarget() { if (!this.tip) return utils.toCompact(network.powLimit); return this.getTarget(this.tip); }; -// Legacy -Chain.prototype.currentTarget = Chain.prototype.getCurrentTarget; - Chain.prototype.getTarget = function getTarget(last, block) { var powLimit = utils.toCompact(network.powLimit); var ts, first, i; diff --git a/lib/bcoin/input.js b/lib/bcoin/input.js index 93b3b19f..f7d4646b 100644 --- a/lib/bcoin/input.js +++ b/lib/bcoin/input.js @@ -235,8 +235,8 @@ Input.prototype.inspect = function inspect() { height: -1, value: '0.0', script: '', - hash: utils.toHex(constants.zeroHash), - index: 0, + hash: this.prevout.hash, + index: this.prevout.index, spent: false, address: null }; diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index ef9f131a..47f7edb7 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -1233,7 +1233,7 @@ Pool.prototype.addWallet = function addWallet(wallet, callback) { // search, because search could add TS // to pending TXs, thus making them // confirmed. - wallet.pending().forEach(function(tx) { + wallet.getPending().forEach(function(tx) { self.sendTX(tx); }); diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index 8bc82c7c..c16ee965 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -411,11 +411,6 @@ TX.prototype.verify = function verify(index, force, flags) { if (this.isCoinbase()) return true; - if (this.getOutputValue().cmp(this.getInputValue()) > 0) { - utils.debug('TX is spending funds it does not have.'); - return false; - } - return this.inputs.every(function(input, i) { if (index != null && i !== index) return true; diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index f91bb0fe..555f4f2d 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -51,7 +51,7 @@ function Wallet(options) { this.labelMap = {}; this.change = []; this.receive = []; - this.program = options.program || false; + this.witness = options.witness || false; this.accountIndex = options.accountIndex || 0; this.receiveDepth = options.receiveDepth || 1; @@ -357,7 +357,7 @@ Wallet.prototype.deriveAddress = function deriveAddress(change, index) { index: data.index, path: data.path, type: this.type, - program: this.program, + witness: this.witness, m: this.m, n: this.n, keys: [], @@ -377,7 +377,7 @@ Wallet.prototype.deriveAddress = function deriveAddress(change, index) { if (this.type === 'multisig') this.addressMap[address.getScriptAddress()] = data.path; - if (this.program) + if (this.witness) this.addressMap[address.getProgramAddress()] = data.path; this.emit('add address', address); @@ -821,12 +821,6 @@ Wallet.prototype.getBalance = function getBalance(address) { return this.tx.getBalance(address); }; -// Legacy -Wallet.prototype.all = Wallet.prototype.getAll; -Wallet.prototype.unspent = Wallet.prototype.getUnspent; -Wallet.prototype.pending = Wallet.prototype.getPending; -Wallet.prototype.balance = Wallet.prototype.getBalance; - Wallet.prototype.__defineGetter__('script', function() { return this.getScript(); }); @@ -835,10 +829,30 @@ Wallet.prototype.__defineGetter__('scriptHash', function() { return this.getScriptHash(); }); +Wallet.prototype.__defineGetter__('scriptHash160', function() { + return this.getScriptHash160(); +}); + +Wallet.prototype.__defineGetter__('scriptHash256', function() { + return this.getScriptHash256(); +}); + Wallet.prototype.__defineGetter__('scriptAddress', function() { return this.getScriptAddress(); }); +// Wallet.prototype.__defineGetter__('program', function() { +// return this.getProgram(); +// }); + +Wallet.prototype.__defineGetter__('programHash', function() { + return this.getProgramHash(); +}); + +Wallet.prototype.__defineGetter__('programAddress', function() { + return this.getProgramAddress(); +}); + Wallet.prototype.__defineGetter__('privateKey', function() { return this.getPrivateKey(); }); @@ -872,7 +886,7 @@ Wallet.prototype.toJSON = function toJSON(noPool) { type: this.type, m: this.m, n: this.n, - program: this.program, + witness: this.witness, derivation: this.derivation, copayBIP45: this.copayBIP45, accountIndex: this.accountIndex, @@ -904,7 +918,7 @@ Wallet._fromJSON = function _fromJSON(json, passphrase) { type: json.type, m: json.m, n: json.n, - program: json.program, + witness: json.witness, derivation: json.derivation, copayBIP45: json.copayBIP45, accountIndex: json.accountIndex, diff --git a/test/wallet-test.js b/test/wallet-test.js index 2030ecfb..60e86719 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -38,13 +38,18 @@ describe('Wallet', function() { assert(!bcoin.address.validate('1KQ1wMNwXHUYj1nv2xzsRcKUH8gVFpTFUc')); }); - function p2pkh(program, bullshitNesting) { + function p2pkh(witness, bullshitNesting) { var flags = bcoin.protocol.constants.flags.STANDARD_VERIFY_FLAGS; - if (program) + if (witness) flags |= bcoin.protocol.constants.flags.VERIFY_WITNESS; - var w = bcoin.wallet({ program: program }); + var w = bcoin.wallet({ witness: witness }); + + if (witness) + assert(bcoin.address.parse(w.getAddress()).type === 'witnesspubkeyhash'); + else + assert(bcoin.address.parse(w.getAddress()).type === 'pubkeyhash'); // Input transcation var src = bcoin.mtx({ @@ -168,22 +173,22 @@ describe('Wallet', function() { w.addTX(fake); w.addTX(t4); - assert.equal(w.balance().toString(10), '22500'); + assert.equal(w.getBalance().toString(10), '22500'); w.addTX(t1); - assert.equal(w.balance().toString(10), '73000'); + assert.equal(w.getBalance().toString(10), '73000'); w.addTX(t2); - assert.equal(w.balance().toString(10), '47000'); + assert.equal(w.getBalance().toString(10), '47000'); w.addTX(t3); - assert.equal(w.balance().toString(10), '22000'); + assert.equal(w.getBalance().toString(10), '22000'); w.addTX(f1); - assert.equal(w.balance().toString(10), '11000'); - assert(w.all().some(function(tx) { + assert.equal(w.getBalance().toString(10), '11000'); + assert(w.getAll().some(function(tx) { return tx.hash('hex') === f1.hash('hex'); })); var w2 = bcoin.wallet.fromJSON(w.toJSON()); - assert.equal(w2.balance().toString(10), '11000'); - assert(w2.all().some(function(tx) { + assert.equal(w2.getBalance().toString(10), '11000'); + assert(w2.getAll().some(function(tx) { return tx.hash('hex') === f1.hash('hex'); })); }); @@ -246,8 +251,8 @@ describe('Wallet', function() { var cost = tx.getOutputValue(); var total = cost.add(new bn(constants.tx.minFee)); - var unspent1 = w1.unspent(); - var unspent2 = w2.unspent(); + var unspent1 = w1.getUnspent(); + var unspent2 = w2.getUnspent(); // Add dummy output (for `left`) to calculate maximum TX size tx.addOutput(w1, new bn(0)); @@ -288,15 +293,15 @@ describe('Wallet', function() { cb(); }); - function multisig(program, bullshitNesting, cb) { + function multisig(witness, bullshitNesting, cb) { var flags = bcoin.protocol.constants.flags.STANDARD_VERIFY_FLAGS; - if (program) + if (witness) flags |= bcoin.protocol.constants.flags.VERIFY_WITNESS; // Create 3 2-of-3 wallets with our pubkeys as "shared keys" var w1 = bcoin.wallet({ - program: program, + witness: witness, derivation: 'bip44', type: 'multisig', m: 2, @@ -304,7 +309,7 @@ describe('Wallet', function() { }); var w2 = bcoin.wallet({ - program: program, + witness: witness, derivation: 'bip44', type: 'multisig', m: 2, @@ -312,7 +317,7 @@ describe('Wallet', function() { }); var w3 = bcoin.wallet({ - program: program, + witness: witness, derivation: 'bip44', type: 'multisig', m: 2, @@ -332,6 +337,12 @@ describe('Wallet', function() { // Our p2sh address var addr = w1.getAddress(); + + if (witness) + assert(bcoin.address.parse(addr).type === 'witnessscripthash'); + else + assert(bcoin.address.parse(addr).type === 'scripthash'); + assert.equal(w1.getAddress(), addr); assert.equal(w2.getAddress(), addr); assert.equal(w3.getAddress(), addr); @@ -410,7 +421,7 @@ describe('Wallet', function() { assert.equal(w2.changeAddress.getAddress(), change); assert.equal(w3.changeAddress.getAddress(), change); - if (program) + if (witness) send.inputs[0].witness[2] = new Buffer([]); else send.inputs[0].script[2] = 0;