Fix bit-rotted code in miner tests.
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
parent
33d9ff3d24
commit
dd246587a3
|
@ -127,7 +127,7 @@ void EhIndexToArray(const eh_index i, unsigned char* array)
|
|||
memcpy(array, &bei, sizeof(eh_index));
|
||||
}
|
||||
|
||||
std::vector<unsigned char> GetMinimalFromIndices(std::vector<eh_index> indices,
|
||||
std::vector<unsigned char> GetMinimalFromIndices(const std::vector<eh_index>& indices,
|
||||
size_t cBitLen)
|
||||
{
|
||||
assert(((cBitLen+1)+7)/8 <= sizeof(eh_index));
|
||||
|
|
|
@ -16,7 +16,7 @@ inline constexpr size_t equihash_solution_size(unsigned int N, unsigned int K) {
|
|||
typedef uint32_t eh_index;
|
||||
typedef uint8_t eh_trunc;
|
||||
|
||||
std::vector<unsigned char> GetMinimalFromIndices(std::vector<eh_index> indices,
|
||||
std::vector<unsigned char> GetMinimalFromIndices(const std::vector<eh_index>& indices,
|
||||
size_t cBitLen);
|
||||
void CompressArray(const unsigned char* in, size_t in_len,
|
||||
unsigned char* out, size_t out_len,
|
||||
|
|
|
@ -1053,37 +1053,12 @@ void static BitcoinMiner(const CChainParams& chainparams)
|
|||
|
||||
// TODO: factor this out into a function with the same API for each solver.
|
||||
if (solver == "tromp") {
|
||||
// Create solver and initialize it.
|
||||
equi eq(1);
|
||||
eq.setstate(curr_state.inner);
|
||||
|
||||
// Initialization done, start algo driver.
|
||||
eq.digit0(0);
|
||||
eq.xfull = eq.bfull = eq.hfull = 0;
|
||||
eq.showbsizes(0);
|
||||
for (u32 r = 1; r < WK; r++) {
|
||||
(r&1) ? eq.digitodd(r, 0) : eq.digiteven(r, 0);
|
||||
eq.xfull = eq.bfull = eq.hfull = 0;
|
||||
eq.showbsizes(r);
|
||||
}
|
||||
eq.digitK(0);
|
||||
ehSolverRuns.increment();
|
||||
|
||||
// Convert solution indices to byte array (decompress) and pass it to validBlock method.
|
||||
for (size_t s = 0; s < std::min(MAXSOLS, eq.nsols); s++) {
|
||||
std::function<void()> incrementRuns = [&]() { ehSolverRuns.increment(); };
|
||||
std::function<bool(size_t s, const std::vector<uint32_t>&)> checkSolution = [&](size_t s, const std::vector<uint32_t>& index_vector) {
|
||||
LogPrint("pow", "Checking solution %d\n", s+1);
|
||||
std::vector<eh_index> index_vector(PROOFSIZE);
|
||||
for (size_t i = 0; i < PROOFSIZE; i++) {
|
||||
index_vector[i] = eq.sols[s][i];
|
||||
}
|
||||
std::vector<unsigned char> sol_char = GetMinimalFromIndices(index_vector, DIGITBITS);
|
||||
|
||||
if (validBlock(sol_char)) {
|
||||
// If we find a POW solution, do not try other solutions
|
||||
// because they become invalid as we created a new block in blockchain.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return validBlock(GetMinimalFromIndices(index_vector, DIGITBITS));
|
||||
};
|
||||
equihash_solve(curr_state.inner, incrementRuns, checkSolution);
|
||||
} else {
|
||||
try {
|
||||
// If we find a valid block, we rebuild
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Equihash solver
|
||||
// Copyright (c) 2016-2016 John Tromp, The Zcash developers
|
||||
// Copyright (c) 2016-2023 John Tromp, The Zcash developers
|
||||
|
||||
#ifndef ZCASH_POW_TROMP_EQUI_H
|
||||
#define ZCASH_POW_TROMP_EQUI_H
|
||||
|
@ -43,64 +43,19 @@ typedef u32 proof[PROOFSIZE];
|
|||
|
||||
|
||||
enum verify_code { POW_OK, POW_DUPLICATE, POW_OUT_OF_ORDER, POW_NONZERO_XOR };
|
||||
const char *errstr[] = { "OK", "duplicate index", "indices out of order", "nonzero xor" };
|
||||
extern const char *errstr[4];
|
||||
|
||||
void genhash(const rust::Box<blake2b::State>& ctx, u32 idx, uchar *hash) {
|
||||
auto state = ctx->box_clone();
|
||||
u32 leb = htole32(idx / HASHESPERBLAKE);
|
||||
state->update({(const uchar *)&leb, sizeof(u32)});
|
||||
uchar blakehash[HASHOUT];
|
||||
state->finalize({blakehash, HASHOUT});
|
||||
memcpy(hash, blakehash + (idx % HASHESPERBLAKE) * WN/8, WN/8);
|
||||
}
|
||||
|
||||
int verifyrec(const rust::Box<blake2b::State>& ctx, u32 *indices, uchar *hash, int r) {
|
||||
if (r == 0) {
|
||||
genhash(ctx, *indices, hash);
|
||||
return POW_OK;
|
||||
}
|
||||
u32 *indices1 = indices + (1 << (r-1));
|
||||
if (*indices >= *indices1)
|
||||
return POW_OUT_OF_ORDER;
|
||||
uchar hash0[WN/8], hash1[WN/8];
|
||||
int vrf0 = verifyrec(ctx, indices, hash0, r-1);
|
||||
if (vrf0 != POW_OK)
|
||||
return vrf0;
|
||||
int vrf1 = verifyrec(ctx, indices1, hash1, r-1);
|
||||
if (vrf1 != POW_OK)
|
||||
return vrf1;
|
||||
for (int i=0; i < WN/8; i++)
|
||||
hash[i] = hash0[i] ^ hash1[i];
|
||||
int i, b = r * DIGITBITS;
|
||||
for (i = 0; i < b/8; i++)
|
||||
if (hash[i])
|
||||
return POW_NONZERO_XOR;
|
||||
if ((b%8) && hash[i] >> (8-(b%8)))
|
||||
return POW_NONZERO_XOR;
|
||||
return POW_OK;
|
||||
}
|
||||
|
||||
int compu32(const void *pa, const void *pb) {
|
||||
u32 a = *(u32 *)pa, b = *(u32 *)pb;
|
||||
return a<b ? -1 : a==b ? 0 : +1;
|
||||
}
|
||||
|
||||
bool duped(proof prf) {
|
||||
proof sortprf;
|
||||
memcpy(sortprf, prf, sizeof(proof));
|
||||
qsort(sortprf, PROOFSIZE, sizeof(u32), &compu32);
|
||||
for (u32 i=1; i<PROOFSIZE; i++)
|
||||
if (sortprf[i] <= sortprf[i-1])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
void genhash(const rust::Box<blake2b::State>& ctx, u32 idx, uchar *hash);
|
||||
int verifyrec(const rust::Box<blake2b::State>& ctx, u32 *indices, uchar *hash, int r);
|
||||
int compu32(const void *pa, const void *pb);
|
||||
bool duped(proof prf);
|
||||
|
||||
// verify Wagner conditions
|
||||
int verify(u32 indices[PROOFSIZE], const rust::Box<blake2b::State> ctx) {
|
||||
if (duped(indices))
|
||||
return POW_DUPLICATE;
|
||||
uchar hash[WN/8];
|
||||
return verifyrec(ctx, indices, hash, WK);
|
||||
}
|
||||
int verify(u32 indices[PROOFSIZE], const rust::Box<blake2b::State> ctx);
|
||||
|
||||
bool equihash_solve(
|
||||
const rust::Box<blake2b::State>& curr_state,
|
||||
std::function<void()>& incrementRuns,
|
||||
std::function<bool(size_t s, const std::vector<uint32_t>&)>& checkSolution);
|
||||
|
||||
#endif // ZCASH_POW_TROMP_EQUI_H
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Equihash solver
|
||||
// Copyright (c) 2016 John Tromp, The Zcash developers
|
||||
// Copyright (c) 2016-2023 John Tromp, The Zcash developers
|
||||
|
||||
// Fix N, K, such that n = N/(k+1) is integer
|
||||
// Fix M = 2^{n+1} hashes each of length N bits,
|
||||
|
@ -75,6 +75,8 @@ static const u32 NBLOCKS = (NHASHES+HASHESPERBLAKE-1)/HASHESPERBLAKE;
|
|||
// nothing larger found in 100000 runs
|
||||
static const u32 MAXSOLS = 8;
|
||||
|
||||
const char *errstr[] = { "OK", "duplicate index", "indices out of order", "nonzero xor" };
|
||||
|
||||
// tree node identifying its children as two different slots in
|
||||
// a bucket on previous layer with the same rest bits (x-tra hash)
|
||||
struct tree {
|
||||
|
@ -646,4 +648,98 @@ void *worker(void *vp) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void genhash(const rust::Box<blake2b::State>& ctx, u32 idx, uchar *hash) {
|
||||
auto state = ctx->box_clone();
|
||||
u32 leb = htole32(idx / HASHESPERBLAKE);
|
||||
state->update({(const uchar *)&leb, sizeof(u32)});
|
||||
uchar blakehash[HASHOUT];
|
||||
state->finalize({blakehash, HASHOUT});
|
||||
memcpy(hash, blakehash + (idx % HASHESPERBLAKE) * WN/8, WN/8);
|
||||
}
|
||||
|
||||
int verifyrec(const rust::Box<blake2b::State>& ctx, u32 *indices, uchar *hash, int r) {
|
||||
if (r == 0) {
|
||||
genhash(ctx, *indices, hash);
|
||||
return POW_OK;
|
||||
}
|
||||
u32 *indices1 = indices + (1 << (r-1));
|
||||
if (*indices >= *indices1)
|
||||
return POW_OUT_OF_ORDER;
|
||||
uchar hash0[WN/8], hash1[WN/8];
|
||||
int vrf0 = verifyrec(ctx, indices, hash0, r-1);
|
||||
if (vrf0 != POW_OK)
|
||||
return vrf0;
|
||||
int vrf1 = verifyrec(ctx, indices1, hash1, r-1);
|
||||
if (vrf1 != POW_OK)
|
||||
return vrf1;
|
||||
for (int i=0; i < WN/8; i++)
|
||||
hash[i] = hash0[i] ^ hash1[i];
|
||||
int i, b = r * DIGITBITS;
|
||||
for (i = 0; i < b/8; i++)
|
||||
if (hash[i])
|
||||
return POW_NONZERO_XOR;
|
||||
if ((b%8) && hash[i] >> (8-(b%8)))
|
||||
return POW_NONZERO_XOR;
|
||||
return POW_OK;
|
||||
}
|
||||
|
||||
int compu32(const void *pa, const void *pb) {
|
||||
u32 a = *(u32 *)pa, b = *(u32 *)pb;
|
||||
return a<b ? -1 : a==b ? 0 : +1;
|
||||
}
|
||||
|
||||
bool duped(proof prf) {
|
||||
proof sortprf;
|
||||
memcpy(sortprf, prf, sizeof(proof));
|
||||
qsort(sortprf, PROOFSIZE, sizeof(u32), &compu32);
|
||||
for (u32 i=1; i<PROOFSIZE; i++)
|
||||
if (sortprf[i] <= sortprf[i-1])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// verify Wagner conditions
|
||||
int verify(u32 indices[PROOFSIZE], const rust::Box<blake2b::State> ctx) {
|
||||
if (duped(indices))
|
||||
return POW_DUPLICATE;
|
||||
uchar hash[WN/8];
|
||||
return verifyrec(ctx, indices, hash, WK);
|
||||
}
|
||||
|
||||
bool equihash_solve(
|
||||
const rust::Box<blake2b::State>& curr_state,
|
||||
std::function<void()>& incrementRuns,
|
||||
std::function<bool(size_t s, const std::vector<uint32_t>&)>& checkSolution)
|
||||
{
|
||||
// Create solver and initialize it.
|
||||
equi eq(1);
|
||||
eq.setstate(curr_state);
|
||||
|
||||
// Initialization done, start algo driver.
|
||||
eq.digit0(0);
|
||||
eq.xfull = eq.bfull = eq.hfull = 0;
|
||||
eq.showbsizes(0);
|
||||
for (u32 r = 1; r < WK; r++) {
|
||||
(r&1) ? eq.digitodd(r, 0) : eq.digiteven(r, 0);
|
||||
eq.xfull = eq.bfull = eq.hfull = 0;
|
||||
eq.showbsizes(r);
|
||||
}
|
||||
eq.digitK(0);
|
||||
incrementRuns();
|
||||
|
||||
// Decompress solution indices and pass to checkSolution.
|
||||
for (size_t s = 0; s < std::min(MAXSOLS, eq.nsols); s++) {
|
||||
std::vector<uint32_t> index_vector(PROOFSIZE);
|
||||
for (size_t i = 0; i < PROOFSIZE; i++) {
|
||||
index_vector[i] = eq.sols[s][i];
|
||||
}
|
||||
if (checkSolution(s, index_vector)) {
|
||||
// If we find a POW solution, do not try other solutions
|
||||
// because they become invalid as we created a new block in blockchain.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // ZCASH_POW_TROMP_EQUI_MINER_H
|
||||
|
|
|
@ -12,10 +12,11 @@
|
|||
#include "uint256.h"
|
||||
#include "util/system.h"
|
||||
#include "crypto/equihash.h"
|
||||
//#include "pow/tromp/equi_miner.h"
|
||||
|
||||
#include "pow/tromp/equi.h"
|
||||
#include "test/test_bitcoin.h"
|
||||
|
||||
#include <rust/equihash.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
|
||||
|
@ -170,11 +171,18 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
// Simple block creation, nothing special yet:
|
||||
BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
|
||||
|
||||
// We can't make transactions until we have inputs
|
||||
// Therefore, load 100 blocks :)
|
||||
// We can't make transactions until we have inputs. Therefore, load 110 blocks.
|
||||
const int nblocks = 110;
|
||||
assert(nblocks < chainparams.GetConsensus().SubsidySlowStartShift());
|
||||
|
||||
auto MinerSubsidy = [](int height) { return height*50000; };
|
||||
auto FoundersReward = [](int height) { return height*12500; };
|
||||
|
||||
std::vector<CTransaction*> txFirst;
|
||||
for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i)
|
||||
|
||||
for (unsigned int i = 0; i < nblocks; ++i)
|
||||
{
|
||||
int height = i+1;
|
||||
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
||||
pblock->nVersion = 4;
|
||||
// Fake the blocks taking at least nPowTargetSpacing to be mined.
|
||||
|
@ -182,26 +190,28 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
// of the next block must be six spacings ahead of that to be at least
|
||||
// one spacing ahead of the tip. Within 11 blocks of genesis, the median
|
||||
// will be closer to the tip, and blocks will appear slower.
|
||||
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+6*Params().GetConsensus().PoWTargetSpacing(i);
|
||||
pblock->nTime = chainActive.Tip()->GetMedianTimePast() + 6*chainparams.GetConsensus().PoWTargetSpacing(i);
|
||||
pblock->nBits = GetNextWorkRequired(chainActive.Tip(), pblock, chainparams.GetConsensus());
|
||||
CMutableTransaction txCoinbase(pblock->vtx[0]);
|
||||
txCoinbase.nVersion = 1;
|
||||
txCoinbase.vin[0].scriptSig = CScript() << (chainActive.Height()+1) << OP_0;
|
||||
txCoinbase.vout[0].scriptPubKey = CScript();
|
||||
txCoinbase.vout[0].nValue = 50000 * (i + 1);
|
||||
txCoinbase.vout[1].nValue = 12500 * (i + 1);
|
||||
txCoinbase.vout[0].nValue = MinerSubsidy(height);
|
||||
txCoinbase.vout[1].nValue = FoundersReward(height);
|
||||
pblock->vtx[0] = CTransaction(txCoinbase);
|
||||
if (txFirst.size() < 2)
|
||||
txFirst.push_back(new CTransaction(pblock->vtx[0]));
|
||||
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
|
||||
|
||||
if (i < sizeof(blockinfo)/sizeof(*blockinfo)) {
|
||||
pblock->nNonce = uint256S(blockinfo[i].nonce_hex);
|
||||
pblock->nSolution = ParseHex(blockinfo[i].solution_hex);
|
||||
|
||||
/*
|
||||
{
|
||||
} else {
|
||||
// If you need to mine more blocks than are currently in blockinfo, this code will do so.
|
||||
// We leave it compiling so that it doesn't bitrot.
|
||||
arith_uint256 try_nonce(0);
|
||||
unsigned int n = Params().GetConsensus().nEquihashN;
|
||||
unsigned int k = Params().GetConsensus().nEquihashK;
|
||||
unsigned int n = chainparams.GetConsensus().nEquihashN;
|
||||
unsigned int k = chainparams.GetConsensus().nEquihashK;
|
||||
|
||||
// Hash state
|
||||
eh_HashState eh_state = EhInitialiseState(n, k);
|
||||
|
@ -221,60 +231,29 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
eh_HashState curr_state(eh_state);
|
||||
curr_state.Update(pblock->nNonce.begin(), pblock->nNonce.size());
|
||||
|
||||
// Create solver and initialize it.
|
||||
equi eq(1);
|
||||
eq.setstate(curr_state.state);
|
||||
|
||||
// Initialization done, start algo driver.
|
||||
eq.digit0(0);
|
||||
eq.xfull = eq.bfull = eq.hfull = 0;
|
||||
eq.showbsizes(0);
|
||||
for (u32 r = 1; r < WK; r++) {
|
||||
(r&1) ? eq.digitodd(r, 0) : eq.digiteven(r, 0);
|
||||
eq.xfull = eq.bfull = eq.hfull = 0;
|
||||
eq.showbsizes(r);
|
||||
}
|
||||
eq.digitK(0);
|
||||
|
||||
// Convert solution indices to byte array (decompress) and pass it to validBlock method.
|
||||
std::set<std::vector<unsigned char>> solns;
|
||||
for (size_t s = 0; s < std::min(MAXSOLS, eq.nsols); s++) {
|
||||
LogPrint("pow", "Checking solution %d\n", s+1);
|
||||
std::vector<eh_index> index_vector(PROOFSIZE);
|
||||
for (size_t i = 0; i < PROOFSIZE; i++) {
|
||||
index_vector[i] = eq.sols[s][i];
|
||||
}
|
||||
std::vector<unsigned char> sol_char = GetMinimalFromIndices(index_vector, DIGITBITS);
|
||||
solns.insert(sol_char);
|
||||
}
|
||||
|
||||
for (auto soln : solns) {
|
||||
std::function<void()> incrementRuns = [&]() {};
|
||||
std::function<bool(size_t, const std::vector<uint32_t>&)> checkSolution = [&](size_t s, const std::vector<uint32_t>& index_vector) {
|
||||
auto soln = GetMinimalFromIndices(index_vector, DIGITBITS);
|
||||
pblock->nSolution = soln;
|
||||
if (!equihash::is_valid(
|
||||
n, k,
|
||||
{(const unsigned char*)ss.data(), ss.size()},
|
||||
{pblock->nNonce.begin(), pblock->nNonce.size()},
|
||||
{soln.data(), soln.size()})) continue;
|
||||
pblock->nSolution = soln;
|
||||
|
||||
{soln.data(), soln.size()})) {
|
||||
return false;
|
||||
}
|
||||
CValidationState state;
|
||||
|
||||
if (ProcessNewBlock(state, NULL, pblock, true, NULL) && state.IsValid()) {
|
||||
goto foundit;
|
||||
}
|
||||
|
||||
//std::cout << state.GetRejectReason() << std::endl;
|
||||
}
|
||||
return ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL) && state.IsValid();
|
||||
};
|
||||
if (equihash_solve(curr_state.inner, incrementRuns, checkSolution))
|
||||
break;
|
||||
|
||||
try_nonce += 1;
|
||||
}
|
||||
foundit:
|
||||
|
||||
std::cout << " {\"" << pblock->nNonce.GetHex() << "\", \"";
|
||||
std::cout << HexStr(pblock->nSolution.begin(), pblock->nSolution.end());
|
||||
std::cout << "\"}," << std::endl;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
// These tests assume null hashBlockCommitments (before Sapling)
|
||||
pblock->hashBlockCommitments = uint256();
|
||||
|
@ -285,6 +264,9 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
pblock->hashPrevBlock = pblock->GetHash();
|
||||
}
|
||||
|
||||
// Stop here if we needed to mine more blocks.
|
||||
assert(nblocks == sizeof(blockinfo)/sizeof(*blockinfo));
|
||||
|
||||
// Set the clock to be just ahead of the last "mined" block, to ensure we satisfy the
|
||||
// future timestamp soft fork rule.
|
||||
auto curTime = GetTime();
|
||||
|
|
Loading…
Reference in New Issue