Skip to content

Commit

Permalink
Spork for managing Spark functionality (#1398)
Browse files Browse the repository at this point in the history
* Introduce sporks "spark" and "sparktransparentlimit"

* Added spark and sparktransparentlimit to allowed spork features

* Added test for spark spork

* Fixes for spark limit block template creation

* Fixed test instability

* Additional cleanup in tests
  • Loading branch information
psolstice authored Jan 25, 2024
1 parent 2957748 commit 28dbfb3
Show file tree
Hide file tree
Showing 7 changed files with 335 additions and 30 deletions.
32 changes: 30 additions & 2 deletions src/evo/spork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ static bool IsTransactionAllowed(const CTransaction &tx, const ActiveSporkMap &s
}
}
}
else if (tx.IsSparkTransaction()) {
if (sporkMap.count(CSporkAction::featureSpark) > 0)
return state.DoS(100, false, REJECT_CONFLICT, "txn-spark-disabled", false, "Spark transactions are disabled at the moment");

if (tx.IsSparkSpend()) {
const auto &limitSpork = sporkMap.find(CSporkAction::featureSparkTransparentLimit);
if (limitSpork != sporkMap.cend()) {
if (spark::GetSpendTransparentAmount(tx) > (CAmount)limitSpork->second.second)
return state.DoS(100, false, REJECT_CONFLICT, "txn-spark-disabled", false, "Spark transaction is over the transparent limit");
}
}
}
return true;
}

Expand Down Expand Up @@ -176,8 +188,24 @@ bool CSporkManager::IsBlockAllowed(const CBlock &block, const CBlockIndex *pinde
totalTransparentOutput += lelantus::GetSpendTransparentAmount(*tx);
}

return totalTransparentOutput <= CAmount(limit) ? true :
state.DoS(100, false, REJECT_CONFLICT, "txn-lelantus-disabled", false, "Block is over the transparent output limit because of existing spork");
if (totalTransparentOutput > CAmount(limit))
return state.DoS(100, false, REJECT_CONFLICT, "txn-lelantus-disabled", false, "Block is over the transparent output limit because of existing spork");
}

if (pindex->activeDisablingSporks.count(CSporkAction::featureSparkTransparentLimit) > 0) {
// limit total transparent output of lelantus joinsplit
int64_t limit = pindex->activeDisablingSporks.at(CSporkAction::featureSparkTransparentLimit).second;
CAmount totalTransparentOutput = 0;

for (const auto &tx: block.vtx) {
if (!tx->IsSparkSpend())
continue;

totalTransparentOutput += spark::GetSpendTransparentAmount(*tx);
}

if (totalTransparentOutput > CAmount(limit))
return state.DoS(100, false, REJECT_CONFLICT, "txn-spark-disabled", false, "Block is over the transparent output limit because of existing spork");
}

return true;
Expand Down
2 changes: 2 additions & 0 deletions src/evo/spork.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ struct CSporkAction
static constexpr const char *featureLelantusTransparentLimit = "lelantustransparentlimit";
static constexpr const char *featureChainlocks = "chainlocks";
static constexpr const char *featureInstantSend = "instantsend";
static constexpr const char *featureSpark = "spark";
static constexpr const char *featureSparkTransparentLimit = "sparktransparentlimit";

