tests. asserts. subtractFee.

This commit is contained in:
Christopher Jeffrey 2016-06-20 16:49:09 -07:00
parent 8a16cefe30
commit 8b262a7ff9
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
7 changed files with 152 additions and 44 deletions

View File

@ -477,7 +477,8 @@ Input.prototype.toJSON = function toJSON() {
coin: this.coin ? this.coin.toJSON() : null,
script: this.script.toJSON(),
witness: this.witness.toJSON(),
sequence: this.sequence
sequence: this.sequence,
address: this.getAddress()
};
};

View File

@ -1091,35 +1091,6 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
// How much money is left after filling outputs.
change = tx.getInputValue() - total();
// Attempt to subtract fee.
if (options.subtractFee != null) {
if (typeof options.subtractFee === 'number') {
i = options.subtractFee;
output = tx.outputs[i];
if (!output)
throw new Error('Subtraction index does not exist.');
min = fee + output.getDustThreshold();
if (output.value < min)
throw new Error('Could not subtract fee.');
output.value -= fee;
} else {
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
min = fee + output.getDustThreshold();
if (output.value >= min) {
output.value -= fee;
break;
}
}
if (i === tx.outputs.length)
throw new Error('Could not subtract fee.');
}
}
// Return necessary inputs and change.
return {
coins: chosen,
@ -1129,6 +1100,44 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
};
};
/**
* Attempt to subtract a fee from outputs.
* @param {Amount} fee
* @param {Number?} index
*/
MTX.prototype.subtractFee = function subtractFee(fee, index) {
var i, min, output;
if (typeof index === 'number') {
output = this.outputs[index];
if (!output)
throw new Error('Subtraction index does not exist.');
min = fee + output.getDustThreshold();
if (output.value < min)
throw new Error('Could not subtract fee.');
output.value -= fee;
return;
}
for (i = 0; i < this.outputs.length; i++) {
output = this.outputs[i];
min = fee + output.getDustThreshold();
if (output.value >= min) {
output.value -= fee;
break;
}
}
if (i === this.outputs.length)
throw new Error('Could not subtract fee.');
};
/**
* Select coins and fill the inputs.
* @param {Coin[]} coins
@ -1164,6 +1173,10 @@ MTX.prototype.fill = function fill(coins, options) {
for (i = 0; i < result.coins.length; i++)
this.addInput(result.coins[i]);
// Attempt to subtract fee.
if (options.subtractFee || options.subtractFee === 0)
this.subtractFee(result.fee, options.subtractFee);
// Add a change output.
this.addOutput({
address: changeAddress,

View File

@ -166,7 +166,8 @@ Output.prototype.inspect = function inspect() {
Output.prototype.toJSON = function toJSON() {
return {
value: utils.btc(this.value),
script: this.script.toJSON()
script: this.script.toJSON(),
address: this.getAddress()
};
};

View File

@ -628,7 +628,7 @@ Framer.tx = function _tx(tx, writer) {
*/
Framer.witnessTX = function _witnessTX(tx, writer) {
return tx.toRaw(writer);
return tx.toWitness(writer);
};
/**
@ -651,7 +651,7 @@ Framer.block = function _block(block, writer) {
*/
Framer.witnessBlock = function _witnessBlock(block, writer) {
return block.toRaw(writer);
return block.toWitness(writer);
};
/**

View File

@ -2422,7 +2422,7 @@ Script.isCode = function isCode(raw) {
*/
Script.fromPubkey = function fromPubkey(key) {
assert(key.length >= 33);
assert(Buffer.isBuffer(key) && key.length >= 33);
return Script.fromArray([key, opcodes.OP_CHECKSIG]);
};
@ -2433,7 +2433,7 @@ Script.fromPubkey = function fromPubkey(key) {
*/
Script.fromPubkeyhash = function fromPubkeyhash(hash) {
assert(hash.length === 20);
assert(Buffer.isBuffer(hash) && hash.length === 20);
return Script.fromArray([
opcodes.OP_DUP,
opcodes.OP_HASH160,
@ -2455,6 +2455,8 @@ Script.fromMultisig = function fromMultisig(m, n, keys) {
var code = [];
var i;
assert(utils.isNumber(m) && utils.isNumber(n));
assert(Array.isArray(keys));
assert(keys.length === n, '`n` keys are required for multisig.');
assert(m >= 1 && m <= n);
assert(n >= 1 && n <= 15);
@ -2479,7 +2481,7 @@ Script.fromMultisig = function fromMultisig(m, n, keys) {
*/
Script.fromScripthash = function fromScripthash(hash) {
assert(hash.length === 20);
assert(Buffer.isBuffer(hash) && hash.length === 20);
return Script.fromArray([
opcodes.OP_HASH160,
hash,
@ -2510,8 +2512,8 @@ Script.fromNulldata = function fromNulldata(flags) {
*/
Script.fromProgram = function fromProgram(version, data) {
assert(typeof version === 'number' && version >= 0 && version <= 16);
assert(data.length >= 2 && data.length <= 32);
assert(utils.isNumber(version) && version >= 0 && version <= 16);
assert(Buffer.isBuffer(data) && data.length >= 2 && data.length <= 40);
return Script.fromArray([version === 0 ? 0 : version + 0x50, data]);
};

View File

@ -57,6 +57,7 @@ function TX(options) {
this.inputs = [];
this.outputs = [];
this.locktime = 0;
this.ts = 0;
this.block = null;
this.index = -1;
@ -100,7 +101,15 @@ TX.prototype.fromOptions = function fromOptions(options) {
this.version = options.version;
this.flag = options.flag;
for (i = 0; i < options.inputs.length; i++)
this.inputs.push(new bcoin.input(options.inputs[i]));
for (i = 0; i < options.outputs.length; i++)
this.outputs.push(new bcoin.output(options.outputs[i]));
this.locktime = options.locktime;
this.ts = options.ts || 0;
this.block = options.block || null;
this.index = options.index != null
@ -121,12 +130,6 @@ TX.prototype.fromOptions = function fromOptions(options) {
? options._witnessSize
: null;
for (i = 0; i < options.inputs.length; i++)
this.inputs.push(new bcoin.input(options.inputs[i]));
for (i = 0; i < options.outputs.length; i++)
this.outputs.push(new bcoin.output(options.outputs[i]));
return this;
};
@ -1890,6 +1893,8 @@ TX.prototype.toJSON = function toJSON() {
ps: this.ps,
index: this.index,
changeIndex: this.changeIndex || -1,
fee: utils.btc(this.getFee()),
confirmations: this.getConfirmations(),
version: this.version,
flag: this.flag,
inputs: this.inputs.map(function(input) {
@ -2286,8 +2291,10 @@ TX.fromExtended = function fromExtended(data, saveCoins, enc) {
enc = saveCoins;
saveCoins = false;
}
if (typeof data === 'string')
data = new Buffer(data, enc);
return new TX().fromExtended(data, saveCoins);
};

View File

@ -903,6 +903,90 @@ describe('Wallet', function() {
});
});
it('should fill tx with inputs with subtract fee', function(cb) {
walletdb.create(function(err, w1) {
assert.ifError(err);
walletdb.create(function(err, w2) {
assert.ifError(err);
// Coinbase
var t1 = bcoin.mtx()
.addOutput(w1, 5460)
.addOutput(w1, 5460)
.addOutput(w1, 5460)
.addOutput(w1, 5460);
t1.addInput(dummyInput);
walletdb.addTX(t1, function(err) {
assert.ifError(err);
// Create new transaction
var t2 = bcoin.mtx().addOutput(w2, 21840);
w1.fill(t2, { rate: 10000, round: true, subtractFee: true }, function(err) {
assert.ifError(err);
w1.sign(t2, function(err) {
assert.ifError(err);
assert(t2.verify());
assert.equal(t2.getInputValue(), 5460 * 4);
assert.equal(t2.getOutputValue(), 21840 - 10000);
assert.equal(t2.getFee(), 10000);
cb();
});
});
});
});
});
});
it('should fill tx with inputs with subtract fee with create tx', function(cb) {
walletdb.create(function(err, w1) {
assert.ifError(err);
walletdb.create(function(err, w2) {
assert.ifError(err);
// Coinbase
var t1 = bcoin.mtx()
.addOutput(w1, 5460)
.addOutput(w1, 5460)
.addOutput(w1, 5460)
.addOutput(w1, 5460);
t1.addInput(dummyInput);
walletdb.addTX(t1, function(err) {
assert.ifError(err);
var options = {
subtractFee: true,
rate: 10000,
round: true,
outputs: [{ address: w2.getAddress(), value: 21840 }]
};
// Create new transaction
w1.createTX(options, function(err, t2) {
assert.ifError(err);
w1.sign(t2, function(err) {
assert.ifError(err);
assert(t2.verify());
assert.equal(t2.getInputValue(), 5460 * 4);
assert.equal(t2.getOutputValue(), 21840 - 10000);
assert.equal(t2.getFee(), 10000);
cb();
});
});
});
});
});
});
it('should cleanup', function(cb) {
constants.tx.COINBASE_MATURITY = 100;
cb();