functional_tests: add randomx tests
This commit is contained in:
parent
9d42649d58
commit
6a0b3b1f8a
|
@ -116,6 +116,46 @@ static inline int enabled_flags(void) {
|
||||||
#define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */
|
#define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */
|
||||||
#define SEEDHASH_EPOCH_LAG 64
|
#define SEEDHASH_EPOCH_LAG 64
|
||||||
|
|
||||||
|
static inline int is_power_of_2(uint64_t n) { return n && (n & (n-1)) == 0; }
|
||||||
|
|
||||||
|
static int get_seedhash_epoch_lag(void)
|
||||||
|
{
|
||||||
|
static unsigned int lag = (unsigned int)-1;
|
||||||
|
if (lag != (unsigned int)-1)
|
||||||
|
return lag;
|
||||||
|
const char *e = getenv("SEEDHASH_EPOCH_LAG");
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
lag = atoi(e);
|
||||||
|
if (lag > SEEDHASH_EPOCH_LAG || !is_power_of_2(lag))
|
||||||
|
lag = SEEDHASH_EPOCH_LAG;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lag = SEEDHASH_EPOCH_LAG;
|
||||||
|
}
|
||||||
|
return lag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int get_seedhash_epoch_blocks(void)
|
||||||
|
{
|
||||||
|
static unsigned int blocks = (unsigned int)-1;
|
||||||
|
if (blocks != (unsigned int)-1)
|
||||||
|
return blocks;
|
||||||
|
const char *e = getenv("SEEDHASH_EPOCH_BLOCKS");
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
blocks = atoi(e);
|
||||||
|
if (blocks < 2 || blocks > SEEDHASH_EPOCH_BLOCKS || !is_power_of_2(blocks))
|
||||||
|
blocks = SEEDHASH_EPOCH_BLOCKS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blocks = SEEDHASH_EPOCH_BLOCKS;
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
void rx_reorg(const uint64_t split_height) {
|
void rx_reorg(const uint64_t split_height) {
|
||||||
int i;
|
int i;
|
||||||
CTHR_MUTEX_LOCK(rx_mutex);
|
CTHR_MUTEX_LOCK(rx_mutex);
|
||||||
|
@ -130,14 +170,16 @@ void rx_reorg(const uint64_t split_height) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t rx_seedheight(const uint64_t height) {
|
uint64_t rx_seedheight(const uint64_t height) {
|
||||||
uint64_t s_height = (height <= SEEDHASH_EPOCH_BLOCKS+SEEDHASH_EPOCH_LAG) ? 0 :
|
const uint64_t seedhash_epoch_lag = get_seedhash_epoch_lag();
|
||||||
(height - SEEDHASH_EPOCH_LAG - 1) & ~(SEEDHASH_EPOCH_BLOCKS-1);
|
const uint64_t seedhash_epoch_blocks = get_seedhash_epoch_blocks();
|
||||||
|
uint64_t s_height = (height <= seedhash_epoch_blocks+seedhash_epoch_lag) ? 0 :
|
||||||
|
(height - seedhash_epoch_lag - 1) & ~(seedhash_epoch_blocks-1);
|
||||||
return s_height;
|
return s_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) {
|
void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) {
|
||||||
*seedheight = rx_seedheight(height);
|
*seedheight = rx_seedheight(height);
|
||||||
*nextheight = rx_seedheight(height + SEEDHASH_EPOCH_LAG);
|
*nextheight = rx_seedheight(height + get_seedhash_epoch_lag());
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct seedinfo {
|
typedef struct seedinfo {
|
||||||
|
@ -194,7 +236,7 @@ static void rx_initdata(randomx_cache *rs_cache, const int miners, const uint64_
|
||||||
void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length,
|
void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length,
|
||||||
char *hash, int miners, int is_alt) {
|
char *hash, int miners, int is_alt) {
|
||||||
uint64_t s_height = rx_seedheight(mainheight);
|
uint64_t s_height = rx_seedheight(mainheight);
|
||||||
int toggle = (s_height & SEEDHASH_EPOCH_BLOCKS) != 0;
|
int toggle = (s_height & get_seedhash_epoch_blocks()) != 0;
|
||||||
randomx_flags flags = enabled_flags() & ~disabled_flags();
|
randomx_flags flags = enabled_flags() & ~disabled_flags();
|
||||||
rx_state *rx_sp;
|
rx_state *rx_sp;
|
||||||
randomx_cache *cache;
|
randomx_cache *cache;
|
||||||
|
|
|
@ -92,6 +92,9 @@ try:
|
||||||
os.environ['PYTHONIOENCODING'] = 'utf-8'
|
os.environ['PYTHONIOENCODING'] = 'utf-8'
|
||||||
os.environ['DIFFICULTY'] = str(DIFFICULTY)
|
os.environ['DIFFICULTY'] = str(DIFFICULTY)
|
||||||
os.environ['MAKE_TEST_SIGNATURE'] = builddir + '/tests/functional_tests/make_test_signature'
|
os.environ['MAKE_TEST_SIGNATURE'] = builddir + '/tests/functional_tests/make_test_signature'
|
||||||
|
os.environ['SEEDHASH_EPOCH_BLOCKS'] = "8"
|
||||||
|
os.environ['SEEDHASH_EPOCH_LAG'] = "4"
|
||||||
|
|
||||||
for i in range(len(command_lines)):
|
for i in range(len(command_lines)):
|
||||||
#print('Running: ' + str(command_lines[i]))
|
#print('Running: ' + str(command_lines[i]))
|
||||||
processes.append(subprocess.Popen(command_lines[i], stdout = outputs[i]))
|
processes.append(subprocess.Popen(command_lines[i], stdout = outputs[i]))
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import time
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
"""Test daemon mining RPC calls
|
"""Test daemon mining RPC calls
|
||||||
|
|
||||||
|
@ -49,6 +50,8 @@ class MiningTest():
|
||||||
self.mine(True)
|
self.mine(True)
|
||||||
self.mine(False)
|
self.mine(False)
|
||||||
self.submitblock()
|
self.submitblock()
|
||||||
|
self.reset()
|
||||||
|
self.test_randomx()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
|
@ -169,6 +172,117 @@ class MiningTest():
|
||||||
assert res.height == height + i + 1
|
assert res.height == height + i + 1
|
||||||
assert res.hash == block_hash
|
assert res.hash == block_hash
|
||||||
|
|
||||||
|
def test_randomx(self):
|
||||||
|
print("Test RandomX")
|
||||||
|
|
||||||
|
daemon = Daemon()
|
||||||
|
wallet = Wallet()
|
||||||
|
|
||||||
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
|
daemon.flush_txpool()
|
||||||
|
|
||||||
|
epoch = int(os.environ['SEEDHASH_EPOCH_BLOCKS'])
|
||||||
|
lag = int(os.environ['SEEDHASH_EPOCH_LAG'])
|
||||||
|
address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
|
||||||
|
# check we can generate blocks, and that the seed hash changes when expected
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
first_seed_hash = res.seed_hash
|
||||||
|
daemon.generateblocks(address, 1 + lag)
|
||||||
|
res = daemon.mining_status()
|
||||||
|
assert res.active == False
|
||||||
|
assert res.pow_algorithm == 'RandomX'
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
seed_hash = res.seed_hash
|
||||||
|
t0 = time.time()
|
||||||
|
daemon.generateblocks(address, epoch - 3)
|
||||||
|
t0 = time.time() - t0
|
||||||
|
res = daemon.get_info()
|
||||||
|
assert res.height == lag + epoch - 1
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
assert seed_hash == res.seed_hash
|
||||||
|
t0 = time.time()
|
||||||
|
daemon.generateblocks(address, 1)
|
||||||
|
t0 = time.time() - t0
|
||||||
|
res = daemon.get_info()
|
||||||
|
assert res.height == lag + epoch
|
||||||
|
daemon.generateblocks(address, 1)
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
assert seed_hash != res.seed_hash
|
||||||
|
new_seed_hash = res.seed_hash
|
||||||
|
t0 = time.time()
|
||||||
|
daemon.generateblocks(address, epoch - 1)
|
||||||
|
t0 = time.time() - t0
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
assert new_seed_hash == res.seed_hash
|
||||||
|
daemon.generateblocks(address, 1)
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
assert new_seed_hash != res.seed_hash
|
||||||
|
new_seed_hash = res.seed_hash
|
||||||
|
t0 = time.time()
|
||||||
|
daemon.generateblocks(address, epoch - 1)
|
||||||
|
t0 = time.time() - t0
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
assert new_seed_hash == res.seed_hash
|
||||||
|
daemon.generateblocks(address, 1)
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
assert new_seed_hash != res.seed_hash
|
||||||
|
#print('First mining: ' + str(t0))
|
||||||
|
|
||||||
|
# pop all these blocks, and feed them again to monerod
|
||||||
|
print('Recreating the chain')
|
||||||
|
res = daemon.get_info()
|
||||||
|
height = res.height
|
||||||
|
assert height == lag + epoch * 3 + 1
|
||||||
|
block_hashes = [x.hash for x in daemon.getblockheadersrange(0, height - 1).headers]
|
||||||
|
assert len(block_hashes) == height
|
||||||
|
blocks = []
|
||||||
|
for i in range(len(block_hashes)):
|
||||||
|
res = daemon.getblock(height = i)
|
||||||
|
assert res.block_header.hash == block_hashes[i]
|
||||||
|
blocks.append(res.blob)
|
||||||
|
daemon.pop_blocks(height)
|
||||||
|
res = daemon.get_info()
|
||||||
|
assert res.height == 1
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
assert first_seed_hash == res.seed_hash
|
||||||
|
t0 = time.time()
|
||||||
|
for h in range(len(block_hashes)):
|
||||||
|
res = daemon.submitblock(blocks[h])
|
||||||
|
t0 = time.time() - t0
|
||||||
|
res = daemon.get_info()
|
||||||
|
assert height == res.height
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
assert new_seed_hash != res.seed_hash
|
||||||
|
res = daemon.pop_blocks(1)
|
||||||
|
res = daemon.getblocktemplate(address)
|
||||||
|
assert new_seed_hash == res.seed_hash
|
||||||
|
#print('Submit: ' + str(t0))
|
||||||
|
|
||||||
|
# start mining from the genesis block again
|
||||||
|
print('Mining from genesis block again')
|
||||||
|
res = daemon.get_height()
|
||||||
|
top_hash = res.hash
|
||||||
|
res = daemon.getblockheaderbyheight(0)
|
||||||
|
genesis_block_hash = res.block_header.hash
|
||||||
|
t0 = time.time()
|
||||||
|
daemon.generateblocks(address, height - 2, prev_block = genesis_block_hash)
|
||||||
|
t0 = time.time() - t0
|
||||||
|
res = daemon.get_info()
|
||||||
|
assert res.height == height - 1
|
||||||
|
assert res.top_block_hash == top_hash
|
||||||
|
#print('Second mining: ' + str(t0))
|
||||||
|
|
||||||
|
# that one will cause a huge reorg
|
||||||
|
print('Adding one to reorg')
|
||||||
|
res = daemon.generateblocks(address, 1)
|
||||||
|
assert len(res.blocks) == 1
|
||||||
|
new_top_hash = res.blocks[0]
|
||||||
|
res = daemon.get_info()
|
||||||
|
assert res.height == height
|
||||||
|
assert res.top_block_hash == new_top_hash
|
||||||
|
|
||||||
|
|
||||||
class Guard:
|
class Guard:
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
|
|
Loading…
Reference in New Issue