Skip to content

Commit 8bafd0c

Browse files
committed
feat: discounted fees for confidential transactions
This is a mempool policy only change to enable cheaper fees for Confidential Transactions. At a feerate of 1 sat/vb for a 2 input, 3 output transaction: - explicit tx fee 326 sats - confidential tx fee 408 sats
1 parent 2d298f7 commit 8bafd0c

39 files changed

+281
-6
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ BITCOIN_CORE_H = \
206206
noui.h \
207207
outputtype.h \
208208
pegins.h \
209+
policy/discount.h \
209210
policy/feerate.h \
210211
policy/fees.h \
211212
policy/packages.h \

src/chainparams.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ class CMainParams : public CChainParams {
223223
anyonecanspend_aremine = false;
224224
enforce_pak = false;
225225
multi_data_permitted = false;
226+
accept_discount_ct = false;
227+
create_discount_ct = false;
226228
consensus.has_parent_chain = false;
227229
g_signed_blocks = false;
228230
g_con_elementsmode = false;
@@ -361,6 +363,8 @@ class CTestNetParams : public CChainParams {
361363
anyonecanspend_aremine = false;
362364
enforce_pak = false;
363365
multi_data_permitted = false;
366+
accept_discount_ct = false;
367+
create_discount_ct = false;
364368
consensus.has_parent_chain = false;
365369
g_signed_blocks = false;
366370
g_con_elementsmode = false;
@@ -517,6 +521,8 @@ class SigNetParams : public CChainParams {
517521
anyonecanspend_aremine = false;
518522
enforce_pak = false;
519523
multi_data_permitted = false;
524+
accept_discount_ct = false;
525+
create_discount_ct = false;
520526
consensus.has_parent_chain = false;
521527
g_signed_blocks = false; // lol
522528
g_con_elementsmode = false;
@@ -610,6 +616,8 @@ class CRegTestParams : public CChainParams {
610616
anyonecanspend_aremine = false;
611617
enforce_pak = false;
612618
multi_data_permitted = false;
619+
accept_discount_ct = false;
620+
create_discount_ct = false;
613621
consensus.has_parent_chain = false;
614622
g_signed_blocks = false;
615623
g_con_elementsmode = false;
@@ -887,6 +895,8 @@ class CCustomParams : public CRegTestParams {
887895
const CScript default_script(CScript() << OP_TRUE);
888896
consensus.fedpegScript = StrHexToScriptWithDefault(args.GetArg("-fedpegscript", ""), default_script);
889897
consensus.start_p2wsh_script = args.GetIntArg("-con_start_p2wsh_script", consensus.start_p2wsh_script);
898+
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", false);
899+
create_discount_ct = args.GetBoolArg("-creatediscountct", false);
890900

891901
// Calculate pegged Bitcoin asset
892902
std::vector<unsigned char> commit = CommitToArguments(consensus, strNetworkID);
@@ -1023,7 +1033,7 @@ class CLiquidTestNetParams : public CCustomParams {
10231033
*/
10241034
class CLiquidV1Params : public CChainParams {
10251035
public:
1026-
CLiquidV1Params()
1036+
explicit CLiquidV1Params(const ArgsManager& args)
10271037
{
10281038

10291039
strNetworkID = "liquidv1";
@@ -1118,6 +1128,8 @@ class CLiquidV1Params : public CChainParams {
11181128
enforce_pak = true;
11191129

11201130
multi_data_permitted = true;
1131+
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", true);
1132+
create_discount_ct = args.GetBoolArg("-creatediscountct", false);
11211133

11221134
parentGenesisBlockHash = uint256S("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
11231135
const bool parent_genesis_is_null = parentGenesisBlockHash == uint256();
@@ -1261,7 +1273,7 @@ class CLiquidV1Params : public CChainParams {
12611273
*/
12621274
class CLiquidV1TestParams : public CLiquidV1Params {
12631275
public:
1264-
explicit CLiquidV1TestParams(const ArgsManager& args)
1276+
explicit CLiquidV1TestParams(const ArgsManager& args) : CLiquidV1Params(args)
12651277
{
12661278
// Our goal here is to override ONLY the things from liquidv1 that make no sense for a test chain / which are pointless and burdensome to require people to override manually.
12671279

@@ -1466,6 +1478,8 @@ class CLiquidV1TestParams : public CLiquidV1Params {
14661478
enforce_pak = args.GetBoolArg("-enforce_pak", enforce_pak);
14671479

14681480
multi_data_permitted = args.GetBoolArg("-multi_data_permitted", multi_data_permitted);
1481+
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", accept_discount_ct);
1482+
create_discount_ct = args.GetBoolArg("-creatediscountct", create_discount_ct);
14691483

14701484
if (args.IsArgSet("-parentgenesisblockhash")) {
14711485
parentGenesisBlockHash = uint256S(args.GetArg("-parentgenesisblockhash", ""));
@@ -1557,7 +1571,7 @@ std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, c
15571571
} else if (chain == CBaseChainParams::REGTEST) {
15581572
return std::unique_ptr<CChainParams>(new CRegTestParams(args));
15591573
} else if (chain == CBaseChainParams::LIQUID1) {
1560-
return std::unique_ptr<CChainParams>(new CLiquidV1Params());
1574+
return std::unique_ptr<CChainParams>(new CLiquidV1Params(args));
15611575
} else if (chain == CBaseChainParams::LIQUID1TEST) {
15621576
return std::unique_ptr<CChainParams>(new CLiquidV1TestParams(args));
15631577
} else if (chain == CBaseChainParams::LIQUIDTESTNET) {

src/chainparams.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ class CChainParams
135135
const std::string& ParentBlech32HRP() const { return parent_blech32_hrp; }
136136
bool GetEnforcePak() const { return enforce_pak; }
137137
bool GetMultiDataPermitted() const { return multi_data_permitted; }
138+
bool GetAcceptDiscountCT() const { return accept_discount_ct; }
139+
bool GetCreateDiscountCT() const { return create_discount_ct; }
138140

139141
protected:
140142
CChainParams() {}
@@ -167,6 +169,8 @@ class CChainParams
167169
std::string parent_blech32_hrp;
168170
bool enforce_pak;
169171
bool multi_data_permitted;
172+
bool accept_discount_ct;
173+
bool create_discount_ct;
170174
};
171175

172176
/**

src/core_write.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <consensus/validation.h>
1010
#include <issuance.h>
1111
#include <key_io.h>
12+
#include <policy/discount.h> // ELEMENTS
1213
#include <script/descriptor.h>
1314
#include <script/script.h>
1415
#include <script/sign.h>
@@ -236,6 +237,12 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
236237
entry.pushKV("version", static_cast<int64_t>(static_cast<uint32_t>(tx.nVersion)));
237238
entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION));
238239
entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
240+
// ELEMENTS: add discountvsize
241+
if (Params().GetAcceptDiscountCT()) {
242+
entry.pushKV("discountvsize", GetDiscountVirtualTransactionSize(tx));
243+
} else {
244+
entry.pushKV("discountvsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
245+
}
239246
entry.pushKV("weight", GetTransactionWeight(tx));
240247
entry.pushKV("locktime", (int64_t)tx.nLockTime);
241248

src/init.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,8 @@ void SetupServerArgs(ArgsManager& argsman)
640640
argsman.AddArg("-initialreissuancetokens=<n>", "The amount of reissuance tokens created in the genesis block. (default: 0)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
641641
argsman.AddArg("-ct_bits", strprintf("The default number of hiding bits in a rangeproof. Will be exceeded to cover amounts exceeding the maximum hiding value. (default: %d)", 52), ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
642642
argsman.AddArg("-ct_exponent", strprintf("The hiding exponent. (default: %s)", 0), ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
643+
argsman.AddArg("-acceptdiscountct", "Accept discounted fees for Confidential Transactions (default: true for liquidv1, false for other chains)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
644+
argsman.AddArg("-creatediscountct", "Create Confidential Transactions with discounted fees (default: false)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
643645

644646
#if defined(USE_SYSCALL_SANDBOX)
645647
argsman.AddArg("-sandbox=<mode>", "Use the experimental syscall sandbox in the specified mode (-sandbox=log-and-abort or -sandbox=abort). Allow only expected syscalls to be used by bitcoind. Note that this is an experimental new feature that may cause bitcoind to exit or crash unexpectedly: use with caution. In the \"log-and-abort\" mode the invocation of an unexpected syscall results in a debug handler being invoked which will log the incident and terminate the program (without executing the unexpected syscall). In the \"abort\" mode the invocation of an unexpected syscall results in the entire process being killed immediately by the kernel without executing the unexpected syscall.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);

src/net_processing.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4964,7 +4964,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
49644964
auto txid = txinfo.tx->GetHash();
49654965
auto wtxid = txinfo.tx->GetWitnessHash();
49664966
// Peer told you to not send transactions at that feerate? Don't bother sending it.
4967-
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
4967+
// ELEMENTS: use the discounted vsize here so that discounted CTs are relayed.
4968+
// discountvsize only differs from vsize if accept_discount_ct is true.
4969+
if (txinfo.fee < filterrate.GetFee(txinfo.discountvsize)) {
49684970
continue;
49694971
}
49704972
if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;

src/policy/discount.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) 2009-2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2021 The Bitcoin Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#ifndef BITCOIN_POLICY_DISCOUNT_H
7+
#define BITCOIN_POLICY_DISCOUNT_H
8+
9+
#include <consensus/consensus.h>
10+
#include <cstdint>
11+
#include <primitives/transaction.h>
12+
#include <version.h>
13+
14+
/**
15+
* Calculate a smaller virtual size for discounted Confidential Transactions.
16+
*/
17+
static inline int64_t GetDiscountVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost = 0, unsigned int bytes_per_sig_op = 0)
18+
{
19+
int64_t size_bytes = ::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(tx, PROTOCOL_VERSION);
20+
int64_t sigop_bytes = nSigOpCost * bytes_per_sig_op;
21+
22+
int64_t weight = std::max(size_bytes, sigop_bytes);
23+
24+
// for each confidential output
25+
for (size_t i = 0; i < tx.vout.size(); ++i) {
26+
const CTxOut& output = tx.vout[i];
27+
if (output.IsFee()) continue;
28+
if (output.nAsset.IsCommitment() && output.nValue.IsCommitment()) {
29+
// subtract the weight of the output witness
30+
weight -= ::GetSerializeSize(tx.witness.vtxoutwit[i], PROTOCOL_VERSION);
31+
// subtract the weight difference of amount commitment (33) vs explicit amount (9)
32+
weight -= (33 - 9);
33+
// subtract the weight difference of the confidential nonce (33)
34+
weight -= 33;
35+
}
36+
}
37+
assert(weight > 0);
38+
39+
size_t discountvsize = (weight + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
40+
41+
assert(discountvsize > 0);
42+
return discountvsize;
43+
}
44+
45+
#endif // BITCOIN_POLICY_DISCOUNT_H

src/policy/policy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define BITCOIN_POLICY_POLICY_H
88

99
#include <consensus/consensus.h>
10+
#include <policy/discount.h>
1011
#include <policy/feerate.h>
1112
#include <script/interpreter.h>
1213
#include <script/standard.h>

src/txmempool.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <consensus/tx_verify.h>
1414
#include <consensus/validation.h>
1515
#include <pegins.h>
16+
#include <policy/discount.h>
1617
#include <policy/fees.h>
1718
#include <policy/policy.h>
1819
#include <policy/settings.h>
@@ -965,7 +966,14 @@ void CTxMemPool::queryHashes(std::vector<uint256>& vtxid) const
965966
}
966967

967968
static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {
968-
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee()};
969+
// ELEMENTS: include the discounted vsize of the tx
970+
size_t discountvsize = it->GetTxSize();
971+
CTransaction tx = it->GetTx();
972+
// discountvsize only differs from vsize if we accept discounted CTs
973+
if (Params().GetAcceptDiscountCT()) {
974+
discountvsize = GetDiscountVirtualTransactionSize(tx);
975+
}
976+
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee(), discountvsize};
969977
}
970978

971979
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const

src/txmempool.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,9 @@ struct TxMempoolInfo
345345

346346
/** The fee delta. */
347347
int64_t nFeeDelta;
348+
349+
/** ELEMENTS: Discounted CT size. */
350+
size_t discountvsize;
348351
};
349352

350353
/** Reason why a transaction was removed from the mempool,

src/validation.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
914914

915915
// No transactions are allowed below minRelayTxFee except from disconnected
916916
// blocks
917-
if (!bypass_limits && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state)) return false;
917+
bool fee_check = CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state);
918+
// ELEMENTS: accept discounted fees for Confidential Transactions only, if enabled.
919+
if (Params().GetAcceptDiscountCT()) {
920+
fee_check = CheckFeeRate(GetDiscountVirtualTransactionSize(tx), ws.m_modified_fees, state);
921+
}
922+
if (!bypass_limits && !fee_check) return false;
918923

919924
ws.m_iters_conflicting = m_pool.GetIterSet(ws.m_conflicts);
920925
// Calculate in-mempool ancestors, up to a limit.

src/wallet/spend.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *walle
174174
CTransaction ctx(txNew);
175175
int64_t vsize = GetVirtualTransactionSize(ctx);
176176
int64_t weight = GetTransactionWeight(ctx);
177+
// ELEMENTS: use discounted vsize for CTs if enabled
178+
if (Params().GetCreateDiscountCT()) {
179+
vsize = GetDiscountVirtualTransactionSize(ctx);
180+
}
181+
177182
return TxSize{vsize, weight};
178183
}
179184

0 commit comments

Comments
 (0)