EthashRule extends BlockHeaderRule { @Override public ValidationResult validate(BlockHeader header) { if (header.isGenesis()) return Success; if (ethashHelper == null) return powRule.validate(header); if (chain.isSide()) ethashHelper.preCache(header.getNumber()); if (mode == mixed && !syncDone && rnd.nextInt(100) % MIX_DENOMINATOR > 0) return powRule.validate(header); try { Pair<byte[], byte[]> res = ethashHelper.ethashWorkFor(header, header.getNonce(), true); if (res == null) { return powRule.validate(header); } if (!FastByteComparisons.equal(res.getLeft(), header.getMixHash())) { return fault(String.format("#%d: mixHash doesn't match", header.getNumber())); } if (FastByteComparisons.compareTo(res.getRight(), 0, 32, header.getPowBoundary(), 0, 32) > 0) { return fault(String.format("#%d: proofValue > header.getPowBoundary()", header.getNumber())); } return Success; } catch (Exception e) { logger.error("Failed to verify ethash work for block {}", header.getShortDescr(), e); return fault("Failed to verify ethash work for block " + header.getShortDescr()); } } EthashRule(Mode mode, ChainType chain, CompositeEthereumListener listener); static EthashRule createRegular(SystemProperties systemProperties, CompositeEthereumListener listener); static EthashRule createReverse(SystemProperties systemProperties); @Override ValidationResult validate(BlockHeader header);  }
@Test public void testFake() { CompositeEthereumListener listener = new CompositeEthereumListenerMock(); EthashRule rule = new EthashRule(EthashRule.Mode.fake, EthashRule.ChainType.main, listener); assertEquals(Success, rule.validate(validHeader)); assertEquals(Success, rule.validate(partlyValidHeader)); assertNotEquals(Success, rule.validate(invalidHeader)); }
@Test public void testStrict() { CompositeEthereumListener listener = new CompositeEthereumListenerMock(); EthashRule rule = new EthashRule(EthashRule.Mode.strict, EthashRule.ChainType.main, listener); assertEquals(Success, rule.validate(partlyValidHeader)); listener.onBlock(dummySummaryNum_1, true); assertEquals(Success, rule.validate(validHeader)); assertNotEquals(Success, rule.validate(partlyValidHeader)); assertNotEquals(Success, rule.validate(invalidHeader)); for (int i = 0; i < 100; i++) { assertNotEquals(Success, rule.validate(partlyValidHeader)); } }
@Test public void testMixed() { CompositeEthereumListener listener = new CompositeEthereumListenerMock(); EthashRule rule = new EthashRule(EthashRule.Mode.mixed, EthashRule.ChainType.main, listener); listener.onBlock(dummySummaryNum_1, true); boolean fullCheckTriggered = false; boolean partialCheckTriggered = false; for (int i = 0; i < 100; i++) { if (Success != rule.validate(partlyValidHeader)) { fullCheckTriggered = true; } else { partialCheckTriggered = true; } if (partialCheckTriggered & fullCheckTriggered) break; } assertTrue(fullCheckTriggered); assertTrue(partialCheckTriggered); listener.onSyncDone(EthereumListener.SyncState.COMPLETE); for (int i = 0; i < 100; i++) { assertNotEquals(Success, rule.validate(partlyValidHeader)); } }
@Test public void testCacheDirect() { EthashValidationHelperMock helper = new EthashValidationHelperMock(EthashValidationHelper.CacheOrder.direct); CompositeEthereumListener listener = new CompositeEthereumListenerMock(); EthashRule rule = new EthashRule(EthashRule.Mode.mixed, EthashRule.ChainType.direct, listener); rule.ethashHelper = helper; for (int i = 0; i < 100; i++) { rule.validate(validHeader); } assertEquals(100, helper.preCacheCounter); }
@Test public void testCacheReverse() { EthashValidationHelperMock helper = new EthashValidationHelperMock(EthashValidationHelper.CacheOrder.direct); CompositeEthereumListener listener = new CompositeEthereumListenerMock(); EthashRule rule = new EthashRule(EthashRule.Mode.mixed, EthashRule.ChainType.reverse, listener); rule.ethashHelper = helper; for (int i = 0; i < 100; i++) { rule.validate(validHeader); } assertEquals(100, helper.preCacheCounter); }