Merge pull request #1366 from delta1/discountweight

discount: fix weight calculation
This commit is contained in:
Pablo Greco 2024-09-25 09:29:08 -07:00 committed by GitHub
commit fbc01d56d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 43 additions and 22 deletions

View file

@ -237,11 +237,12 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
entry.pushKV("version", static_cast<int64_t>(static_cast<uint32_t>(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};

View file

@ -12,16 +12,15 @@
#include <version.h>
/**
* 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;
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,16 +31,25 @@ static inline int64_t GetDiscountVirtualTransactionSize(const CTransaction& tx,
}
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);
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;

View file

@ -79,8 +79,10 @@ class CTTest(BitcoinTestFramework):
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,9 +97,11 @@ class CTTest(BitcoinTestFramework):
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['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()
@ -111,8 +115,10 @@ class CTTest(BitcoinTestFramework):
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,9 +133,11 @@ class CTTest(BitcoinTestFramework):
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['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'
@ -148,11 +156,13 @@ class CTTest(BitcoinTestFramework):
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['weight'], 10300)
assert_equal(decoded['discountweight'], 1302)
assert_equal(decoded['discountvsize'], 326)
# node0 only has vsize
tx = node0.getrawtransaction(txid, True)
@ -176,11 +186,13 @@ class CTTest(BitcoinTestFramework):
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['discountvsize'], 410)
assert_equal(decoded['weight'], 10300)
assert_equal(decoded['discountweight'], 1302)
assert_equal(decoded['discountvsize'], 326)
# node0 only has vsize
tx = node0.getrawtransaction(txid, True)
assert_equal(tx['vsize'], 2575)
@ -207,7 +219,7 @@ class CTTest(BitcoinTestFramework):
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}")
@ -231,7 +243,7 @@ class CTTest(BitcoinTestFramework):
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)

View file

@ -113,7 +113,7 @@ class CTTest(BitcoinTestFramework):
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 @@ class CTTest(BitcoinTestFramework):
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 @@ class CTTest(BitcoinTestFramework):
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")