From d0f714638ac565fbfeccd9a7940d827c19ce0993 Mon Sep 17 00:00:00 2001 From: Byron Hambly Date: Fri, 20 Sep 2024 14:39:13 +0200 Subject: [PATCH 1/3] feat: add discountweight to TxToUniv --- src/core_write.cpp | 3 ++- src/policy/discount.h | 13 ++++++++++--- test/functional/feature_discount_ct.py | 12 ++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/core_write.cpp b/src/core_write.cpp index d9fc2a7a59..d61b89900f 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -237,11 +237,12 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, entry.pushKV("version", static_cast(static_cast(tx.nVersion))); entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION)); entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR); + entry.pushKV("weight", GetTransactionWeight(tx)); // ELEMENTS: add discountvsize if (Params().GetAcceptDiscountCT()) { entry.pushKV("discountvsize", GetDiscountVirtualTransactionSize(tx)); + entry.pushKV("discountweight", GetDiscountTransactionWeight(tx)); } - entry.pushKV("weight", GetTransactionWeight(tx)); entry.pushKV("locktime", (int64_t)tx.nLockTime); UniValue vin{UniValue::VARR}; diff --git a/src/policy/discount.h b/src/policy/discount.h index e8c3ece6e0..1cfec410af 100644 --- a/src/policy/discount.h +++ b/src/policy/discount.h @@ -12,9 +12,9 @@ #include /** - * Calculate a smaller virtual size for discounted Confidential Transactions. + * Calculate a smaller weight for discounted Confidential Transactions. */ -static inline int64_t GetDiscountVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost = 0, unsigned int bytes_per_sig_op = 0) +static inline int64_t GetDiscountTransactionWeight(const CTransaction& tx, int64_t nSigOpCost = 0, unsigned int bytes_per_sig_op = 0) { int64_t size_bytes = ::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(tx, PROTOCOL_VERSION); int64_t sigop_bytes = nSigOpCost * bytes_per_sig_op; @@ -40,8 +40,15 @@ static inline int64_t GetDiscountVirtualTransactionSize(const CTransaction& tx, } } assert(weight > 0); + return weight; +} - size_t discountvsize = (weight + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR; +/** + * Calculate a smaller virtual size for discounted Confidential Transactions. + */ +static inline int64_t GetDiscountVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost = 0, unsigned int bytes_per_sig_op = 0) +{ + size_t discountvsize = (GetDiscountTransactionWeight(tx, nSigOpCost, bytes_per_sig_op) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR; assert(discountvsize > 0); return discountvsize; diff --git a/test/functional/feature_discount_ct.py b/test/functional/feature_discount_ct.py index b0b43361e6..85a341df5b 100755 --- a/test/functional/feature_discount_ct.py +++ b/test/functional/feature_discount_ct.py @@ -79,8 +79,10 @@ def run_test(self): assert_equal(len(vout), 3) assert_equal(tx['fee']['bitcoin'], Decimal('-0.00000326')) assert_equal(decoded['vsize'], 326) + assert_equal(decoded['weight'], 1302) self.generate(node0, 1) tx = node1.getrawtransaction(txid, True) + assert_equal(tx['discountweight'], 1302) assert_equal(tx['discountvsize'], 326) self.log.info("Send confidential tx to node 0") @@ -95,8 +97,10 @@ def run_test(self): assert_equal(len(vout), 3) assert_equal(tx['fee']['bitcoin'], Decimal('-0.00002575')) assert_equal(decoded['vsize'], 2575) + assert_equal(decoded['weight'], 10300) self.generate(node0, 1) tx = node1.getrawtransaction(txid, True) + assert_equal(tx['discountweight'], 1638) assert_equal(tx['discountvsize'], 410) # node1 has discountvsize self.log.info("Send explicit tx to node 1") @@ -111,8 +115,10 @@ def run_test(self): assert_equal(len(vout), 3) assert_equal(tx['fee']['bitcoin'], Decimal('-0.00000326')) assert_equal(decoded['vsize'], 326) + assert_equal(decoded['weight'], 1302) self.generate(node0, 1) tx = node1.getrawtransaction(txid, True) + assert_equal(tx['discountweight'], 1302) assert_equal(tx['discountvsize'], 326) self.log.info("Send confidential (undiscounted) tx to node 1") @@ -127,8 +133,10 @@ def run_test(self): assert_equal(len(vout), 3) assert_equal(tx['fee']['bitcoin'], Decimal('-0.00002575')) assert_equal(decoded['vsize'], 2575) + assert_equal(decoded['weight'], 10300) self.generate(node0, 1) tx = node1.getrawtransaction(txid, True) + assert_equal(tx['discountweight'], 1638) assert_equal(tx['discountvsize'], 410) # node1 has discountvsize self.log.info("Send confidential (discounted) tx to node 1") @@ -152,6 +160,8 @@ def run_test(self): else: assert_equal(decoded['fee'][bitcoin], Decimal('0.00000410')) assert_equal(decoded['vsize'], 2575) + assert_equal(decoded['weight'], 10300) + assert_equal(decoded['discountweight'], 1638) assert_equal(decoded['discountvsize'], 410) # node0 only has vsize @@ -180,7 +190,9 @@ def run_test(self): else: assert_equal(decoded['fee'][bitcoin], Decimal('0.00000041')) assert_equal(decoded['vsize'], 2575) + assert_equal(decoded['weight'], 10300) assert_equal(decoded['discountvsize'], 410) + assert_equal(decoded['discountweight'], 1638) # node0 only has vsize tx = node0.getrawtransaction(txid, True) assert_equal(tx['vsize'], 2575) From 09c5068ab19390fc6553172c645b72ee3d6fecd8 Mon Sep 17 00:00:00 2001 From: Byron Hambly Date: Wed, 25 Sep 2024 15:18:38 +0200 Subject: [PATCH 2/3] discount: fix weight calculation Thanks to Jon Griffiths for picking up that the amount and nonce discount should be multiplied by the witness scaling factor as they form part of the base transaction. --- src/policy/discount.h | 7 +++-- test/functional/feature_discount_ct.py | 28 +++++++++---------- .../feature_discount_ct_ordering.py | 10 +++---- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/policy/discount.h b/src/policy/discount.h index 1cfec410af..9f087f62c9 100644 --- a/src/policy/discount.h +++ b/src/policy/discount.h @@ -21,7 +21,6 @@ static inline int64_t GetDiscountTransactionWeight(const CTransaction& tx, int64 int64_t weight = std::max(size_bytes, sigop_bytes); - // for each confidential output for (size_t i = 0; i < tx.vout.size(); ++i) { const CTxOut& output = tx.vout[i]; if (i < tx.witness.vtxoutwit.size()) { @@ -32,11 +31,13 @@ static inline int64_t GetDiscountTransactionWeight(const CTransaction& tx, int64 } if (output.nValue.IsCommitment()) { // subtract the weight difference of amount commitment (33) vs explicit amount (9) - weight -= (33 - 9); + // weighted as part of the base transaction + weight -= (33 - 9) * WITNESS_SCALE_FACTOR; } if (output.nNonce.IsCommitment()) { // subtract the weight difference of nonce commitment (33) vs no nonce (1) - weight -= 32; + // weighted as part of the base transaction + weight -= 32 * WITNESS_SCALE_FACTOR; } } assert(weight > 0); diff --git a/test/functional/feature_discount_ct.py b/test/functional/feature_discount_ct.py index 85a341df5b..84e2c096b1 100755 --- a/test/functional/feature_discount_ct.py +++ b/test/functional/feature_discount_ct.py @@ -100,8 +100,8 @@ def run_test(self): assert_equal(decoded['weight'], 10300) self.generate(node0, 1) tx = node1.getrawtransaction(txid, True) - assert_equal(tx['discountweight'], 1638) - assert_equal(tx['discountvsize'], 410) # node1 has discountvsize + assert_equal(tx['discountweight'], 1302) + assert_equal(tx['discountvsize'], 326) # node1 has discountvsize self.log.info("Send explicit tx to node 1") addr = node1.getnewaddress() @@ -136,8 +136,8 @@ def run_test(self): assert_equal(decoded['weight'], 10300) self.generate(node0, 1) tx = node1.getrawtransaction(txid, True) - assert_equal(tx['discountweight'], 1638) - assert_equal(tx['discountvsize'], 410) # node1 has discountvsize + assert_equal(tx['discountweight'], 1302) + assert_equal(tx['discountvsize'], 326) # node1 has discountvsize self.log.info("Send confidential (discounted) tx to node 1") bitcoin = 'b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23' @@ -156,13 +156,13 @@ def run_test(self): assert_equal(len(vin), 2) assert_equal(len(vout), 3) if 'bitcoin' in decoded['fee']: - assert_equal(decoded['fee']['bitcoin'], Decimal('-0.00000410')) + assert_equal(decoded['fee']['bitcoin'], Decimal('-0.00000326')) else: - assert_equal(decoded['fee'][bitcoin], Decimal('0.00000410')) + assert_equal(decoded['fee'][bitcoin], Decimal('0.00000326')) assert_equal(decoded['vsize'], 2575) assert_equal(decoded['weight'], 10300) - assert_equal(decoded['discountweight'], 1638) - assert_equal(decoded['discountvsize'], 410) + assert_equal(decoded['discountweight'], 1302) + assert_equal(decoded['discountvsize'], 326) # node0 only has vsize tx = node0.getrawtransaction(txid, True) @@ -186,13 +186,13 @@ def run_test(self): assert_equal(len(vin), 2) assert_equal(len(vout), 3) if 'bitcoin' in decoded['fee']: - assert_equal(decoded['fee']['bitcoin'], Decimal('-0.00000041')) + assert_equal(decoded['fee']['bitcoin'], Decimal('-0.00000033')) else: - assert_equal(decoded['fee'][bitcoin], Decimal('0.00000041')) + assert_equal(decoded['fee'][bitcoin], Decimal('0.00000033')) assert_equal(decoded['vsize'], 2575) assert_equal(decoded['weight'], 10300) - assert_equal(decoded['discountvsize'], 410) - assert_equal(decoded['discountweight'], 1638) + assert_equal(decoded['discountweight'], 1302) + assert_equal(decoded['discountvsize'], 326) # node0 only has vsize tx = node0.getrawtransaction(txid, True) assert_equal(tx['vsize'], 2575) @@ -219,7 +219,7 @@ def run_test(self): assert_equal(test[0]["allowed"], True) txid = node1.sendrawtransaction(signed['hex']) tx = node1.gettransaction(txid, True, True) - assert_equal(tx['decoded']['discountvsize'], 341) + assert_equal(tx['decoded']['discountvsize'], 257) for i in range(24): self.log.info(f"Add package descendant {i+1}") @@ -243,7 +243,7 @@ def run_test(self): assert_equal(test[0]["allowed"], True) txid = node1.sendrawtransaction(hex) tx = node1.gettransaction(txid, True, True) - assert_equal(tx['decoded']['discountvsize'], 341) + assert_equal(tx['decoded']['discountvsize'], 257) assert_equal(len(node1.getrawmempool()), i + 2) assert_equal(len(node1.getrawmempool()), 25) diff --git a/test/functional/feature_discount_ct_ordering.py b/test/functional/feature_discount_ct_ordering.py index 7cca1ee880..aed8a1f0db 100755 --- a/test/functional/feature_discount_ct_ordering.py +++ b/test/functional/feature_discount_ct_ordering.py @@ -113,7 +113,7 @@ def run_test(self): assert_equal(decoded['vsize'], 2575) self.sync_mempools([node0, node1]) tx = node1.getrawtransaction(txid, True) - assert_equal(tx['discountvsize'], 410) + assert_equal(tx['discountvsize'], 326) feerate = 1.0 self.log.info(f"Send confidential (discounted) tx to node 1 at {feerate} sat/vb") @@ -131,11 +131,11 @@ def run_test(self): assert_equal(len(vin), 2) assert_equal(len(vout), 3) if 'bitcoin' in decoded['fee']: - assert_equal(decoded['fee']['bitcoin'], Decimal('-0.00000410')) + assert_equal(decoded['fee']['bitcoin'], Decimal('-0.00000326')) else: - assert_equal(decoded['fee'][bitcoin], Decimal('0.00000410')) + assert_equal(decoded['fee'][bitcoin], Decimal('0.00000326')) assert_equal(decoded['vsize'], 2575) - assert_equal(decoded['discountvsize'], 410) + assert_equal(decoded['discountvsize'], 326) feerate = 2.0 self.log.info(f"Send confidential (discounted) tx to node 1 at {feerate} sat/vb") @@ -145,7 +145,7 @@ def run_test(self): self.sync_mempools([node1, node2]) tx = node1.gettransaction(txid, True, True) decoded = tx['decoded'] - assert_equal(decoded['fee'][bitcoin], Decimal('0.00000820')) + assert_equal(decoded['fee'][bitcoin], Decimal('0.00000652')) # check that txs in the block template are in decreasing feerate according to their discount size self.log.info("Check tx ordering in block template") From bcf3a37cba49c65cc87e012c2ec0c4136337128b Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Wed, 25 Sep 2024 09:38:22 -0700 Subject: [PATCH 3/3] Bump version to 23.2.4rc1 --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 0489b5bc53..4839e4fe9c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.69]) define(_CLIENT_VERSION_MAJOR, 23) define(_CLIENT_VERSION_MINOR, 2) -define(_CLIENT_VERSION_BUILD, 3) -define(_CLIENT_VERSION_RC, 0) +define(_CLIENT_VERSION_BUILD, 4) +define(_CLIENT_VERSION_RC, 1) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2024) define(_COPYRIGHT_HOLDERS,[The %s developers])