Skip to content

Commit

Permalink
Merge pull request #1317 from delta1/ct-fees-discount
Browse files Browse the repository at this point in the history
feat: discounted fees for confidential transactions
  • Loading branch information
psgreco authored May 14, 2024
2 parents 7ff33d4 + 3ebc353 commit a4d7ac7
Show file tree
Hide file tree
Showing 17 changed files with 653 additions and 24 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);
create_discount_ct = args.GetBoolArg("-creatediscountct", false);
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", create_discount_ct);

// 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;
create_discount_ct = args.GetBoolArg("-creatediscountct", false);
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", 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);
create_discount_ct = args.GetBoolArg("-creatediscountct", create_discount_ct);
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", accept_discount_ct || 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
5 changes: 5 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,10 @@ 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));
}
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). Setting this to true will also set 'acceptdiscountct' to true.", 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
20 changes: 11 additions & 9 deletions src/node/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ int BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& already
if (mit == mapModifiedTx.end()) {
CTxMemPoolModifiedEntry modEntry(desc);
modEntry.nSizeWithAncestors -= it->GetTxSize();
modEntry.discountSizeWithAncestors -= it->GetDiscountTxSize();
modEntry.nModFeesWithAncestors -= it->GetModifiedFee();
modEntry.nSigOpCostWithAncestors -= it->GetSigOpCost();
mapModifiedTx.insert(modEntry);
Expand Down Expand Up @@ -383,7 +384,8 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
// and modifying them for their already included ancestors
UpdatePackagesForAdded(inBlock, mapModifiedTx);

CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator mi = m_mempool.mapTx.get<ancestor_score>().begin();
// ELEMENTS: we use confidential_score instead of ancestor_score
CTxMemPool::indexed_transaction_set::index<confidential_score>::type::iterator mi = m_mempool.mapTx.get<confidential_score>().begin();
CTxMemPool::txiter iter;

// Limit the number of attempts to add transactions to the block when it is
Expand All @@ -392,9 +394,9 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
const int64_t MAX_CONSECUTIVE_FAILURES = 1000;
int64_t nConsecutiveFailed = 0;

while (mi != m_mempool.mapTx.get<ancestor_score>().end() || !mapModifiedTx.empty()) {
while (mi != m_mempool.mapTx.get<confidential_score>().end() || !mapModifiedTx.empty()) {
// First try to find a new transaction in mapTx to evaluate.
if (mi != m_mempool.mapTx.get<ancestor_score>().end() &&
if (mi != m_mempool.mapTx.get<confidential_score>().end() &&
SkipMapTxEntry(m_mempool.mapTx.project<0>(mi), mapModifiedTx, failedTx)) {
++mi;
continue;
Expand All @@ -404,16 +406,16 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
// the next entry from mapTx, or the best from mapModifiedTx?
bool fUsingModified = false;

modtxscoreiter modit = mapModifiedTx.get<ancestor_score>().begin();
if (mi == m_mempool.mapTx.get<ancestor_score>().end()) {
modconftxscoreiter modit = mapModifiedTx.get<confidential_score>().begin();
if (mi == m_mempool.mapTx.get<confidential_score>().end()) {
// We're out of entries in mapTx; use the entry from mapModifiedTx
iter = modit->iter;
fUsingModified = true;
} else {
// Try to compare the mapTx entry to the mapModifiedTx entry
iter = m_mempool.mapTx.project<0>(mi);
if (modit != mapModifiedTx.get<ancestor_score>().end() &&
CompareTxMemPoolEntryByAncestorFee()(*modit, CTxMemPoolModifiedEntry(iter))) {
if (modit != mapModifiedTx.get<confidential_score>().end() &&
CompareTxMemPoolEntryByConfidentialFee()(*modit, CTxMemPoolModifiedEntry(iter))) {
// The best entry in mapModifiedTx has higher score
// than the one from mapTx.
// Switch which transaction (package) to consider
Expand Down Expand Up @@ -455,7 +457,7 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
// Since we always look at the best entry in mapModifiedTx,
// we must erase failed entries so that we can consider the
// next best entry on the next loop iteration
mapModifiedTx.get<ancestor_score>().erase(modit);
mapModifiedTx.get<confidential_score>().erase(modit);
failedTx.insert(iter);
}

Expand All @@ -480,7 +482,7 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
// Test if all tx's are Final
if (!TestPackageTransactions(ancestors)) {
if (fUsingModified) {
mapModifiedTx.get<ancestor_score>().erase(modit);
mapModifiedTx.get<confidential_score>().erase(modit);
failedTx.insert(iter);
}
continue;
Expand Down
11 changes: 11 additions & 0 deletions src/node/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,22 @@ struct CTxMemPoolModifiedEntry {
{
iter = entry;
nSizeWithAncestors = entry->GetSizeWithAncestors();
discountSizeWithAncestors = entry->GetDiscountSizeWithAncestors();
nModFeesWithAncestors = entry->GetModFeesWithAncestors();
nSigOpCostWithAncestors = entry->GetSigOpCostWithAncestors();
}

int64_t GetModifiedFee() const { return iter->GetModifiedFee(); }
uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
uint64_t GetDiscountSizeWithAncestors() const { return discountSizeWithAncestors; }
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
size_t GetTxSize() const { return iter->GetTxSize(); }
size_t GetDiscountTxSize() const { return iter->GetDiscountTxSize(); }
const CTransaction& GetTx() const { return iter->GetTx(); }

CTxMemPool::txiter iter;
uint64_t nSizeWithAncestors;
uint64_t discountSizeWithAncestors;
CAmount nModFeesWithAncestors;
int64_t nSigOpCostWithAncestors;
};
Expand Down Expand Up @@ -103,12 +107,19 @@ typedef boost::multi_index_container<
boost::multi_index::tag<ancestor_score>,
boost::multi_index::identity<CTxMemPoolModifiedEntry>,
CompareTxMemPoolEntryByAncestorFee
>,
// ELEMENTS
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<confidential_score>,
boost::multi_index::identity<CTxMemPoolModifiedEntry>,
CompareTxMemPoolEntryByConfidentialFee
>
>
> indexed_modified_transaction_set;

typedef indexed_modified_transaction_set::nth_index<0>::type::iterator modtxiter;
typedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator modtxscoreiter;
typedef indexed_modified_transaction_set::index<confidential_score>::type::iterator modconftxscoreiter; // ELEMENTS

struct update_for_parent_inclusion
{
Expand Down
50 changes: 50 additions & 0 deletions src/policy/discount.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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 (i < tx.witness.vtxoutwit.size()) {
// subtract the weight of the output witness, except the 2 bytes used to serialize the empty proofs
size_t witness_size = ::GetSerializeSize(tx.witness.vtxoutwit[i], PROTOCOL_VERSION);
assert(witness_size >= 2);
weight -= (witness_size - 2);
}
if (output.nValue.IsCommitment()) {
// subtract the weight difference of amount commitment (33) vs explicit amount (9)
weight -= (33 - 9);
}
if (output.nNonce.IsCommitment()) {
// subtract the weight difference of nonce commitment (33) vs no nonce (1)
weight -= 32;
}
}
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
Loading

0 comments on commit a4d7ac7

Please sign in to comment.