Make Equihash solvers cancellable
The miner only cancels the solver when chainActive.Tip() changes. Closes #1055
This commit is contained in:
@@ -21,6 +21,8 @@
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
EhSolverCancelledException solver_cancelled;
|
||||
|
||||
template<unsigned int N, unsigned int K>
|
||||
int Equihash<N,K>::InitialiseState(eh_HashState& base_state)
|
||||
{
|
||||
@@ -191,7 +193,7 @@ eh_trunc* TruncatedStepRow<WIDTH>::GetTruncatedIndices(size_t len, size_t lenInd
|
||||
}
|
||||
|
||||
template<unsigned int N, unsigned int K>
|
||||
std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& base_state)
|
||||
std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& base_state, const std::function<bool()> cancelled)
|
||||
{
|
||||
eh_index init_size { 1 << (CollisionBitLength + 1) };
|
||||
|
||||
@@ -203,6 +205,8 @@ std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& ba
|
||||
X.reserve(init_size);
|
||||
for (eh_index i = 0; i < init_size; i++) {
|
||||
X.emplace_back(N, base_state, i);
|
||||
// Slow down checking to prevent segfaults (??)
|
||||
if (i % 10000 == 0 && cancelled()) throw solver_cancelled;
|
||||
}
|
||||
|
||||
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
||||
@@ -211,6 +215,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& ba
|
||||
// 2a) Sort the list
|
||||
LogPrint("pow", "- Sorting list\n");
|
||||
std::sort(X.begin(), X.end(), CompareSR(CollisionByteLength));
|
||||
if (cancelled()) throw solver_cancelled;
|
||||
|
||||
LogPrint("pow", "- Finding collisions\n");
|
||||
int i = 0;
|
||||
@@ -240,6 +245,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& ba
|
||||
}
|
||||
|
||||
i += j;
|
||||
if (cancelled()) throw solver_cancelled;
|
||||
}
|
||||
|
||||
// 2e) Handle edge case where final table entry has no collision
|
||||
@@ -259,6 +265,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& ba
|
||||
|
||||
hashLen -= CollisionByteLength;
|
||||
lenIndices *= 2;
|
||||
if (cancelled()) throw solver_cancelled;
|
||||
}
|
||||
|
||||
// k+1) Find a collision on last 2n(k+1) bits
|
||||
@@ -286,6 +293,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& ba
|
||||
}
|
||||
|
||||
i += j;
|
||||
if (cancelled()) throw solver_cancelled;
|
||||
}
|
||||
} else
|
||||
LogPrint("pow", "- List is empty\n");
|
||||
@@ -346,7 +354,7 @@ void CollideBranches(std::vector<FullStepRow<WIDTH>>& X, const size_t hlen, cons
|
||||
}
|
||||
|
||||
template<unsigned int N, unsigned int K>
|
||||
std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state)
|
||||
std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state, const std::function<bool()> cancelled)
|
||||
{
|
||||
eh_index init_size { 1 << (CollisionBitLength + 1) };
|
||||
|
||||
@@ -366,6 +374,8 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
Xt.reserve(init_size);
|
||||
for (eh_index i = 0; i < init_size; i++) {
|
||||
Xt.emplace_back(N, base_state, i, CollisionBitLength + 1);
|
||||
// Slow down checking to prevent segfaults (??)
|
||||
if (i % 10000 == 0 && cancelled()) throw solver_cancelled;
|
||||
}
|
||||
|
||||
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
||||
@@ -374,6 +384,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
// 2a) Sort the list
|
||||
LogPrint("pow", "- Sorting list\n");
|
||||
std::sort(Xt.begin(), Xt.end(), CompareSR(CollisionByteLength));
|
||||
if (cancelled()) throw solver_cancelled;
|
||||
|
||||
LogPrint("pow", "- Finding collisions\n");
|
||||
int i = 0;
|
||||
@@ -402,6 +413,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
}
|
||||
|
||||
i += j;
|
||||
if (cancelled()) throw solver_cancelled;
|
||||
}
|
||||
|
||||
// 2e) Handle edge case where final table entry has no collision
|
||||
@@ -421,6 +433,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
|
||||
hashLen -= CollisionByteLength;
|
||||
lenIndices *= 2;
|
||||
if (cancelled()) throw solver_cancelled;
|
||||
}
|
||||
|
||||
// k+1) Find a collision on last 2n(k+1) bits
|
||||
@@ -428,6 +441,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
if (Xt.size() > 1) {
|
||||
LogPrint("pow", "- Sorting list\n");
|
||||
std::sort(Xt.begin(), Xt.end(), CompareSR(hashLen));
|
||||
if (cancelled()) throw solver_cancelled;
|
||||
LogPrint("pow", "- Finding collisions\n");
|
||||
int i = 0;
|
||||
while (i < Xt.size() - 1) {
|
||||
@@ -445,6 +459,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
}
|
||||
|
||||
i += j;
|
||||
if (cancelled()) break;
|
||||
}
|
||||
} else
|
||||
LogPrint("pow", "- List is empty\n");
|
||||
@@ -458,6 +473,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
std::set<std::vector<eh_index>> solns;
|
||||
eh_index recreate_size { UntruncateIndex(1, 0, CollisionBitLength + 1) };
|
||||
int invalidCount = 0;
|
||||
if (cancelled()) goto cancelsolver;
|
||||
for (eh_trunc* partialSoln : partialSolns) {
|
||||
size_t hashLen;
|
||||
size_t lenIndices;
|
||||
@@ -472,6 +488,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
for (eh_index j = 0; j < recreate_size; j++) {
|
||||
eh_index newIndex { UntruncateIndex(partialSoln[i], j, CollisionBitLength + 1) };
|
||||
icv.emplace_back(N, base_state, newIndex);
|
||||
if (cancelled()) goto cancelsolver;
|
||||
}
|
||||
boost::optional<std::vector<FullStepRow<FinalFullWidth>>> ic = icv;
|
||||
|
||||
@@ -487,6 +504,7 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
ic->reserve(ic->size() + X[r]->size());
|
||||
ic->insert(ic->end(), X[r]->begin(), X[r]->end());
|
||||
std::sort(ic->begin(), ic->end(), CompareSR(hashLen));
|
||||
if (cancelled()) goto cancelsolver;
|
||||
size_t lti = rti-(1<<r);
|
||||
CollideBranches(*ic, hashLen, lenIndices,
|
||||
CollisionByteLength,
|
||||
@@ -509,7 +527,9 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
X.push_back(ic);
|
||||
break;
|
||||
}
|
||||
if (cancelled()) goto cancelsolver;
|
||||
}
|
||||
if (cancelled()) goto cancelsolver;
|
||||
}
|
||||
|
||||
// We are at the top of the tree
|
||||
@@ -517,17 +537,24 @@ std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState
|
||||
for (FullStepRow<FinalFullWidth> row : *X[K]) {
|
||||
solns.insert(row.GetIndices(hashLen, lenIndices));
|
||||
}
|
||||
goto deletesolution;
|
||||
if (cancelled()) goto cancelsolver;
|
||||
continue;
|
||||
|
||||
invalidsolution:
|
||||
invalidCount++;
|
||||
|
||||
deletesolution:
|
||||
delete[] partialSoln;
|
||||
}
|
||||
LogPrint("pow", "- Number of invalid solutions found: %d\n", invalidCount);
|
||||
|
||||
for (eh_trunc* partialSoln : partialSolns) {
|
||||
delete[] partialSoln;
|
||||
}
|
||||
return solns;
|
||||
|
||||
cancelsolver:
|
||||
for (eh_trunc* partialSoln : partialSolns) {
|
||||
delete[] partialSoln;
|
||||
}
|
||||
throw solver_cancelled;
|
||||
}
|
||||
|
||||
template<unsigned int N, unsigned int K>
|
||||
@@ -577,18 +604,18 @@ bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<
|
||||
|
||||
// Explicit instantiations for Equihash<96,3>
|
||||
template int Equihash<96,3>::InitialiseState(eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,3>::BasicSolve(const eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,3>::OptimisedSolve(const eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,3>::BasicSolve(const eh_HashState& base_state, const std::function<bool()> cancelled);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,3>::OptimisedSolve(const eh_HashState& base_state, const std::function<bool()> cancelled);
|
||||
template bool Equihash<96,3>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<96,5>
|
||||
template int Equihash<96,5>::InitialiseState(eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,5>::BasicSolve(const eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,5>::OptimisedSolve(const eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,5>::BasicSolve(const eh_HashState& base_state, const std::function<bool()> cancelled);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,5>::OptimisedSolve(const eh_HashState& base_state, const std::function<bool()> cancelled);
|
||||
template bool Equihash<96,5>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<48,5>
|
||||
template int Equihash<48,5>::InitialiseState(eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<48,5>::BasicSolve(const eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<48,5>::OptimisedSolve(const eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<48,5>::BasicSolve(const eh_HashState& base_state, const std::function<bool()> cancelled);
|
||||
template std::set<std::vector<eh_index>> Equihash<48,5>::OptimisedSolve(const eh_HashState& base_state, const std::function<bool()> cancelled);
|
||||
template bool Equihash<48,5>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
|
||||
Reference in New Issue
Block a user