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/mempool_tests.cpp b/src/test/mempool_tests.cpp --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -452,10 +452,10 @@ */ // take out tx9, tx8 from the beginning sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin() + 2); - sortedOrder.insert(sortedOrder.begin() + 5, tx9.GetId().ToString()); - sortedOrder.insert(sortedOrder.begin() + 6, tx8.GetId().ToString()); - // tx10 is just before tx6 - sortedOrder.insert(sortedOrder.begin() + 7, tx10.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin() + 7, tx9.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin() + 8, tx8.GetId().ToString()); + // tx10 is before tx7 + sortedOrder.insert(sortedOrder.begin() + 9, tx10.GetId().ToString()); CheckSort(pool, sortedOrder, "MempoolIndexingTest6"); // there should be 10 transactions in the mempool @@ -597,7 +597,7 @@ // CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true); pool.addUnchecked(tx7.GetId(), entry.Fee(Amount(fee)).FromTx(tx7)); BOOST_CHECK_EQUAL(pool.size(), 7UL); - sortedOrder.insert(sortedOrder.begin() + 1, tx7.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin(), tx7.GetId().ToString()); CheckSort(pool, sortedOrder, "MempoolAncestorIndexingTest3"); @@ -606,7 +606,7 @@ vtx.push_back(MakeTransactionRef(tx6)); pool.removeForBlock(vtx, 1); - sortedOrder.erase(sortedOrder.begin() + 1); + sortedOrder.erase(sortedOrder.begin()); // Ties are broken by hash if (tx3.GetId() < tx6.GetId()) { sortedOrder.pop_back(); 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/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""