aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2019-11-08 17:30:51 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2020-08-27 15:13:03 +0000
commit6a0b3b1f8a5f96e8906e4a6746ad2b0358bb3d64 (patch)
tree3189cf95fbf1b5f26259f0d7f36eed03339c2601
parentcore: fix mining from a block that's not the current top (diff)
downloadmonero-6a0b3b1f8a5f96e8906e4a6746ad2b0358bb3d64.tar.xz
functional_tests: add randomx tests
-rw-r--r--src/crypto/rx-slow-hash.c50
-rwxr-xr-xtests/functional_tests/functional_tests_rpc.py3
-rwxr-xr-xtests/functional_tests/mining.py114
3 files changed, 163 insertions, 4 deletions
diff --git a/src/crypto/rx-slow-hash.c b/src/crypto/rx-slow-hash.c
index 1d7f09cab..fa35a32e2 100644
--- a/src/crypto/rx-slow-hash.c
+++ b/src/crypto/rx-slow-hash.c
@@ -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_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) {
int i;
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 s_height = (height <= SEEDHASH_EPOCH_BLOCKS+SEEDHASH_EPOCH_LAG) ? 0 :
- (height - SEEDHASH_EPOCH_LAG - 1) & ~(SEEDHASH_EPOCH_BLOCKS-1);
+ const uint64_t seedhash_epoch_lag = get_seedhash_epoch_lag();
+ 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;
}
void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) {
*seedheight = rx_seedheight(height);
- *nextheight = rx_seedheight(height + SEEDHASH_EPOCH_LAG);
+ *nextheight = rx_seedheight(height + get_seedhash_epoch_lag());
}
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,
char *hash, int miners, int is_alt) {
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();
rx_state *rx_sp;
randomx_cache *cache;
diff --git a/tests/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py
index 3be62c0ca..79e04b8a6 100755
--- a/tests/functional_tests/functional_tests_rpc.py
+++ b/tests/functional_tests/functional_tests_rpc.py
@@ -92,6 +92,9 @@ try:
os.environ['PYTHONIOENCODING'] = 'utf-8'
os.environ['DIFFICULTY'] = str(DIFFICULTY)
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)):
#print('Running: ' + str(command_lines[i]))
processes.append(subprocess.Popen(command_lines[i], stdout = outputs[i]))
diff --git a/tests/functional_tests/mining.py b/tests/functional_tests/mining.py
index d067c25e1..c60bf8396 100755
--- a/tests/functional_tests/mining.py
+++ b/tests/functional_tests/mining.py
@@ -30,6 +30,7 @@
from __future__ import print_function
import time
+import os
"""Test daemon mining RPC calls
@@ -49,6 +50,8 @@ class MiningTest():
self.mine(True)
self.mine(False)
self.submitblock()
+ self.reset()
+ self.test_randomx()
def reset(self):
print('Resetting blockchain')
@@ -169,6 +172,117 @@ class MiningTest():
assert res.height == height + i + 1
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:
def __enter__(self):