tests. asserts. subtractFee.
This commit is contained in:
parent
8a16cefe30
commit
8b262a7ff9
@ -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()
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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()
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -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]);
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user