Skip to content

Commit

Permalink
feat: discounted fees for confidential transactions
Browse files Browse the repository at this point in the history
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
  • Loading branch information
delta1 committed Mar 14, 2024
1 parent 2d298f7 commit 8bafd0c
Show file tree
Hide file tree
Showing 39 changed files with 281 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ BITCOIN_CORE_H = \
noui.h \
outputtype.h \
pegins.h \
policy/discount.h \
policy/feerate.h \
policy/fees.h \
policy/packages.h \
Expand Down
20 changes: 17 additions & 3 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ class CMainParams : public CChainParams {
anyonecanspend_aremine = false;
enforce_pak = false;
multi_data_permitted = false;
accept_discount_ct = false;
create_discount_ct = false;
consensus.has_parent_chain = false;
g_signed_blocks = false;
g_con_elementsmode = false;
Expand Down Expand Up @@ -361,6 +363,8 @@ class CTestNetParams : public CChainParams {
anyonecanspend_aremine = false;
enforce_pak = false;
multi_data_permitted = false;
accept_discount_ct = false;
create_discount_ct = false;
consensus.has_parent_chain = false;
g_signed_blocks = false;
g_con_elementsmode = false;
Expand Down Expand Up @@ -517,6 +521,8 @@ class SigNetParams : public CChainParams {
anyonecanspend_aremine = false;
enforce_pak = false;
multi_data_permitted = false;
accept_discount_ct = false;
create_discount_ct = false;
consensus.has_parent_chain = false;
g_signed_blocks = false; // lol
g_con_elementsmode = false;
Expand Down Expand Up @@ -610,6 +616,8 @@ class CRegTestParams : public CChainParams {
anyonecanspend_aremine = false;
enforce_pak = false;
multi_data_permitted = false;
accept_discount_ct = false;
create_discount_ct = false;
consensus.has_parent_chain = false;
g_signed_blocks = false;
g_con_elementsmode = false;
Expand Down Expand Up @@ -887,6 +895,8 @@ class CCustomParams : public CRegTestParams {
const CScript default_script(CScript() << OP_TRUE);
consensus.fedpegScript = StrHexToScriptWithDefault(args.GetArg("-fedpegscript", ""), default_script);
consensus.start_p2wsh_script = args.GetIntArg("-con_start_p2wsh_script", consensus.start_p2wsh_script);
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", false);
create_discount_ct = args.GetBoolArg("-creatediscountct", false);

// Calculate pegged Bitcoin asset
std::vector<unsigned char> commit = CommitToArguments(consensus, strNetworkID);
Expand Down Expand Up @@ -1023,7 +1033,7 @@ class CLiquidTestNetParams : public CCustomParams {
*/
class CLiquidV1Params : public CChainParams {
public:
CLiquidV1Params()
explicit CLiquidV1Params(const ArgsManager& args)
{

strNetworkID = "liquidv1";
Expand Down Expand Up @@ -1118,6 +1128,8 @@ class CLiquidV1Params : public CChainParams {
enforce_pak = true;

multi_data_permitted = true;
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", true);
create_discount_ct = args.GetBoolArg("-creatediscountct", false);

parentGenesisBlockHash = uint256S("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
const bool parent_genesis_is_null = parentGenesisBlockHash == uint256();
Expand Down Expand Up @@ -1261,7 +1273,7 @@ class CLiquidV1Params : public CChainParams {
*/
class CLiquidV1TestParams : public CLiquidV1Params {
public:
explicit CLiquidV1TestParams(const ArgsManager& args)
explicit CLiquidV1TestParams(const ArgsManager& args) : CLiquidV1Params(args)
{
// 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.

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

multi_data_permitted = args.GetBoolArg("-multi_data_permitted", multi_data_permitted);
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", accept_discount_ct);
create_discount_ct = args.GetBoolArg("-creatediscountct", create_discount_ct);

if (args.IsArgSet("-parentgenesisblockhash")) {
parentGenesisBlockHash = uint256S(args.GetArg("-parentgenesisblockhash", ""));
Expand Down Expand Up @@ -1557,7 +1571,7 @@ std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, c
} else if (chain == CBaseChainParams::REGTEST) {
return std::unique_ptr<CChainParams>(new CRegTestParams(args));
} else if (chain == CBaseChainParams::LIQUID1) {
return std::unique_ptr<CChainParams>(new CLiquidV1Params());
return std::unique_ptr<CChainParams>(new CLiquidV1Params(args));
} else if (chain == CBaseChainParams::LIQUID1TEST) {
return std::unique_ptr<CChainParams>(new CLiquidV1TestParams(args));
} else if (chain == CBaseChainParams::LIQUIDTESTNET) {
Expand Down
4 changes: 4 additions & 0 deletions src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ class CChainParams
const std::string& ParentBlech32HRP() const { return parent_blech32_hrp; }
bool GetEnforcePak() const { return enforce_pak; }
bool GetMultiDataPermitted() const { return multi_data_permitted; }
bool GetAcceptDiscountCT() const { return accept_discount_ct; }
bool GetCreateDiscountCT() const { return create_discount_ct; }

protected:
CChainParams() {}
Expand Down Expand Up @@ -167,6 +169,8 @@ class CChainParams
std::string parent_blech32_hrp;
bool enforce_pak;
bool multi_data_permitted;
bool accept_discount_ct;
bool create_discount_ct;
};

/**
Expand Down
7 changes: 7 additions & 0 deletions src/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <consensus/validation.h>
#include <issuance.h>
#include <key_io.h>
#include <policy/discount.h> // ELEMENTS
#include <script/descriptor.h>
#include <script/script.h>
#include <script/sign.h>
Expand Down Expand Up @@ -236,6 +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);
// ELEMENTS: add discountvsize
if (Params().GetAcceptDiscountCT()) {
entry.pushKV("discountvsize", GetDiscountVirtualTransactionSize(tx));
} else {
entry.pushKV("discountvsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
}
entry.pushKV("weight", GetTransactionWeight(tx));
entry.pushKV("locktime", (int64_t)tx.nLockTime);

Expand Down
2 changes: 2 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,8 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-initialreissuancetokens=<n>", "The amount of reissuance tokens created in the genesis block. (default: 0)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
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);
argsman.AddArg("-ct_exponent", strprintf("The hiding exponent. (default: %s)", 0), ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-acceptdiscountct", "Accept discounted fees for Confidential Transactions (default: true for liquidv1, false for other chains)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-creatediscountct", "Create Confidential Transactions with discounted fees (default: false)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);

#if defined(USE_SYSCALL_SANDBOX)
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);
Expand Down
4 changes: 3 additions & 1 deletion src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4964,7 +4964,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
auto txid = txinfo.tx->GetHash();
auto wtxid = txinfo.tx->GetWitnessHash();
// Peer told you to not send transactions at that feerate? Don't bother sending it.
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
// ELEMENTS: use the discounted vsize here so that discounted CTs are relayed.
// discountvsize only differs from vsize if accept_discount_ct is true.
if (txinfo.fee < filterrate.GetFee(txinfo.discountvsize)) {
continue;
}
if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
Expand Down
45 changes: 45 additions & 0 deletions src/policy/discount.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_POLICY_DISCOUNT_H
#define BITCOIN_POLICY_DISCOUNT_H

#include <consensus/consensus.h>
#include <cstdint>
#include <primitives/transaction.h>
#include <version.h>

/**
* 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)
{
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 (output.IsFee()) continue;
if (output.nAsset.IsCommitment() && output.nValue.IsCommitment()) {
// subtract the weight of the output witness
weight -= ::GetSerializeSize(tx.witness.vtxoutwit[i], PROTOCOL_VERSION);
// subtract the weight difference of amount commitment (33) vs explicit amount (9)
weight -= (33 - 9);
// subtract the weight difference of the confidential nonce (33)
weight -= 33;
}
}
assert(weight > 0);

size_t discountvsize = (weight + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;

assert(discountvsize > 0);
return discountvsize;
}

#endif // BITCOIN_POLICY_DISCOUNT_H
1 change: 1 addition & 0 deletions src/policy/policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define BITCOIN_POLICY_POLICY_H

#include <consensus/consensus.h>
#include <policy/discount.h>
#include <policy/feerate.h>
#include <script/interpreter.h>
#include <script/standard.h>
Expand Down
10 changes: 9 additions & 1 deletion src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <pegins.h>
#include <policy/discount.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/settings.h>
Expand Down Expand Up @@ -965,7 +966,14 @@ void CTxMemPool::queryHashes(std::vector<uint256>& vtxid) const
}

static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee()};
// ELEMENTS: include the discounted vsize of the tx
size_t discountvsize = it->GetTxSize();
CTransaction tx = it->GetTx();
// discountvsize only differs from vsize if we accept discounted CTs
if (Params().GetAcceptDiscountCT()) {
discountvsize = GetDiscountVirtualTransactionSize(tx);
}
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee(), discountvsize};
}

std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
Expand Down
3 changes: 3 additions & 0 deletions src/txmempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ struct TxMempoolInfo

/** The fee delta. */
int64_t nFeeDelta;

/** ELEMENTS: Discounted CT size. */
size_t discountvsize;
};

/** Reason why a transaction was removed from the mempool,
Expand Down
7 changes: 6 additions & 1 deletion src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)

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

ws.m_iters_conflicting = m_pool.GetIterSet(ws.m_conflicts);
// Calculate in-mempool ancestors, up to a limit.
Expand Down
5 changes: 5 additions & 0 deletions src/wallet/spend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *walle
CTransaction ctx(txNew);
int64_t vsize = GetVirtualTransactionSize(ctx);
int64_t weight = GetTransactionWeight(ctx);
// ELEMENTS: use discounted vsize for CTs if enabled
if (Params().GetCreateDiscountCT()) {
vsize = GetDiscountVirtualTransactionSize(ctx);
}

return TxSize{vsize, weight};
}

Expand Down
Loading

0 comments on commit 8bafd0c

Please sign in to comment.