Skip to content

Commit 12a0625

Browse files
committed
feat!: remove dependency of Asset Lock txes on CCreditPool
There's no more check when tx is accepted in mempool. Functional and unit tests updated accordingly
1 parent 0e171f1 commit 12a0625

File tree

10 files changed

+46
-43
lines changed

10 files changed

+46
-43
lines changed

src/evo/assetlocktx.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
#include <evo/assetlocktx.h>
66
#include <evo/specialtx.h>
7-
#include <evo/creditpool.h>
87

98
#include <consensus/params.h>
109

@@ -17,18 +16,20 @@
1716
#include <llmq/utils.h>
1817
#include <llmq/quorums.h>
1918

19+
#include <util/ranges_set.h>
20+
2021
#include <algorithm>
2122

2223
/**
2324
* Common code for Asset Lock and Asset Unlock
2425
*/
25-
bool CheckAssetLockUnlockTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCreditPool& creditPool, TxValidationState& state)
26+
bool CheckAssetLockUnlockTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const std::optional<CRangesSet>& indexes, TxValidationState& state)
2627
{
2728
switch (tx.nType) {
2829
case TRANSACTION_ASSET_LOCK:
2930
return CheckAssetLockTx(tx, state);
3031
case TRANSACTION_ASSET_UNLOCK:
31-
return CheckAssetUnlockTx(tx, pindexPrev, creditPool, state);
32+
return CheckAssetUnlockTx(tx, pindexPrev, indexes, state);
3233
default:
3334
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-not-asset-locks-at-all");
3435
}
@@ -142,8 +143,10 @@ bool CAssetUnlockPayload::VerifySig(const uint256& msgHash, const CBlockIndex* p
142143
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-assetunlock-not-verified");
143144
}
144145

145-
bool CheckAssetUnlockTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCreditPool& creditPool, TxValidationState& state)
146+
bool CheckAssetUnlockTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const std::optional<CRangesSet>& indexes, TxValidationState& state)
146147
{
148+
// Some checks depends from blockchain status also, such as `known indexes` and `withdrawal limits`
149+
// They are omitted here and done by CCreditPool
147150
if (tx.nType != TRANSACTION_ASSET_UNLOCK) {
148151
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-assetunlocktx-type");
149152
}
@@ -165,7 +168,7 @@ bool CheckAssetUnlockTx(const CTransaction& tx, const CBlockIndex* pindexPrev, c
165168
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-assetunlocktx-version");
166169
}
167170

168-
if (creditPool.indexes.Contains(assetUnlockTx.getIndex())) {
171+
if (indexes != std::nullopt && indexes->Contains(assetUnlockTx.getIndex())) {
169172
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-assetunlock-duplicated-index");
170173
}
171174

src/evo/assetlocktx.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
#include <tinyformat.h>
1515
#include <univalue.h>
1616

17+
#include <optional>
18+
1719
class CBlockIndex;
18-
struct CCreditPool;
20+
class CRangesSet;
1921

2022
class CAssetLockPayload
2123
{
@@ -166,8 +168,8 @@ class CAssetUnlockPayload
166168
};
167169

168170
bool CheckAssetLockTx(const CTransaction& tx, TxValidationState& state);
169-
bool CheckAssetUnlockTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCreditPool& creditPool, TxValidationState& state);
170-
bool CheckAssetLockUnlockTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCreditPool& creditPool, TxValidationState& state);
171+
bool CheckAssetUnlockTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const std::optional<CRangesSet>& indexes, TxValidationState& state);
172+
bool CheckAssetLockUnlockTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const std::optional<CRangesSet>& indexes, TxValidationState& state);
171173
bool GetAssetUnlockFee(const CTransaction& tx, CAmount& txfee, TxValidationState& state);
172174

173175
#endif // BITCOIN_EVO_ASSETLOCKTX_H

