diff --git a/src/mining/score_bpp9000.h b/src/mining/score_bpp9000.h index 6152ab28..b7f308b4 100644 --- a/src/mining/score_bpp9000.h +++ b/src/mining/score_bpp9000.h @@ -8,6 +8,19 @@ namespace score_engine { +// Largest L (mutations per step) the scorer clamps nonce[1] to +static constexpr unsigned int MAX_LUT_ENTRIES_PER_STEP = 10; + +// A bpp9000 nonce is canonical iff its score-irrelevant knob bytes are canonical: +// nonce[0] = algo (enforced by routing), nonce[1] = L in [1, MAX_LUT_ENTRIES_PER_STEP], nonce[2] = K = 0 +static bool isCanonicalBpp9000Nonce(const unsigned char* nonce) +{ + return (getAlgoType(nonce) == AlgoType::Bpp9000) + && (nonce[1] >= 1) + && (nonce[1] <= MAX_LUT_ENTRIES_PER_STEP) + && (nonce[2] == 0); +} + template struct ScoreBpp9000 { @@ -29,7 +42,6 @@ struct ScoreBpp9000 static constexpr unsigned long long lutSize = 27; // LUT row storage stride, padded to 32; only leading lutSize entries logical (index <= 26). static constexpr unsigned long long lutStride = 32; - static constexpr unsigned int MAX_LUT_ENTRIES_PER_STEP = 10; static_assert(lutSize <= lutStride, "LUT rows must fit the padded stride"); diff --git a/src/public_settings.h b/src/public_settings.h index 7e21e380..92060605 100644 --- a/src/public_settings.h +++ b/src/public_settings.h @@ -71,7 +71,7 @@ static_assert(AUTO_FORCE_NEXT_TICK_THRESHOLD* TARGET_TICK_DURATION >= PEER_REFRE #define VERSION_A 1 #define VERSION_B 301 -#define VERSION_C 0 +#define VERSION_C 2 // Epoch and initial tick for node startup #define EPOCH 224 @@ -126,6 +126,10 @@ static constexpr unsigned long long BPP9000_NUMBER_OF_MUTATIONS = 100; static constexpr unsigned long long BPP9000_NUMBER_OF_WINDOWS = BPP9000_SEQUENCE_LENGTH - BPP9000_WINDOW_WIDTH; static constexpr unsigned int BPP9000_SOLUTION_THRESHOLD_DEFAULT = 3838; +// From this tick, bpp9000 solutions whose nonce is non-canonical (nonce[1] outside [1, MAX_LUT_ENTRIES_PER_STEP] +// or nonce[2] != 0) are rejected as invalid +static constexpr unsigned int BPP9000_NONCE_CANONICAL_ACTIVATION_TICK = 70900000; + // Multipler of score static constexpr unsigned int NEURAXON_SOLUTION_MULTIPLER = 1; diff --git a/src/qubic.cpp b/src/qubic.cpp index 7b5368ba..03dd1a28 100644 --- a/src/qubic.cpp +++ b/src/qubic.cpp @@ -636,7 +636,8 @@ static void processBroadcastMessage(const unsigned long long processorNumber, Re } if (k == system.numberOfSolutions) { - unsigned int solutionScore = (*score)(processorNumber, request->destinationPublicKey, solution_miningSeed, solution_nonce); + unsigned int solutionScore = (system.tick >= BPP9000_NONCE_CANONICAL_ACTIVATION_TICK && !score_engine::isCanonicalBpp9000Nonce(solution_nonce.m256i_u8)) ? + score_engine::INVALID_SCORE_VALUE : (*score)(processorNumber, request->destinationPublicKey, solution_miningSeed, solution_nonce); score_engine::AlgoType selectedAlgo = score_engine::getAlgoType(solution_nonce.m256i_u8); const int threshold = getSolutionThreshold(selectedAlgo); if (system.numberOfSolutions < MAX_NUMBER_OF_SOLUTIONS @@ -1015,7 +1016,10 @@ static void processBroadcastTransaction(Peer* peer, RequestResponseHeader* heade { const m256i& solutionMiningSeed = *(m256i*)request->inputPtr(); const m256i& solutionNonce = *(m256i*)(request->inputPtr() + 32); - (*score)(processorNumber, request->sourcePublicKey, solutionMiningSeed, solutionNonce); + if (system.tick < BPP9000_NONCE_CANONICAL_ACTIVATION_TICK || score_engine::isCanonicalBpp9000Nonce(solutionNonce.m256i_u8)) + { + (*score)(processorNumber, request->sourcePublicKey, solutionMiningSeed, solutionNonce); + } } } @@ -2500,7 +2504,8 @@ static void processTickTransactionSolution(const MiningSolutionTransaction* tran minerSolutionFlags[flagIndices[0] >> 6] |= (1ULL << (flagIndices[0] & 63)); minerSolutionFlags[flagIndices[1] >> 6] |= (1ULL << (flagIndices[1] & 63)); - unsigned int solutionScore = (*::score)(processorNumber, transaction->sourcePublicKey, transaction->miningSeed, transaction->nonce); + unsigned int solutionScore = (system.tick >= BPP9000_NONCE_CANONICAL_ACTIVATION_TICK && !score_engine::isCanonicalBpp9000Nonce(transaction->nonce.m256i_u8)) ? + score_engine::INVALID_SCORE_VALUE : (*::score)(processorNumber, transaction->sourcePublicKey, transaction->miningSeed, transaction->nonce); score_engine::AlgoType selectedAlgo = score_engine::getAlgoType(transaction->nonce.m256i_u8); if (score->isValidScore(solutionScore, selectedAlgo)) {