Skip to content

Allow any fee config #1476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,8 @@ class CCustomParams : public CRegTestParams {
std::vector<unsigned char> man_bytes = ParseHex(args.GetArg("-con_mandatorycoinbase", ""));
consensus.mandatory_coinbase_destination = CScript(man_bytes.begin(), man_bytes.end()); // Blank script allows any coinbase destination

consensus.allow_any_fee = args.GetBoolArg("-con_allow_any_fee", consensus.allow_any_fee);

// Custom chains connect coinbase outputs to db by default
consensus.connect_genesis_outputs = args.GetIntArg("-con_connect_genesis_outputs", true);

Expand Down Expand Up @@ -1515,6 +1517,8 @@ class CLiquidV1TestParams : public CLiquidV1Params {
consensus.mandatory_coinbase_destination = CScript(man_bytes.begin(), man_bytes.end()); // Blank script allows any coinbase destination
}

consensus.allow_any_fee = args.GetBoolArg("-con_allow_any_fee", consensus.allow_any_fee);

consensus.connect_genesis_outputs = args.GetIntArg("-con_connect_genesis_outputs", consensus.connect_genesis_outputs);

initialFreeCoins = args.GetIntArg("-initialfreecoins", initialFreeCoins);
Expand Down
1 change: 1 addition & 0 deletions src/chainparamsbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
argsman.AddArg("-con_signed_blocks", "Signed blockchain. Uses input of `-signblockscript` to define what signatures are necessary to solve it.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-signblockscript", "Signed blockchain enumberance. Only active when `-con_signed_blocks` set to true.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-con_max_block_sig_size", "Max allowed witness data for the signed block header.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-con_allow_any_fee", "Allow any fee value for any asset", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);

argsman.AddArg("-con_has_parent_chain", "Whether or not there is a parent chain.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-parentgenesisblockhash", "The genesis blockhash of the parent chain.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
Expand Down
10 changes: 7 additions & 3 deletions src/confidential_validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ class CSecp256k1Init {
static CSecp256k1Init instance_of_csecp256k1;
}

bool HasValidFee(const CTransaction& tx) {
bool HasValidFee(const CTransaction& tx, bool allow_any_fee) {
CAmountMap totalFee;
for (unsigned int i = 0; i < tx.vout.size(); i++) {
CAmount fee = 0;
if (tx.vout[i].IsFee()) {
fee = tx.vout[i].nValue.GetAmount();
if (fee == 0 || !MoneyRange(fee))
if (!allow_any_fee && (fee == 0 || !MoneyRange(fee))) {
return false;
}
totalFee[tx.vout[i].nAsset.GetAsset()] += fee;
if (!MoneyRange(totalFee)) {
if (!allow_any_fee && !MoneyRange(totalFee)) {
return false;
}
if(allow_any_fee && fee < 0) {
return false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/confidential_validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


// Check if explicit TX fees overflow or are negative
bool HasValidFee(const CTransaction& tx);
bool HasValidFee(const CTransaction& tx, bool allow_any_fee);

// Compute the fee from the explicit fee outputs. Must call HasValidFee first
CAmountMap GetFeeMap(const CTransaction& tx);
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ struct Params {
size_t total_valid_epochs = 1;
bool elements_mode = false;
bool start_p2wsh_script = false;
bool allow_any_fee = false;
};

} // namespace Consensus
Expand Down
6 changes: 3 additions & 3 deletions src/consensus/tx_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
return nSigOps;
}

bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set<std::pair<uint256, COutPoint>>& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore, bool fScriptChecks, const std::vector<std::pair<CScript, CScript>>& fedpegscripts)
bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set<std::pair<uint256, COutPoint>>& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore, bool fScriptChecks, const std::vector<std::pair<CScript, CScript>>& fedpegscripts, bool allow_any_fee)
{
// are the actual inputs available?
if (!inputs.HaveInputs(tx)) {
Expand Down Expand Up @@ -245,7 +245,7 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,

if (g_con_elementsmode) {
// Tally transaction fees
if (!HasValidFee(tx)) {
if (!HasValidFee(tx, allow_any_fee)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
}

Expand All @@ -254,7 +254,7 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-ne-out", "value in != value out");
}
fee_map += GetFeeMap(tx);
if (!MoneyRange(fee_map)) {
if (allow_any_fee && !MoneyRange(fee_map)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-block-total-fee-outofrange");
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/consensus/tx_verify.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace Consensus {
* @param[out] fee_map Set to the transaction fee if successful.
* Preconditions: tx.IsCoinBase() is false.
*/
[[nodiscard] ]bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set<std::pair<uint256, COutPoint>>& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore, bool fScriptChecks, const std::vector<std::pair<CScript, CScript>>& fedpegscripts);
[[nodiscard] ]bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set<std::pair<uint256, COutPoint>>& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore, bool fScriptChecks, const std::vector<std::pair<CScript, CScript>>& fedpegscripts, bool allow_any_fee);
} // namespace Consensus

/** Auxiliary functions for transaction validation (ideally should not be exposed) */
Expand Down
2 changes: 1 addition & 1 deletion src/test/fuzz/coins_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
}
std::vector<std::pair<CScript, CScript>> fedpegscripts; // ELEMENTS: we ought to populate this and have a more useful fuzztest
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
if (Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_map, setPeginsSpent, NULL, false, true, fedpegscripts)) {
if (Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_map, setPeginsSpent, NULL, false, true, fedpegscripts, false)) {
assert(MoneyRange(tx_fee_map));
}
},
Expand Down
6 changes: 3 additions & 3 deletions src/test/pegin_witness_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,15 @@ BOOST_AUTO_TEST_CASE(witness_valid)
CCoinsViewCache coins(&coinsDummy);
// Get the latest block index to look up fedpegscripts
// For these tests, should be genesis-block-hardcoded consensus.fedpegscript
BOOST_CHECK(Consensus::CheckTxInputs(tx, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts));
BOOST_CHECK(Consensus::CheckTxInputs(tx, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts, false));
BOOST_CHECK(setPeginsSpent.size() == 1);
setPeginsSpent.clear();

// Strip pegin_witness
CMutableTransaction mtxn(tx);
mtxn.witness.vtxinwit[0].m_pegin_witness.SetNull();
CTransaction tx2(mtxn);
BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts));
BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts, false));
BOOST_CHECK(setPeginsSpent.empty());