src/evo/creditpool.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ bool CCreditPoolDiff::ProcessTransaction(const CTransaction& tx, TxValidationSta
278278

279279
if (tx.nType != TRANSACTION_ASSET_LOCK && tx.nType != TRANSACTION_ASSET_UNLOCK) return true;
280280

281-
if (!CheckAssetLockUnlockTx(tx, pindex, this->pool, state)) {
281+
if (!CheckAssetLockUnlockTx(tx, pindex, pool.indexes, state)) {
282282
// pass the state returned by the function above
283283
return false;
284284
}

src/evo/specialtxman.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include <primitives/block.h>
2020
#include <validation.h>
2121

22-
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache& view, const CCreditPool& creditPool, bool check_sigs, TxValidationState& state)
22+
static bool CheckSpecialTxInner(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache& view, const std::optional<CRangesSet>& indexes, bool check_sigs, TxValidationState& state)
2323
{
2424
AssertLockHeld(cs_main);
2525

@@ -54,7 +54,7 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const
5454
if (!llmq::utils::IsV20Active(pindexPrev)) {
5555
return state.Invalid(TxValidationResult::TX_CONSENSUS, "assetlocks-before-v20");
5656
}
57-
return CheckAssetLockUnlockTx(tx, pindexPrev, creditPool, state);
57+
return CheckAssetLockUnlockTx(tx, pindexPrev, indexes, state);
5858
}
5959
} catch (const std::exception& e) {
6060
LogPrintf("%s -- failed: %s\n", __func__, e.what());
@@ -64,6 +64,12 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const
6464
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-tx-type-check");
6565
}
6666

67+
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache& view, bool check_sigs, TxValidationState& state)
68+
{
69+
AssertLockHeld(cs_main);
70+
return CheckSpecialTxInner(tx, pindexPrev, view, std::nullopt, check_sigs, state);
71+
}
72+
6773
bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, TxValidationState& state)
6874
{
6975
if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL) {
@@ -142,7 +148,7 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll
142148
TxValidationState tx_state;
143149
// At this moment CheckSpecialTx() and ProcessSpecialTx() may fail by 2 possible ways:
144150
// consensus failures and "TX_BAD_SPECIAL"
145-
if (!CheckSpecialTx(*ptr_tx, pindex->pprev, view, creditPool, fCheckCbTxMerleRoots, tx_state)) {
151+
if (!CheckSpecialTxInner(*ptr_tx, pindex->pprev, view, creditPool.indexes, fCheckCbTxMerleRoots, tx_state)) {
146152
assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS || tx_state.GetResult() == TxValidationResult::TX_BAD_SPECIAL);
147153
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(),
148154
strprintf("Special Transaction check failed (tx hash %s) %s", ptr_tx->GetHash().ToString(), tx_state.GetDebugMessage()));

src/evo/specialtxman.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
class BlockValidationState;
1313
class CBlock;
1414
class CBlockIndex;
15-
struct CCreditPool;
1615
class CCoinsViewCache;
1716
class TxValidationState;
1817
namespace llmq {
@@ -25,7 +24,7 @@ struct Params;
2524

2625
extern RecursiveMutex cs_main;
2726

28-
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache& view, const CCreditPool& pool, bool check_sigs,
27+
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache& view, bool check_sigs,
2928
TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
3029
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq::CQuorumBlockProcessor& quorum_block_processor, const llmq::CChainLocksHandler& chainlock_handler,
3130
const Consensus::Params& consensusParams, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots,

src/rpc/evo.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include <chainparams.h>
88
#include <consensus/validation.h>
99
#include <core_io.h>
10-
#include <evo/creditpool.h>
1110
#include <evo/deterministicmns.h>
1211
#include <evo/dmn_types.h>
1312
#include <evo/providertx.h>
@@ -329,10 +328,8 @@ static std::string SignAndSendSpecialTx(const JSONRPCRequest& request, const Cha
329328
{
330329
LOCK(cs_main);
331330

332-
CCreditPool creditPool = creditPoolManager->GetCreditPool(chainman.ActiveChain().Tip(), Params().GetConsensus());
333-
334331
TxValidationState state;
335-
if (!CheckSpecialTx(CTransaction(tx), chainman.ActiveChain().Tip(), chainman.ActiveChainstate().CoinsTip(), creditPool, true, state)) {
332+
if (!CheckSpecialTx(CTransaction(tx), chainman.ActiveChain().Tip(), chainman.ActiveChainstate().CoinsTip(), true, state)) {
336333
throw std::runtime_error(state.ToString());
337334
}
338335
} // cs_main

src/test/evo_assetlocks_tests.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
#include <amount.h>
88
#include <consensus/tx_check.h>
99
#include <evo/assetlocktx.h>
10-
#include <evo/creditpool.h>
1110
#include <policy/settings.h>
1211
#include <script/script.h>
1312
#include <script/signingprovider.h>
13+
#include <util/ranges_set.h>
1414
#include <validation.h> // for ::ChainActive()
1515

1616
#include <boost/test/unit_test.hpp>
1717

18+
19+
#include <optional>
1820
//
1921
// Helper: create two dummy transactions, each with
2022
// two outputs. The first has 11 and 50 CENT outputs
@@ -314,8 +316,7 @@ BOOST_FIXTURE_TEST_CASE(evo_assetunlock, TestChain100Setup)
314316
BOOST_CHECK(tx_state.IsValid());
315317

316318
const CBlockIndex *block_index = ::ChainActive().Tip();
317-
CCreditPool pool;
318-
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(tx), block_index, pool, tx_state));
319+
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(tx), block_index, std::nullopt, tx_state));
319320
BOOST_CHECK(tx_state.GetRejectReason() == "bad-assetunlock-quorum-hash");
320321

