wallet refactoring.

This commit is contained in:
Christopher Jeffrey 2016-02-28 22:44:02 -08:00
parent 8d0f432c7a
commit 2677b0eecd
8 changed files with 75 additions and 109 deletions

View File

@ -42,6 +42,7 @@ function Address(options) {
this.keys = []; this.keys = [];
this.m = options.m || 1; this.m = options.m || 1;
this.n = options.n || 1; this.n = options.n || 1;
this.witness = options.witness || false;
if (this.n > 1) if (this.n > 1)
this.type = 'multisig'; this.type = 'multisig';
@ -60,10 +61,6 @@ function Address(options) {
utils.inherits(Address, EventEmitter); utils.inherits(Address, EventEmitter);
Address.prototype.__defineGetter__('balance', function() {
return this.getBalance();
});
Address.prototype.getID = function getID() { Address.prototype.getID = function getID() {
return this.getKeyAddress(); 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.createMultisig(this.keys, this.m, this.n);
redeem = bcoin.script.encode(redeem); redeem = bcoin.script.encode(redeem);
if (this.options.program) { if (this.witness) {
if (redeem.length > 10000) if (redeem.length > 10000)
throw new Error('Redeem script too large (10000 byte limit).'); throw new Error('Redeem script too large (10000 byte limit).');
} else { } else {
@ -158,7 +155,7 @@ Address.prototype.getScript = function getScript() {
Address.prototype.getProgram = function getProgram() { Address.prototype.getProgram = function getProgram() {
var program; var program;
if (!this.options.program) if (!this.witness)
return; return;
if (this._program) if (this._program)
@ -169,7 +166,7 @@ Address.prototype.getProgram = function getProgram() {
0, Address.hash160(this.getPublicKey())); 0, Address.hash160(this.getPublicKey()));
} else if (this.type === 'multisig') { } else if (this.type === 'multisig') {
program = bcoin.script.createWitnessProgram( program = bcoin.script.createWitnessProgram(
0, utils.sha256(this.getScript())); 0, Address.sha256(this.getScript()));
} }
assert(program); assert(program);
@ -180,7 +177,7 @@ Address.prototype.getProgram = function getProgram() {
}; };
Address.prototype.getProgramHash = function getProgramHash() { Address.prototype.getProgramHash = function getProgramHash() {
if (!this.options.program) if (!this.witness)
return; return;
if (this._programHash) if (this._programHash)
@ -192,7 +189,7 @@ Address.prototype.getProgramHash = function getProgramHash() {
}; };
Address.prototype.getProgramAddress = function getProgramAddress() { Address.prototype.getProgramAddress = function getProgramAddress() {
if (!this.options.program) if (!this.witness)
return; return;
if (this._programAddress) if (this._programAddress)
@ -238,7 +235,7 @@ Address.prototype.getScriptAddress = function getScriptAddress() {
if (this._scriptAddress) if (this._scriptAddress)
return this._scriptAddress; return this._scriptAddress;
if (this.options.program) if (this.witness)
this._scriptAddress = Address.compileHash(this.getScriptHash256(), 'witnessscripthash'); this._scriptAddress = Address.compileHash(this.getScriptHash256(), 'witnessscripthash');
else else
this._scriptAddress = Address.compileHash(this.getScriptHash160(), 'scripthash'); this._scriptAddress = Address.compileHash(this.getScriptHash160(), 'scripthash');
@ -263,7 +260,7 @@ Address.prototype.getKeyAddress = function getKeyAddress() {
if (this._address) if (this._address)
return this._address; return this._address;
if (this.options.program) if (this.witness)
this._address = Address.compileHash(this.getKeyHash(), 'witnesspubkeyhash'); this._address = Address.compileHash(this.getKeyHash(), 'witnesspubkeyhash');
else else
this._address = Address.compileHash(this.getKeyHash(), 'pubkeyhash'); this._address = Address.compileHash(this.getKeyHash(), 'pubkeyhash');
@ -294,7 +291,7 @@ Address.prototype._getAddressMap = function _getAddressMap() {
if (this.type === 'multisig') if (this.type === 'multisig')
this.addressMap[this.getScriptAddress()] = true; this.addressMap[this.getScriptAddress()] = true;
if (this.options.program) if (this.witness)
this.addressMap[this.getProgramAddress()] = true; this.addressMap[this.getProgramAddress()] = true;
return this.addressMap; return this.addressMap;
@ -660,6 +657,7 @@ Address.prototype.toJSON = function toJSON(passphrase) {
address: this.getAddress(), address: this.getAddress(),
key: key.toJSON(passphrase), key: key.toJSON(passphrase),
type: this.type, type: this.type,
witness: this.witness,
redeem: this.redeem ? utils.toHex(this.redeem) : null, redeem: this.redeem ? utils.toHex(this.redeem) : null,
keys: this.keys.map(utils.toBase58), keys: this.keys.map(utils.toBase58),
m: this.m, m: this.m,
@ -684,6 +682,7 @@ Address.fromJSON = function fromJSON(json, passphrase) {
path: json.path, path: json.path,
key: bcoin.keypair.fromJSON(json.key, passphrase), key: bcoin.keypair.fromJSON(json.key, passphrase),
type: json.type, type: json.type,
witness: json.witness,
redeem: json.redeem ? new Buffer(json.redeem, 'hex') : null, redeem: json.redeem ? new Buffer(json.redeem, 'hex') : null,
keys: json.keys.map(utils.fromBase58), keys: json.keys.map(utils.fromBase58),
m: json.m, m: json.m,

View File

@ -259,64 +259,12 @@ Block.reward = function reward(height) {
if (halvings >= 64) if (halvings >= 64)
return new bn(0); return new bn(0);
reward = new bn(50).mul(constants.coin); reward = new bn(5000000000);
reward.iushrn(halvings); reward.iushrn(halvings);
return reward; 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() { Block.prototype.inspect = function inspect() {
return { return {
type: this.type, type: this.type,

View File

@ -668,6 +668,11 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
tx = block.txs[i]; tx = block.txs[i];
hash = tx.hash('hex'); 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++) { for (j = 0; j < tx.inputs.length; j++) {
input = tx.inputs[j]; input = tx.inputs[j];
@ -1853,18 +1858,12 @@ Chain.prototype.getSize = function getSize() {
return this.db.getSize(); return this.db.getSize();
}; };
// Legacy
Chain.prototype.size = Chain.prototype.getSize;
Chain.prototype.getCurrentTarget = function getCurrentTarget() { Chain.prototype.getCurrentTarget = function getCurrentTarget() {
if (!this.tip) if (!this.tip)
return utils.toCompact(network.powLimit); return utils.toCompact(network.powLimit);
return this.getTarget(this.tip); return this.getTarget(this.tip);
}; };
// Legacy
Chain.prototype.currentTarget = Chain.prototype.getCurrentTarget;
Chain.prototype.getTarget = function getTarget(last, block) { Chain.prototype.getTarget = function getTarget(last, block) {
var powLimit = utils.toCompact(network.powLimit); var powLimit = utils.toCompact(network.powLimit);
var ts, first, i; var ts, first, i;

View File

@ -235,8 +235,8 @@ Input.prototype.inspect = function inspect() {
height: -1, height: -1,
value: '0.0', value: '0.0',
script: '', script: '',
hash: utils.toHex(constants.zeroHash), hash: this.prevout.hash,
index: 0, index: this.prevout.index,
spent: false, spent: false,
address: null address: null
}; };

View File

@ -1233,7 +1233,7 @@ Pool.prototype.addWallet = function addWallet(wallet, callback) {
// search, because search could add TS // search, because search could add TS
// to pending TXs, thus making them // to pending TXs, thus making them
// confirmed. // confirmed.
wallet.pending().forEach(function(tx) { wallet.getPending().forEach(function(tx) {
self.sendTX(tx); self.sendTX(tx);
}); });

View File

@ -411,11 +411,6 @@ TX.prototype.verify = function verify(index, force, flags) {
if (this.isCoinbase()) if (this.isCoinbase())
return true; 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) { return this.inputs.every(function(input, i) {
if (index != null && i !== index) if (index != null && i !== index)
return true; return true;

View File

@ -51,7 +51,7 @@ function Wallet(options) {
this.labelMap = {}; this.labelMap = {};
this.change = []; this.change = [];
this.receive = []; this.receive = [];
this.program = options.program || false; this.witness = options.witness || false;
this.accountIndex = options.accountIndex || 0; this.accountIndex = options.accountIndex || 0;
this.receiveDepth = options.receiveDepth || 1; this.receiveDepth = options.receiveDepth || 1;
@ -357,7 +357,7 @@ Wallet.prototype.deriveAddress = function deriveAddress(change, index) {
index: data.index, index: data.index,
path: data.path, path: data.path,
type: this.type, type: this.type,
program: this.program, witness: this.witness,
m: this.m, m: this.m,
n: this.n, n: this.n,
keys: [], keys: [],
@ -377,7 +377,7 @@ Wallet.prototype.deriveAddress = function deriveAddress(change, index) {
if (this.type === 'multisig') if (this.type === 'multisig')
this.addressMap[address.getScriptAddress()] = data.path; this.addressMap[address.getScriptAddress()] = data.path;
if (this.program) if (this.witness)
this.addressMap[address.getProgramAddress()] = data.path; this.addressMap[address.getProgramAddress()] = data.path;
this.emit('add address', address); this.emit('add address', address);
@ -821,12 +821,6 @@ Wallet.prototype.getBalance = function getBalance(address) {
return this.tx.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() { Wallet.prototype.__defineGetter__('script', function() {
return this.getScript(); return this.getScript();
}); });
@ -835,10 +829,30 @@ Wallet.prototype.__defineGetter__('scriptHash', function() {
return this.getScriptHash(); return this.getScriptHash();
}); });
Wallet.prototype.__defineGetter__('scriptHash160', function() {
return this.getScriptHash160();
});
Wallet.prototype.__defineGetter__('scriptHash256', function() {
return this.getScriptHash256();
});
Wallet.prototype.__defineGetter__('scriptAddress', function() { Wallet.prototype.__defineGetter__('scriptAddress', function() {
return this.getScriptAddress(); 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() { Wallet.prototype.__defineGetter__('privateKey', function() {
return this.getPrivateKey(); return this.getPrivateKey();
}); });
@ -872,7 +886,7 @@ Wallet.prototype.toJSON = function toJSON(noPool) {
type: this.type, type: this.type,
m: this.m, m: this.m,
n: this.n, n: this.n,
program: this.program, witness: this.witness,
derivation: this.derivation, derivation: this.derivation,
copayBIP45: this.copayBIP45, copayBIP45: this.copayBIP45,
accountIndex: this.accountIndex, accountIndex: this.accountIndex,
@ -904,7 +918,7 @@ Wallet._fromJSON = function _fromJSON(json, passphrase) {
type: json.type, type: json.type,
m: json.m, m: json.m,
n: json.n, n: json.n,
program: json.program, witness: json.witness,
derivation: json.derivation, derivation: json.derivation,
copayBIP45: json.copayBIP45, copayBIP45: json.copayBIP45,
accountIndex: json.accountIndex, accountIndex: json.accountIndex,

View File

@ -38,13 +38,18 @@ describe('Wallet', function() {
assert(!bcoin.address.validate('1KQ1wMNwXHUYj1nv2xzsRcKUH8gVFpTFUc')); assert(!bcoin.address.validate('1KQ1wMNwXHUYj1nv2xzsRcKUH8gVFpTFUc'));
}); });
function p2pkh(program, bullshitNesting) { function p2pkh(witness, bullshitNesting) {
var flags = bcoin.protocol.constants.flags.STANDARD_VERIFY_FLAGS; var flags = bcoin.protocol.constants.flags.STANDARD_VERIFY_FLAGS;
if (program) if (witness)
flags |= bcoin.protocol.constants.flags.VERIFY_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 // Input transcation
var src = bcoin.mtx({ var src = bcoin.mtx({
@ -168,22 +173,22 @@ describe('Wallet', function() {
w.addTX(fake); w.addTX(fake);
w.addTX(t4); w.addTX(t4);
assert.equal(w.balance().toString(10), '22500'); assert.equal(w.getBalance().toString(10), '22500');
w.addTX(t1); w.addTX(t1);
assert.equal(w.balance().toString(10), '73000'); assert.equal(w.getBalance().toString(10), '73000');
w.addTX(t2); w.addTX(t2);
assert.equal(w.balance().toString(10), '47000'); assert.equal(w.getBalance().toString(10), '47000');
w.addTX(t3); w.addTX(t3);
assert.equal(w.balance().toString(10), '22000'); assert.equal(w.getBalance().toString(10), '22000');
w.addTX(f1); w.addTX(f1);
assert.equal(w.balance().toString(10), '11000'); assert.equal(w.getBalance().toString(10), '11000');
assert(w.all().some(function(tx) { assert(w.getAll().some(function(tx) {
return tx.hash('hex') === f1.hash('hex'); return tx.hash('hex') === f1.hash('hex');
})); }));
var w2 = bcoin.wallet.fromJSON(w.toJSON()); var w2 = bcoin.wallet.fromJSON(w.toJSON());
assert.equal(w2.balance().toString(10), '11000'); assert.equal(w2.getBalance().toString(10), '11000');
assert(w2.all().some(function(tx) { assert(w2.getAll().some(function(tx) {
return tx.hash('hex') === f1.hash('hex'); return tx.hash('hex') === f1.hash('hex');
})); }));
}); });
@ -246,8 +251,8 @@ describe('Wallet', function() {
var cost = tx.getOutputValue(); var cost = tx.getOutputValue();
var total = cost.add(new bn(constants.tx.minFee)); var total = cost.add(new bn(constants.tx.minFee));
var unspent1 = w1.unspent(); var unspent1 = w1.getUnspent();
var unspent2 = w2.unspent(); var unspent2 = w2.getUnspent();
// Add dummy output (for `left`) to calculate maximum TX size // Add dummy output (for `left`) to calculate maximum TX size
tx.addOutput(w1, new bn(0)); tx.addOutput(w1, new bn(0));
@ -288,15 +293,15 @@ describe('Wallet', function() {
cb(); cb();
}); });
function multisig(program, bullshitNesting, cb) { function multisig(witness, bullshitNesting, cb) {
var flags = bcoin.protocol.constants.flags.STANDARD_VERIFY_FLAGS; var flags = bcoin.protocol.constants.flags.STANDARD_VERIFY_FLAGS;
if (program) if (witness)
flags |= bcoin.protocol.constants.flags.VERIFY_WITNESS; flags |= bcoin.protocol.constants.flags.VERIFY_WITNESS;
// Create 3 2-of-3 wallets with our pubkeys as "shared keys" // Create 3 2-of-3 wallets with our pubkeys as "shared keys"
var w1 = bcoin.wallet({ var w1 = bcoin.wallet({
program: program, witness: witness,
derivation: 'bip44', derivation: 'bip44',
type: 'multisig', type: 'multisig',
m: 2, m: 2,
@ -304,7 +309,7 @@ describe('Wallet', function() {
}); });
var w2 = bcoin.wallet({ var w2 = bcoin.wallet({
program: program, witness: witness,
derivation: 'bip44', derivation: 'bip44',
type: 'multisig', type: 'multisig',
m: 2, m: 2,
@ -312,7 +317,7 @@ describe('Wallet', function() {
}); });
var w3 = bcoin.wallet({ var w3 = bcoin.wallet({
program: program, witness: witness,
derivation: 'bip44', derivation: 'bip44',
type: 'multisig', type: 'multisig',
m: 2, m: 2,
@ -332,6 +337,12 @@ describe('Wallet', function() {
// Our p2sh address // Our p2sh address
var addr = w1.getAddress(); 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(w1.getAddress(), addr);
assert.equal(w2.getAddress(), addr); assert.equal(w2.getAddress(), addr);
assert.equal(w3.getAddress(), addr); assert.equal(w3.getAddress(), addr);
@ -410,7 +421,7 @@ describe('Wallet', function() {
assert.equal(w2.changeAddress.getAddress(), change); assert.equal(w2.changeAddress.getAddress(), change);
assert.equal(w3.changeAddress.getAddress(), change); assert.equal(w3.changeAddress.getAddress(), change);
if (program) if (witness)
send.inputs[0].witness[2] = new Buffer([]); send.inputs[0].witness[2] = new Buffer([]);
else else
send.inputs[0].script[2] = 0; send.inputs[0].script[2] = 0;