// Invalidate peg-in (and spending) authorization by pegin marker.
Expand All @@ -140,7 +140,7 @@ BOOST_AUTO_TEST_CASE(witness_valid)
CMutableTransaction mtxn2(tx);
mtxn2.vin[0].m_is_pegin = false;
CTransaction tx3(mtxn2);
BOOST_CHECK(!Consensus::CheckTxInputs(tx3, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts));
BOOST_CHECK(!Consensus::CheckTxInputs(tx3, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts, false));
BOOST_CHECK(setPeginsSpent.empty());


Expand Down
2 changes: 1 addition & 1 deletion src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@ void CTxMemPool::check(const CBlockIndex* active_chain_tip, const CCoinsViewCach
const auto& fedpegscripts = GetValidFedpegScripts(active_chain_tip, Params().GetConsensus(), true /* nextblock_validation */);
bool cacheStore = true;
bool fScriptChecks = true;
assert(Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, fee_map, setPeginsSpent, nullptr, cacheStore, fScriptChecks, fedpegscripts));
assert(Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, fee_map, setPeginsSpent, nullptr, cacheStore, fScriptChecks, fedpegscripts, Params().GetConsensus().allow_any_fee));
for (const auto& input: tx.vin) mempoolDuplicate.SpendCoin(input.prevout);
AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max());
}
Expand Down
6 changes: 4 additions & 2 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,10 +855,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)

// The mempool holds txs for the next block, so pass height+1 to CheckTxInputs
CAmountMap fee_map;
if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_chain.Height() + 1, fee_map, setPeginsSpent, NULL, true, true, fedpegscripts)) {
if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_chain.Height() + 1, fee_map, setPeginsSpent, NULL, true, true, fedpegscripts, Params().GetConsensus().allow_any_fee)) {
return false; // state filled in by CheckTxInputs
}

LogPrintf("mand coin: %u\n", Params().GetConsensus().allow_any_fee);

// ELEMENTS: extra policy check for consistency between issuances and their rangeproof
if (fRequireStandard) {
for (unsigned i = 0; i < std::min(tx.witness.vtxinwit.size(), tx.vin.size()); i++) {
Expand Down Expand Up @@ -2350,7 +2352,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
TxValidationState tx_state;
if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, fee_map,
setPeginsSpent == NULL ? setPeginsSpentDummy : *setPeginsSpent,
g_parallel_script_checks ? &vChecks : NULL, fCacheResults, fScriptChecks, fedpegscripts)) {
g_parallel_script_checks ? &vChecks : NULL, fCacheResults, fScriptChecks, fedpegscripts, Params().GetConsensus().allow_any_fee)) {
// Any transaction validation failure in ConnectBlock is a block consensus failure
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
tx_state.GetRejectReason(), tx_state.GetDebugMessage());
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/rpc/transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ RPCHelpMan gettransaction()
CAmountMap nCredit = CachedTxGetCredit(*pwallet, wtx, filter);
CAmountMap nDebit = CachedTxGetDebit(*pwallet, wtx, filter);
CAmountMap nNet = nCredit - nDebit;
CHECK_NONFATAL(HasValidFee(*wtx.tx));
CHECK_NONFATAL(HasValidFee(*wtx.tx,Params().GetConsensus().allow_any_fee));
CAmountMap nFee = CachedTxIsFromMe(*pwallet, wtx, filter) ? CAmountMap() - GetFeeMap(*wtx.tx) : CAmountMap();
if (!g_con_elementsmode) {
CAmount total_out = 0;
Expand Down