321322
{
@@ -333,7 +334,7 @@ BOOST_FIXTURE_TEST_CASE(evo_assetunlock, TestChain100Setup)
333334
std::string reason;
334335
BOOST_CHECK(IsStandardTx(CTransaction(tx), reason));
335336

336-
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txNonemptyInput), block_index, pool, tx_state));
337+
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txNonemptyInput), block_index, std::nullopt, tx_state));
337338
BOOST_CHECK(tx_state.GetRejectReason() == "bad-assetunlocktx-have-input");
338339
}
339340

@@ -348,7 +349,7 @@ BOOST_FIXTURE_TEST_CASE(evo_assetunlock, TestChain100Setup)
348349
// Wrong type "Asset Lock TX" instead "Asset Unlock TX"
349350
CMutableTransaction txWrongType = tx;
350351
txWrongType.nType = TRANSACTION_ASSET_LOCK;
351-
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txWrongType), block_index, pool, tx_state));
352+
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txWrongType), block_index, std::nullopt, tx_state));
352353
BOOST_CHECK(tx_state.GetRejectReason() == "bad-assetunlocktx-type");
353354

354355
// Check version of tx and payload
@@ -363,10 +364,10 @@ BOOST_FIXTURE_TEST_CASE(evo_assetunlock, TestChain100Setup)
363364
CMutableTransaction txWrongVersion = tx;
364365
SetTxPayload(txWrongVersion, unlockPayload_tmp);
365366
if (payload_version != 1) {
366-
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txWrongVersion), block_index, pool, tx_state));
367+
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txWrongVersion), block_index, std::nullopt, tx_state));
367368
BOOST_CHECK(tx_state.GetRejectReason() == "bad-assetunlocktx-version");
368369
} else {
369-
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txWrongVersion), block_index, pool, tx_state));
370+
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txWrongVersion), block_index, std::nullopt, tx_state));
370371
BOOST_CHECK(tx_state.GetRejectReason() == "bad-assetunlock-quorum-hash");
371372
}
372373
}
@@ -382,14 +383,23 @@ BOOST_FIXTURE_TEST_CASE(evo_assetunlock, TestChain100Setup)
382383
out.scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
383384
}
384385

385-
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txManyOutputs), block_index, pool, tx_state));
386+
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txManyOutputs), block_index, std::nullopt, tx_state));
387+
BOOST_CHECK(tx_state.GetRejectReason() == "bad-assetunlock-quorum-hash");
388+
389+
// Basic checks for CRangesSet
390+
CRangesSet indexes;
391+
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txManyOutputs), block_index, indexes, tx_state));
386392
BOOST_CHECK(tx_state.GetRejectReason() == "bad-assetunlock-quorum-hash");
393+
BOOST_CHECK(indexes.Add(0x001122334455667788L));
394+
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txManyOutputs), block_index, indexes, tx_state));
395+
BOOST_CHECK(tx_state.GetRejectReason() == "bad-assetunlock-duplicated-index");
396+
387397

388398
// Should not be more than 32 withdrawal in one transaction
389399
txManyOutputs.vout.resize(outputsLimit + 1);
390400
txManyOutputs.vout.back().nValue = CENT;
391401
txManyOutputs.vout.back().scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
392-
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txManyOutputs), block_index, pool, tx_state));
402+
BOOST_CHECK(!CheckAssetUnlockTx(CTransaction(txManyOutputs), block_index, std::nullopt, tx_state));
393403
BOOST_CHECK(tx_state.GetRejectReason() == "bad-assetunlocktx-too-many-outs");
394404
}
395405

