diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -8,3 +8,7 @@ - Improve SHA256 performance using SSE4.1, AVX2 and/or SHA if available. - Add a mode argument to the `getmemoryinfo` RPC call to query `malloc_info` from the system if available. - Disable safe mode by default + - Update fee calculation to add 1790 effective bytes per transaction output in excess of inputs. + Refund 1790 bytes worth of minimum fee per input in excess of outputs to a minimum of + 10 + 34 * (number of utxos) + - Drop min relay fee to 100sat/kb diff --git a/src/policy/policy.h b/src/policy/policy.h --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -29,7 +29,7 @@ * Default for -blockmintxfee, which sets the minimum feerate for a transaction * in blocks created by mining code. */ -static const Amount DEFAULT_BLOCK_MIN_TX_FEE_PER_KB(1000 * SATOSHI); +static const Amount DEFAULT_BLOCK_MIN_TX_FEE_PER_KB(100 * SATOSHI); /** * The maximum size for transactions we're willing to relay/mine. */ diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -115,7 +115,22 @@ } size_t CTransaction::GetBillableSize() const { - return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); + + size_t nTxSize = GetTotalSize(), inputs = vin.size(), outputs = vout.size(); + + // 179 bytes is the minimum size it would take to spend any outputs which + // are created. We want to change in advance of spending them to + // incentivize keeping your UTXO set reasonbly sized. + int64_t modSize = + int64_t(nTxSize) + (int64_t(outputs) - int64_t(inputs)) * 1790; + + // Note: It is impossible to generate a negative number above in any real + // world situation. This is because the inputs have a least 179 byte + // each. However, it is possible to have shorter scriptSigs than 179 + // bytes. Therefore, we include a minimum of 10 bytes + 34 * vouts. + nTxSize = std::max(int64_t(outputs * 34 + 10), modSize); + + return nTxSize; } unsigned int CTransaction::GetTotalSize() const { diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -800,7 +800,7 @@ auto txSize = tx.GetTotalSize(); BOOST_CHECK(txBillableSize > 0); if (inputs > outputs) { - BOOST_CHECK(txBillableSize <= txSize); + BOOST_CHECK(txBillableSize < txSize); } else { BOOST_CHECK(txBillableSize >= txSize); } diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -782,17 +782,20 @@ nNoLimit, nNoLimit, dummy); uint64_t nCountCheck = setAncestors.size() + 1; uint64_t nSizeCheck = it->GetTxSize(); + uint64_t nBillableSizeCheck = it->GetTxBillableSize(); Amount nFeesCheck = it->GetModifiedFee(); int64_t nSigOpCheck = it->GetSigOpCount(); for (txiter ancestorIt : setAncestors) { nSizeCheck += ancestorIt->GetTxSize(); + nBillableSizeCheck += ancestorIt->GetTxBillableSize(); nFeesCheck += ancestorIt->GetModifiedFee(); nSigOpCheck += ancestorIt->GetSigOpCount(); } assert(it->GetCountWithAncestors() == nCountCheck); assert(it->GetSizeWithAncestors() == nSizeCheck); + assert(it->GetBillableSizeWithAncestors() == nBillableSizeCheck); assert(it->GetSigOpCountWithAncestors() == nSigOpCheck); assert(it->GetModFeesWithAncestors() == nFeesCheck); diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -59,7 +59,7 @@ /** Default for DEFAULT_WHITELISTFORCERELAY. */ static const bool DEFAULT_WHITELISTFORCERELAY = true; /** Default for -minrelaytxfee, minimum relay fee for transactions */ -static const Amount DEFAULT_MIN_RELAY_TX_FEE_PER_KB(1000 * SATOSHI); +static const Amount DEFAULT_MIN_RELAY_TX_FEE_PER_KB(100 * SATOSHI); /** Default for -excessutxocharge for transactions transactions */ static const Amount DEFAULT_UTXO_FEE = Amount::zero(); //! -maxtxfee default diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -152,7 +152,7 @@ inputs = [{'txid': utx['txid'], 'vout': utx['vout']}] outputs = { - self.nodes[0].getnewaddress(): Decimal(5.0) - fee - feeTolerance} + self.nodes[0].getnewaddress(): satoshi_round(Decimal(5.0) - fee - feeTolerance)} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -406,7 +406,17 @@ """ Returns the size used for billing the against the transaction """ - return len(self.serialize()) + # We need a heuristic for unsigned transactions as they do not yet + # include the pubkey hash, or the signature. + tx_size = 10 # base transaction overhead + for vin in self.vin: + # Max of sig + p2kh, or the actual size if it's more. + tx_size += max(len(ToHex(vin))//2, 147) + for vout in self.vout: + # Include the sizes for the outputs. + tx_size += len(ToHex(vout))//2 + tx_size += (len(self.vout) - len(self.vin))*1790 + return max(tx_size, 10 + 34 * len(self.vout)) def serialize(self): r = b""