Skip to content
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

Double mint fix #744

Merged
merged 6 commits into from
Oct 23, 2019
Merged
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
40 changes: 32 additions & 8 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,7 @@ bool AcceptToMemoryPoolWorker(
// V3 sigma spends.
sigma::CSigmaState *sigmaState = sigma::CSigmaState::GetState();
vector<Scalar> zcSpendSerialsV3;
vector<GroupElement> zcMintPubcoinsV3;
{
LOCK(pool.cs); // protect pool.mapNextTx
if (tx.IsZerocoinSpend()) {
Expand Down Expand Up @@ -1408,6 +1409,23 @@ bool AcceptToMemoryPoolWorker(
}
}
}

BOOST_FOREACH(const CTxOut &txout, tx.vout)
{
if (txout.scriptPubKey.IsSigmaMint()) {
GroupElement pubCoinValue;
try {
pubCoinValue = sigma::ParseSigmaMintScript(txout.scriptPubKey);
} catch (std::invalid_argument&) {
return state.DoS(100, false, PUBCOIN_NOT_VALIDATE, "bad-txns-zerocoin");
}
if (!sigmaState->CanAddMintToMempool(pubCoinValue)) {
LogPrintf("AcceptToMemoryPool(): sigma mint with the same value %s is already in the mempool\n", pubCoinValue.tostring());
return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict");
}
zcMintPubcoinsV3.push_back(pubCoinValue);
}
}
}

{
Expand Down Expand Up @@ -1833,16 +1851,10 @@ bool AcceptToMemoryPoolWorker(
}
#endif
}
if(markZcoinSpendTransactionSerial)
sigmaState->AddMintsToMempool(zcMintPubcoinsV3);
#ifdef ENABLE_WALLET
vector<GroupElement> zcMintPubcoinsV3;
if(tx.IsSigmaMint()){
BOOST_FOREACH(const CTxOut &txout, tx.vout)
{
if(txout.scriptPubKey.IsSigmaMint()){
GroupElement pubCoinValue = sigma::ParseSigmaMintScript(txout.scriptPubKey);
zcMintPubcoinsV3.push_back(pubCoinValue);
}
}
if (zwalletMain) {
LogPrintf("Updating mint state from Mempool..");
zwalletMain->GetTracker().UpdateMintStateFromMempool(zcMintPubcoinsV3);
Expand Down Expand Up @@ -3172,6 +3184,18 @@ bool ConnectBlock(const CBlock &block, CValidationState &state, CBlockIndex *pin
sigmaState->RemoveSpendFromMempool(zcSpendSerial);
}
}
BOOST_FOREACH(const CTxOut &txout, tx.vout)
{
if (txout.scriptPubKey.IsSigmaMint()) {
GroupElement pubCoinValue;
try {
pubCoinValue = sigma::ParseSigmaMintScript(txout.scriptPubKey);
} catch (std::invalid_argument&) {
return state.DoS(100, false, PUBCOIN_NOT_VALIDATE, "bad-txns-zerocoin");
}
sigmaState->RemoveMintFromMempool(pubCoinValue);
}
}
}

int64_t nTime6 = GetTimeMicros();
Expand Down
15 changes: 15 additions & 0 deletions src/sigma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,16 @@ void CSigmaState::RemoveSpendFromMempool(const Scalar& coinSerial) {
mempoolCoinSerials.erase(coinSerial);
}

void CSigmaState::AddMintsToMempool(const vector<GroupElement>& pubCoins){
BOOST_FOREACH(const GroupElement& pubCoin, pubCoins){
mempoolMints.insert(pubCoin);
}
}

void CSigmaState::RemoveMintFromMempool(const GroupElement& pubCoin){
mempoolMints.erase(pubCoin);
}

