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.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,

View File

@ -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,

View File

@ -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;

View File

@ -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
};

View File

@ -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);
});

View File

@ -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;

View File

@ -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,

View File

@ -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;