src/validation.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
#include <masternode/payments.h>
5353
#include <masternode/sync.h>
5454

55-
#include <evo/creditpool.h>
5655
#include <evo/evodb.h>
5756
#include <evo/specialtx.h>
5857
#include <evo/specialtxman.h>
@@ -712,7 +711,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
712711
}
713712
}
714713
}
715-
CCreditPool creditPool = creditPoolManager->GetCreditPool(::ChainActive().Tip(), chainparams.GetConsensus());
716714
LockPoints lp;
717715
m_view.SetBackend(m_viewmempool);
718716

@@ -827,7 +825,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
827825
// DoS scoring a node for non-critical errors, e.g. duplicate keys because a TX is received that was already
828826
// mined
829827
// NOTE: we use UTXO here and do NOT allow mempool txes as masternode collaterals
830-
if (!CheckSpecialTx(tx, m_active_chainstate.m_chain.Tip(), m_active_chainstate.CoinsTip(), creditPool, true, state))
828+
if (!CheckSpecialTx(tx, m_active_chainstate.m_chain.Tip(), m_active_chainstate.CoinsTip(), true, state))
831829
return false;
832830

833831
if (m_pool.existsProviderTxConflict(tx)) {

test/functional/feature_asset_locks.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ def run_test(self):
298298
asset_unlock_tx_too_big_fee = self.create_assetunlock(104, COIN, pubkey, fee=int(Decimal("0.1") * COIN))
299299
asset_unlock_tx_zero_fee = self.create_assetunlock(105, COIN, pubkey, fee=0)
300300
asset_unlock_tx_duplicate_index = copy.deepcopy(asset_unlock_tx)
301+
# modify this tx with duplicated index to make a hash of tx different, otherwise tx would be refused too early
301302
asset_unlock_tx_duplicate_index.vout[0].nValue += COIN
302303
too_late_height = node.getblock(node.getbestblockhash())["height"] + 48
303304

@@ -331,12 +332,6 @@ def run_test(self):
331332
expected_error = "Transaction already in block chain",
332333
reason = "double copy")
333334

334-
self.check_mempool_result(tx=asset_unlock_tx_duplicate_index,
335-
result_expected={'allowed': False, 'reject-reason' : 'bad-assetunlock-duplicated-index'})
336-
self.send_tx(asset_unlock_tx_duplicate_index,
337-
expected_error = "bad-assetunlock-duplicated-index",
338-
reason = "double index")
339-
340335
self.log.info("Mining next quorum to check tx 'asset_unlock_tx_late' is still valid...")
341336
self.mine_quorum()
342337
self.log.info("Checking credit pool amount is same...")
@@ -411,11 +406,6 @@ def run_test(self):
411406
assert txid_in_block in block['tx']
412407
self.validate_credit_pool_balance(0)
413408

414-
self.log.info("After many blocks duplicated tx still should not be mined")
415-
self.send_tx(asset_unlock_tx_duplicate_index,
416-
expected_error = "bad-assetunlock-duplicated-index",
417-
reason = "double index")
418-
419409
self.log.info("Forcibly mine asset_unlock_tx_full and ensure block is invalid...")
420410
self.create_and_check_block([asset_unlock_tx_duplicate_index], expected_error = "bad-assetunlock-duplicated-index")
421411

test/lint/lint-circular-dependencies.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,8 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
8181
"evo/deterministicmns -> llmq/utils -> net -> evo/deterministicmns"
8282
"policy/policy -> policy/settings -> policy/policy"
8383
"evo/specialtxman -> validation -> evo/specialtxman"
84-
"evo/creditpool -> validation -> evo/creditpool"
8584
"consensus/tx_verify -> evo/assetlocktx -> validation -> consensus/tx_verify"
8685
"consensus/tx_verify -> evo/assetlocktx -> llmq/quorums -> net_processing -> txmempool -> consensus/tx_verify"
87-
"evo/assetlocktx -> evo/creditpool -> evo/assetlocktx"
8886
"evo/assetlocktx -> llmq/quorums -> net_processing -> txmempool -> evo/assetlocktx"
8987

9088
"evo/simplifiedmns -> llmq/blockprocessor -> net_processing -> llmq/snapshot -> evo/simplifiedmns"

0 commit comments

Comments
 (0)