From 97671abfdcdd82ddf835c3b1b41347cf84a77009 Mon Sep 17 00:00:00 2001 From: eordano Date: Tue, 24 Feb 2015 16:12:46 -0300 Subject: [PATCH 1/4] Add more docs on serialization checks --- docs/transaction.md | 20 +++++++++++++++++--- lib/transaction/transaction.js | 31 +++++++++++++++++-------------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/docs/transaction.md b/docs/transaction.md index 0f17c8e..e8851b3 100644 --- a/docs/transaction.md +++ b/docs/transaction.md @@ -142,13 +142,27 @@ There are a series of methods used for serialization: * `toObject`: Returns a plain javascript object with no methods and enough information to fully restore the state of this transaction. Using other serialization methods (except for `toJSON`) will cause a some information to be lost. * `toJSON`: Returns a string with a JSON-encoded version of the output for `toObject`. * `toString` or `uncheckedSerialize`: Returns an hexadecimal serialization of the transaction, in the [serialization format for bitcoin](https://bitcoin.org/en/developer-reference#raw-transaction-format). -* `serialize`: Does a series of checks before serializing the transaction: - - Check that the fee to be used is not very small or very large - - Check for dust outputs +* `serialize`: Does a series of checks before serializing the transaction * `inspect`: Returns a string with some information about the transaction (currently a string formated as ``, that only shows the serialized value of the transaction. * `toBuffer`: Serializes the transaction for sending over the wire in the bitcoin network * `toBufferWriter`: Uses an already existing BufferWriter to copy over the serialized transaction +## Serialization Checks + +When serializing, the Bitcore library performs a series of checks. These can be disabled by providing an object to the `serialize` method with the checks that you'll like to skip. + +* `disableLargeFees` avoids checking that the fee is no more than `Transaction.FEE_PER_KB * Transaction.FEE_SECURITY_MARGIN * size_in_kb`. +* `disableSmallFees` avoids checking that the fee is less than `Transaction.FEE_PER_KB * size_in_kb / Transaction.FEE_SECURITY_MARGIN`. +* `disableIsFullySigned` does not check if all inputs are fully signed +* `disableDustOutputs` does not check for dust outputs being generated +* `disableMoreOutputThanInput` avoids checking that the sum of the output amounts is less than or equal to the sum of the amounts for the outputs being spent in the transaction + +These are the current default values in the Bitcore library involved on these checks: + +* `Transaction.FEE_PER_KB`: `10000` (satoshis per kilobyte) +* `Transaction.FEE_SECURITY_MARGIN`: `15` +* `Transaction.DUST_AMOUNT`: 5460 (satoshis) + ## Fee calculation When outputs' value don't sum up to the same amount that inputs, the difference in bitcoins goes to the miner of the block that includes this transaction. The concept of a "change address" usually is associated with this: an output with an address that can be spent by the creator of the transaction. diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 22f4bfa..de7c4b8 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -24,10 +24,6 @@ var PrivateKey = require('../privatekey'); var Block = require('../block'); var BN = require('../crypto/bn'); -var CURRENT_VERSION = 1; -var DEFAULT_NLOCKTIME = 0; -var DEFAULT_SEQNUMBER = 0xFFFFFFFF; - /** * Represents a transaction, a set of inputs and outputs to change ownership of tokens * @@ -62,6 +58,16 @@ function Transaction(serialized) { } } +var CURRENT_VERSION = 1; +var DEFAULT_NLOCKTIME = 0; +var DEFAULT_SEQNUMBER = 0xFFFFFFFF; + +// Minimum amount for an output for it not to be considered a dust output +Transaction.DUST_AMOUNT = 5460; + +// Margin of error to allow fees in the vecinity of the expected value but doesn't allow a big difference +Transaction.FEE_SECURITY_MARGIN = 15; + // max amount of satoshis in circulation Transaction.MAX_MONEY = 21000000 * 1e8; @@ -71,6 +77,13 @@ Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT = 5e8; // Max value for an unsigned 32 bit value Transaction.NLOCKTIME_MAX_VALUE = 4294967295; +// Value used for fee estimation (satoshis per kilobyte) +Transaction.FEE_PER_KB = 10000; + +// Safe upper bound for change address script size in bytes +Transaction.CHANGE_OUTPUT_MAX_SIZE = 20 + 4 + 34 + 4; +Transaction.MAXIMUM_EXTRA_SIZE = 4 + 9 + 9 + 4; + /* Constructors and Serialization */ /** @@ -179,8 +192,6 @@ Transaction.prototype.getSerializationError = function(opts) { } }; -Transaction.FEE_SECURITY_MARGIN = 15; - Transaction.prototype._isFeeTooLarge = function() { var fee = this._getUnspentValue(); var maximumFee = Math.floor(Transaction.FEE_SECURITY_MARGIN * this._estimateFee()); @@ -201,8 +212,6 @@ Transaction.prototype._missingChange = function() { return !this._changeScript; }; -Transaction.DUST_AMOUNT = 5460; - Transaction.prototype._hasDustOutputs = function() { var index, output; for (index in this.outputs) { @@ -712,10 +721,6 @@ Transaction.prototype._clearSignatures = function() { }); }; -Transaction.FEE_PER_KB = 10000; -// Safe upper bound for change address script -Transaction.CHANGE_OUTPUT_MAX_SIZE = 20 + 4 + 34 + 4; - Transaction._estimateFee = function(size, amountAvailable) { var fee = Math.ceil(size / Transaction.FEE_PER_KB); if (amountAvailable > fee) { @@ -724,8 +729,6 @@ Transaction._estimateFee = function(size, amountAvailable) { return Math.ceil(size / 1000) * Transaction.FEE_PER_KB; }; -Transaction.MAXIMUM_EXTRA_SIZE = 4 + 9 + 9 + 4; - Transaction.prototype._estimateSize = function() { var result = Transaction.MAXIMUM_EXTRA_SIZE; _.each(this.inputs, function(input) { From 2f86f323c03eaea1be2523a4833a1e089cf18652 Mon Sep 17 00:00:00 2001 From: eordano Date: Tue, 24 Feb 2015 16:22:41 -0300 Subject: [PATCH 2/4] Add link when throwing a serialization error --- docs/transaction.md | 2 +- lib/transaction/transaction.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/transaction.md b/docs/transaction.md index e8851b3..c7efa6c 100644 --- a/docs/transaction.md +++ b/docs/transaction.md @@ -161,7 +161,7 @@ These are the current default values in the Bitcore library involved on these ch * `Transaction.FEE_PER_KB`: `10000` (satoshis per kilobyte) * `Transaction.FEE_SECURITY_MARGIN`: `15` -* `Transaction.DUST_AMOUNT`: 5460 (satoshis) +* `Transaction.DUST_AMOUNT`: `5460` (satoshis) ## Fee calculation diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index de7c4b8..165486f 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -153,6 +153,8 @@ Transaction.prototype.uncheckedSerialize = Transaction.prototype.toString = func Transaction.prototype.checkedSerialize = function(opts) { var serializationError = this.getSerializationError(opts); if (serializationError) { + serializationError.message += ' Use Transaction#uncheckedSerialize if you want to skip security checks. ' + + 'See http://bitcore.io/guide/transaction.html#Serialization for more info.' throw serializationError; } return this.uncheckedSerialize(); From 1893b1db0e519a8b0e25382b042cc67564cd4384 Mon Sep 17 00:00:00 2001 From: eordano Date: Tue, 24 Feb 2015 17:19:11 -0300 Subject: [PATCH 3/4] Fix capitalization of bitcore on docs --- docs/transaction.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/transaction.md b/docs/transaction.md index c7efa6c..fb098f6 100644 --- a/docs/transaction.md +++ b/docs/transaction.md @@ -149,7 +149,7 @@ There are a series of methods used for serialization: ## Serialization Checks -When serializing, the Bitcore library performs a series of checks. These can be disabled by providing an object to the `serialize` method with the checks that you'll like to skip. +When serializing, the bitcore library performs a series of checks. These can be disabled by providing an object to the `serialize` method with the checks that you'll like to skip. * `disableLargeFees` avoids checking that the fee is no more than `Transaction.FEE_PER_KB * Transaction.FEE_SECURITY_MARGIN * size_in_kb`. * `disableSmallFees` avoids checking that the fee is less than `Transaction.FEE_PER_KB * size_in_kb / Transaction.FEE_SECURITY_MARGIN`. @@ -157,7 +157,7 @@ When serializing, the Bitcore library performs a series of checks. These can be * `disableDustOutputs` does not check for dust outputs being generated * `disableMoreOutputThanInput` avoids checking that the sum of the output amounts is less than or equal to the sum of the amounts for the outputs being spent in the transaction -These are the current default values in the Bitcore library involved on these checks: +These are the current default values in the bitcore library involved on these checks: * `Transaction.FEE_PER_KB`: `10000` (satoshis per kilobyte) * `Transaction.FEE_SECURITY_MARGIN`: `15` From 405f4f43df8fb136c37c0adff6bad744b704f0aa Mon Sep 17 00:00:00 2001 From: eordano Date: Tue, 24 Feb 2015 17:21:11 -0300 Subject: [PATCH 4/4] Update dust amount --- docs/transaction.md | 2 +- lib/transaction/transaction.js | 2 +- test/transaction/transaction.js | 12 +++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/transaction.md b/docs/transaction.md index fb098f6..9dfbe47 100644 --- a/docs/transaction.md +++ b/docs/transaction.md @@ -161,7 +161,7 @@ These are the current default values in the bitcore library involved on these ch * `Transaction.FEE_PER_KB`: `10000` (satoshis per kilobyte) * `Transaction.FEE_SECURITY_MARGIN`: `15` -* `Transaction.DUST_AMOUNT`: `5460` (satoshis) +* `Transaction.DUST_AMOUNT`: `546` (satoshis) ## Fee calculation diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 165486f..163a165 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -63,7 +63,7 @@ var DEFAULT_NLOCKTIME = 0; var DEFAULT_SEQNUMBER = 0xFFFFFFFF; // Minimum amount for an output for it not to be considered a dust output -Transaction.DUST_AMOUNT = 5460; +Transaction.DUST_AMOUNT = 546; // Margin of error to allow fees in the vecinity of the expected value but doesn't allow a big difference Transaction.FEE_SECURITY_MARGIN = 15; diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js index c1195bb..bbccf92 100644 --- a/test/transaction/transaction.js +++ b/test/transaction/transaction.js @@ -322,13 +322,23 @@ describe('Transaction', function() { it('fails if a dust output is created', function() { var transaction = new Transaction() .from(simpleUtxoWith1BTC) - .to(toAddress, 1) + .to(toAddress, 545) .change(changeAddress) .sign(privateKey); expect(function() { return transaction.serialize(); }).to.throw(errors.Transaction.DustOutputs); }); + it('doesn\'t fail if a dust output is not dust', function() { + var transaction = new Transaction() + .from(simpleUtxoWith1BTC) + .to(toAddress, 546) + .change(changeAddress) + .sign(privateKey); + expect(function() { + return transaction.serialize(); + }).to.not.throw(errors.Transaction.DustOutputs); + }); it('doesn\'t fail if a dust output is an op_return', function() { var transaction = new Transaction() .from(simpleUtxoWith1BTC)