uint256 CSigmaState::GetMempoolConflictingTxHash(const Scalar& coinSerial) {
if (mempoolCoinSerials.count(coinSerial) == 0)
return uint256();
Expand All @@ -1078,10 +1088,15 @@ bool CSigmaState::CanAddSpendToMempool(const Scalar& coinSerial) {
return !IsUsedCoinSerial(coinSerial) && mempoolCoinSerials.count(coinSerial) == 0;
}

bool CSigmaState::CanAddMintToMempool(const GroupElement& pubCoin){
return mempoolMints.count(pubCoin) == 0;
}

void CSigmaState::Reset() {
coinGroups.clear();
latestCoinIds.clear();
mempoolCoinSerials.clear();
mempoolMints.clear();
containers.Reset();
}

Expand Down
10 changes: 10 additions & 0 deletions src/sigma.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ friend bool BuildSigmaStateFromIndex(CChain *, set<CBlockIndex *> &);
// Check if there is a conflicting tx in the blockchain or mempool
bool CanAddSpendToMempool(const Scalar& coinSerial);

bool CanAddMintToMempool(const GroupElement& pubCoin);

// Add spend into the mempool.
// Check if there is a coin with such serial in either blockchain or mempool
bool AddSpendToMempool(const Scalar &coinSerial, uint256 txHash);
Expand All @@ -169,12 +171,18 @@ friend bool BuildSigmaStateFromIndex(CChain *, set<CBlockIndex *> &);
// Check if there is a coin with such serial in either blockchain or mempool
bool AddSpendToMempool(const vector<Scalar> &coinSerials, uint256 txHash);

void AddMintsToMempool(const vector<GroupElement>& pubCoins);

void RemoveMintFromMempool(const GroupElement& pubCoin);

// Get conflicting tx hash by coin serial number
uint256 GetMempoolConflictingTxHash(const Scalar& coinSerial);

// Remove spend from the mempool (usually as the result of adding tx to the block)
void RemoveSpendFromMempool(const Scalar& coinSerial);



static CSigmaState* GetState();

int GetLatestCoinID(sigma::CoinDenomination denomination) const;
Expand All @@ -199,6 +207,8 @@ friend bool BuildSigmaStateFromIndex(CChain *, set<CBlockIndex *> &);
// serials of spends currently in the mempool mapped to tx hashes
std::unordered_map<Scalar, uint256, CScalarHash> mempoolCoinSerials;

std::unordered_set<GroupElement> mempoolMints;

std::atomic<bool> surgeCondition;

struct Containers {
Expand Down
5 changes: 3 additions & 2 deletions src/test/remint_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(remint_basic_test)

string stringError;
CZerocoinState *zerocoinState = CZerocoinState::GetZerocoinState();

sigma::CSigmaState *sigmaState = sigma::CSigmaState::GetState();
CWalletDB walletdb(pwalletMain->strWalletFile);
std::list<CZerocoinEntry> zcEntries;
decltype(zerocoinState->usedCoinSerials) tempSerials;
Expand Down Expand Up @@ -78,6 +78,7 @@ BOOST_AUTO_TEST_CASE(remint_basic_test)
BOOST_CHECK_MESSAGE(mempool.size() == 1, "Remint transaction accepted into mempool when shouldn't");
// Clear mempool serials and retry
zerocoinState->mempoolCoinSerials.clear();
sigmaState->Reset();
pwalletMain->CommitTransaction(dupSerialTx);
// Mempool should contain two remint transactions both having the same serial
BOOST_CHECK(mempool.size() == 2);
Expand Down Expand Up @@ -188,7 +189,7 @@ BOOST_AUTO_TEST_CASE(remint_basic_test)
walletdb.WriteZerocoinEntry(zcEntry);
}
}

tempSerials = zerocoinState->usedCoinSerials;
zerocoinState->usedCoinSerials.clear();

Expand Down
36 changes: 36 additions & 0 deletions src/test/sigma_partialspend_mempool_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,4 +353,40 @@ BOOST_AUTO_TEST_CASE(same_serial_in_a_transaction) {
sigmaState->Reset();
}

BOOST_AUTO_TEST_CASE(double_mint_into_mempool) {
sigma::CSigmaState *sigmaState = sigma::CSigmaState::GetState();
string denomination;
std::vector<string> denominations = {"0.05", "0.1", "0.5", "1", "10", "25", "100"};
const auto& sigmaParams = sigma::Params::get_default();
// Create 400-200+1 = 201 new empty blocks. // consensus.nMintV3SigmaStartBlock = 400
CreateAndProcessEmptyBlocks(201, scriptPubKey);
// foreach denom from denominations
for(auto denomination : denominations)
{
printf("Testing denomination %s\n", denomination.c_str());
// Make sure that transactions get to mempool
pwalletMain->SetBroadcastTransactions(true);
sigma::CoinDenomination denom;
sigma:: StringToDenomination(denomination, denom);
std::vector<sigma::PrivateCoin> privCoins;
privCoins.push_back(sigma::PrivateCoin(sigmaParams, denom));

vector<CHDMint> vDMints;
auto vecSend = CWallet::CreateSigmaMintRecipients(privCoins, vDMints);

CWalletTx wtx;
string stringError = pwalletMain->MintAndStoreSigma(vecSend, privCoins, vDMints, wtx);
BOOST_CHECK_MESSAGE(stringError == "", "Mint Failed");

BOOST_CHECK_MESSAGE(mempool.size() == 1, "Mint not added into mempool");
//Try mint with the same coin
pwalletMain->MintAndStoreSigma(vecSend, privCoins, vDMints, wtx);
//Second mint should not be added into mempool
BOOST_CHECK_MESSAGE(mempool.size() == 1, "Double mint added into mempool");

mempool.clear();
sigmaState->Reset();
}
}

BOOST_AUTO_TEST_SUITE_END()