enum ActionType {
sporkDisable = 1,
Expand Down
63 changes: 39 additions & 24 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1003,34 +1003,49 @@ void BlockAssembler::FillBlackListForBlockTemplate() {

// Now if we have limit on lelantus transparent outputs scan mempool and drop all the transactions exceeding the limit
if (sporkMap.count(CSporkAction::featureLelantusTransparentLimit) > 0) {
CAmount limit = sporkMap[CSporkAction::featureLelantusTransparentLimit].second;
BlacklistTxsExceedingLimit(sporkMap[CSporkAction::featureLelantusTransparentLimit].second,
[](const CTransaction &tx)->bool { return tx.IsLelantusJoinSplit(); },
[](const CTransaction &tx)->CAmount { return lelantus::GetSpendTransparentAmount(tx); });
}

std::vector<CTxMemPool::txiter> joinSplitTxs;
for (CTxMemPool::txiter mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) {
if (txBlackList.count(mi) == 0 && mi->GetTx().IsLelantusJoinSplit())
joinSplitTxs.push_back(mi);
}
// Same for spark spends
if (sporkMap.count(CSporkAction::featureSparkTransparentLimit) > 0) {
BlacklistTxsExceedingLimit(sporkMap[CSporkAction::featureSparkTransparentLimit].second,
[](const CTransaction &tx)->bool { return tx.IsSparkSpend(); },
[](const CTransaction &tx)->CAmount { return spark::GetSpendTransparentAmount(tx); });
}
}

// sort join splits in order of their transparent outputs so large txs won't block smaller ones
// from getting into the mempool
std::sort(joinSplitTxs.begin(), joinSplitTxs.end(),
[](CTxMemPool::txiter a, CTxMemPool::txiter b) -> bool {
return lelantus::GetSpendTransparentAmount(a->GetTx()) < lelantus::GetSpendTransparentAmount(b->GetTx());
});

CAmount transparentAmount = 0;
std::vector<CTxMemPool::txiter>::const_iterator it;
for (it = joinSplitTxs.cbegin(); it != joinSplitTxs.cend(); ++it) {
CAmount output = lelantus::GetSpendTransparentAmount((*it)->GetTx());
if (transparentAmount + output > limit)
break;
transparentAmount += output;
}
void BlockAssembler::BlacklistTxsExceedingLimit(CAmount limit,
std::function<bool (const CTransaction &)> txTypeFilter,
std::function<CAmount (const CTransaction &)> txAmount) {

std::vector<CTxMemPool::txiter> txList;
for (CTxMemPool::txiter mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) {
if (txBlackList.count(mi) == 0 && txTypeFilter(mi->GetTx()))
txList.push_back(mi);
}

// found all the joinsplit transaction fitting in the limit, blacklist the rest
while (it != joinSplitTxs.cend())
mempool.CalculateDescendants(*it++, txBlackList);
// sort transactions in order of their transparent outputs so large txs won't block smaller ones
// from getting into the mempool
std::sort(txList.begin(), txList.end(),
[=](CTxMemPool::txiter a, CTxMemPool::txiter b) -> bool {
return txAmount(a->GetTx()) < txAmount(b->GetTx());
});

CAmount transparentAmount = 0;
std::vector<CTxMemPool::txiter>::const_iterator it;
for (it = txList.cbegin(); it != txList.cend(); ++it) {
CAmount output = txAmount((*it)->GetTx());
if (transparentAmount + output > limit)
break;
transparentAmount += output;
}

// found all the private transaction fitting in the limit, blacklist the rest
while (it != txList.cend())
mempool.CalculateDescendants(*it++, txBlackList);

}

//////////////////////////////////////////////////////////////////////////////
Expand Down
5 changes: 5 additions & 0 deletions src/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,11 @@ class BlockAssembler

/** Fill txBlackList set */
void FillBlackListForBlockTemplate();

/** Ensure spark/lelantus txs don't exceed specific limit */
void BlacklistTxsExceedingLimit(CAmount limit,
std::function<bool (const CTransaction &)> txTypeFilter,
std::function<CAmount (const CTransaction &)> txAmount);
};

/** Modify the extranonce in a block */
Expand Down
4 changes: 3 additions & 1 deletion src/rpc/rpcevo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,9 @@ UniValue spork(const JSONRPCRequest& request)
CSporkAction::featureLelantus,
CSporkAction::featureChainlocks,
CSporkAction::featureInstantSend,
CSporkAction::featureLelantusTransparentLimit
CSporkAction::featureLelantusTransparentLimit,
CSporkAction::featureSpark,
CSporkAction::featureSparkTransparentLimit
};

for (const CSporkAction &action: sporkTx.actions) {
Expand Down
Loading

0 comments on commit 28dbfb3

Please sign in to comment.