[NC-1615] Upgrade ethereum reference tests (#54)

* Upgrade ethereum reference tests

* Add support for sealEngine: NoProof by skipping PoW validation for ommer headers as well.  Production code continues to always use full validation for ommers.

* Add Constantinople to reference test schedules ready for when we enable Constantinople tests.

* Blacklist the new reference tests that are failing while we investigate them.
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Adrian Sutton 6 years ago committed by GitHub
parent 0b3991b4a0
commit 681b17cce1
  1. 6
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockImporter.java
  2. 6
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockImporterTest.java
  3. 5
      ethereum/core/build.gradle
  4. 22
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/BlockImporter.java
  5. 10
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/BlockBodyValidator.java
  6. 31
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockBodyValidator.java
  7. 9
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockImporter.java
  8. 9
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/BlockchainReferenceTestCaseSpec.java
  9. 15
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/BlockchainReferenceTestTools.java
  10. 61
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTestTools.java
  11. 6
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java
  12. 4
      ethereum/core/src/test/resources/tech/pegasys/pantheon/ethereum/vm/BlockchainReferenceTest.java.template
  13. 4
      ethereum/core/src/test/resources/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTest.java.template
  14. 2
      ethereum/referencetests/src/test/resources

@ -27,8 +27,10 @@ public class IbftBlockImporter implements BlockImporter<IbftContext> {
public boolean importBlock(
final ProtocolContext<IbftContext> context,
final Block block,
final HeaderValidationMode headerValidationMode) {
final boolean result = delegate.importBlock(context, block, headerValidationMode);
final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode) {
final boolean result =
delegate.importBlock(context, block, headerValidationMode, ommerValidationMode);
updateVoteTally(result, block.getHeader(), context);
return result;
}

@ -46,7 +46,8 @@ public class IbftBlockImporterTest {
headerBuilder.buildHeader(),
new BlockBody(Collections.emptyList(), Collections.emptyList()));
when(delegate.importBlock(context, block, HeaderValidationMode.FULL)).thenReturn(false);
when(delegate.importBlock(context, block, HeaderValidationMode.FULL, HeaderValidationMode.FULL))
.thenReturn(false);
importer.importBlock(context, block, HeaderValidationMode.FULL);
@ -76,7 +77,8 @@ public class IbftBlockImporterTest {
new BlockHeaderTestFixture().buildHeader(),
new BlockBody(Collections.emptyList(), Collections.emptyList()));
when(delegate.importBlock(context, block, HeaderValidationMode.FULL)).thenReturn(true);
when(delegate.importBlock(context, block, HeaderValidationMode.FULL, HeaderValidationMode.FULL))
.thenReturn(true);
importer.importBlock(context, block, HeaderValidationMode.FULL);

@ -59,7 +59,10 @@ def generateTestFiles(FileTree jsonPath, File resourcesPath, File templateFile,
fileSets.each { fileSet ->
def resPath = resourcesPath.getPath().replaceAll("\\\\", "/")
def name = fileSet.first().getPath().toString()
def name = fileSet
.find({ !it.getName().toString().startsWith(".")})
.getPath()
.toString()
.replaceAll("\\\\", "/")
.replaceAll(resPath + "/", "")
.replaceAll(pathstrip, "")

@ -23,8 +23,28 @@ public interface BlockImporter<C> {
* @return {@code true} if the block was added somewhere in the blockchain; otherwise {@code
* false}
*/
default boolean importBlock(
final ProtocolContext<C> context,
final Block block,
final HeaderValidationMode headerValidationMode) {
return importBlock(context, block, headerValidationMode, HeaderValidationMode.FULL);
}
/**
* Attempts to import the given block to the specificed blockchain and world state.
*
* @param context The context to attempt to update
* @param block The block
* @param headerValidationMode Determines the validation to perform on this header.
* @param ommerValidationMode Determines the validation to perform on ommer headers.
* @return {@code true} if the block was added somewhere in the blockchain; otherwise {@code
* false}
*/
boolean importBlock(
ProtocolContext<C> context, Block block, HeaderValidationMode headerValidationMode);
ProtocolContext<C> context,
Block block,
HeaderValidationMode headerValidationMode,
HeaderValidationMode ommerValidationMode);
/**
* Attempts to import the given block. Uses "fast" validation. Performs light validation using the

@ -18,13 +18,15 @@ public interface BlockBodyValidator<C> {
* @param receipts The receipts that correspond to the blocks transactions
* @param worldStateRootHash The rootHash defining the world state after processing this block and
* all of its transactions.
* @param ommerValidationMode The validation mode to use for ommer headers
* @return {@code true} if valid; otherwise {@code false}
*/
boolean validateBody(
ProtocolContext<C> context,
Block block,
List<TransactionReceipt> receipts,
Hash worldStateRootHash);
Hash worldStateRootHash,
final HeaderValidationMode ommerValidationMode);
/**
* Validates that the block body is valid, but skips state root validation.
@ -32,8 +34,12 @@ public interface BlockBodyValidator<C> {
* @param context The context to validate against
* @param block The block to validate
* @param receipts The receipts that correspond to the blocks transactions
* @param ommerValidationMode The validation mode to use for ommer headers
* @return {@code true} if valid; otherwise {@code false}
*/
boolean validateBodyLight(
ProtocolContext<C> context, Block block, List<TransactionReceipt> receipts);
ProtocolContext<C> context,
Block block,
List<TransactionReceipt> receipts,
final HeaderValidationMode ommerValidationMode);
}

@ -34,9 +34,10 @@ public class MainnetBlockBodyValidator<C> implements BlockBodyValidator<C> {
final ProtocolContext<C> context,
final Block block,
final List<TransactionReceipt> receipts,
final Hash worldStateRootHash) {
final Hash worldStateRootHash,
final HeaderValidationMode ommerValidationMode) {
if (!validateBodyLight(context, block, receipts)) {
if (!validateBodyLight(context, block, receipts, ommerValidationMode)) {
return false;
}
@ -51,7 +52,8 @@ public class MainnetBlockBodyValidator<C> implements BlockBodyValidator<C> {
public boolean validateBodyLight(
final ProtocolContext<C> context,
final Block block,
final List<TransactionReceipt> receipts) {
final List<TransactionReceipt> receipts,
final HeaderValidationMode ommerValidationMode) {
final BlockHeader header = block.getHeader();
final BlockBody body = block.getBody();
@ -75,7 +77,7 @@ public class MainnetBlockBodyValidator<C> implements BlockBodyValidator<C> {
return false;
}
if (!validateEthHash(context, block)) {
if (!validateEthHash(context, block, ommerValidationMode)) {
return false;
}
@ -130,7 +132,10 @@ public class MainnetBlockBodyValidator<C> implements BlockBodyValidator<C> {
return true;
}
private boolean validateEthHash(final ProtocolContext<C> context, final Block block) {
private boolean validateEthHash(
final ProtocolContext<C> context,
final Block block,
final HeaderValidationMode ommerValidationMode) {
final BlockHeader header = block.getHeader();
final BlockBody body = block.getBody();
@ -139,7 +144,7 @@ public class MainnetBlockBodyValidator<C> implements BlockBodyValidator<C> {
return false;
}
if (!validateOmmers(context, header, body.getOmmers())) {
if (!validateOmmers(context, header, body.getOmmers(), ommerValidationMode)) {
return false;
}
@ -156,7 +161,10 @@ public class MainnetBlockBodyValidator<C> implements BlockBodyValidator<C> {
}
private boolean validateOmmers(
final ProtocolContext<C> context, final BlockHeader header, final List<BlockHeader> ommers) {
final ProtocolContext<C> context,
final BlockHeader header,
final List<BlockHeader> ommers,
final HeaderValidationMode ommerValidationMode) {
if (ommers.size() > MAX_OMMERS) {
LOG.warn("Invalid block: ommer count {} exceeds ommer limit {}", ommers.size(), MAX_OMMERS);
return false;
@ -168,7 +176,7 @@ public class MainnetBlockBodyValidator<C> implements BlockBodyValidator<C> {
}
for (final BlockHeader ommer : ommers) {
if (!isOmmerValid(context, header, ommer)) {
if (!isOmmerValid(context, header, ommer, ommerValidationMode)) {
LOG.warn("Invalid block: ommer is invalid");
return false;
}
@ -193,11 +201,14 @@ public class MainnetBlockBodyValidator<C> implements BlockBodyValidator<C> {
}
private boolean isOmmerValid(
final ProtocolContext<C> context, final BlockHeader current, final BlockHeader ommer) {
final ProtocolContext<C> context,
final BlockHeader current,
final BlockHeader ommer,
final HeaderValidationMode ommerValidationMode) {
final ProtocolSpec<C> protocolSpec = protocolSchedule.getByBlockNumber(ommer.getNumber());
if (!protocolSpec
.getBlockHeaderValidator()
.validateHeader(ommer, context, HeaderValidationMode.FULL)) {
.validateHeader(ommer, context, ommerValidationMode)) {
return false;
}

@ -37,7 +37,8 @@ public class MainnetBlockImporter<C> implements BlockImporter<C> {
public synchronized boolean importBlock(
final ProtocolContext<C> context,
final Block block,
final HeaderValidationMode headerValidationMode) {
final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode) {
final BlockHeader header = block.getHeader();
final Optional<BlockHeader> maybeParentHeader =
@ -65,7 +66,8 @@ public class MainnetBlockImporter<C> implements BlockImporter<C> {
}
final List<TransactionReceipt> receipts = result.getReceipts();
if (!blockBodyValidator.validateBody(context, block, receipts, worldState.rootHash())) {
if (!blockBodyValidator.validateBody(
context, block, receipts, worldState.rootHash(), ommerValidationMode)) {
return false;
}
@ -86,7 +88,8 @@ public class MainnetBlockImporter<C> implements BlockImporter<C> {
return false;
}
if (!blockBodyValidator.validateBodyLight(context, block, receipts)) {
if (!blockBodyValidator.validateBodyLight(
context, block, receipts, HeaderValidationMode.FULL)) {
return false;
}

@ -45,6 +45,7 @@ public class BlockchainReferenceTestCaseSpec {
private final WorldStateArchive worldStateArchive;
private final MutableBlockchain blockchain;
private final String sealEngine;
private final ProtocolContext<Void> protocolContext;
@ -78,7 +79,8 @@ public class BlockchainReferenceTestCaseSpec {
@JsonProperty("genesisBlockHeader") final BlockHeaderMock genesisBlockHeader,
@JsonProperty("genesisRLP") final String genesisRLP,
@JsonProperty("pre") final Map<String, WorldStateMock.AccountMock> accounts,
@JsonProperty("lastblockhash") final String lastBlockHash) {
@JsonProperty("lastblockhash") final String lastBlockHash,
@JsonProperty("sealEngine") final String sealEngine) {
this.network = network;
this.candidateBlocks = candidateBlocks;
this.genesisBlockHeader = genesisBlockHeader;
@ -86,6 +88,7 @@ public class BlockchainReferenceTestCaseSpec {
this.lastBlockHash = Hash.fromHexString(lastBlockHash);
this.worldStateArchive = buildWorldStateArchive(accounts);
this.blockchain = buildBlockchain(genesisBlockHeader);
this.sealEngine = sealEngine;
this.protocolContext = new ProtocolContext<>(this.blockchain, this.worldStateArchive, null);
}
@ -117,6 +120,10 @@ public class BlockchainReferenceTestCaseSpec {
return lastBlockHash;
}
public String getSealEngine() {
return sealEngine;
}
public static class BlockHeaderMock extends BlockHeader {
@JsonCreator

@ -54,8 +54,17 @@ public class BlockchainReferenceTestTools {
params.blacklist("ChainAtoChainB_BlockHash_(Frontier|Homestead|EIP150|EIP158|Byzantium)");
// Known bad test.
params.blacklist("RevertPrecompiledTouch_d0g0v0_(EIP158|Byzantium)");
// Consumes a huge amount of memory
params.blacklist("static_Call1MB1024Calldepth_d1g0v0_Byzantium");
// Pantheon is incorrectly rejecting Uncle block timestamps in the future
params.blacklist("futureUncleTimestampDifficultyDrop2");
params.blacklist("futureUncleTimestampDifficultyDrop");
// Needs investigation
params.blacklist("RevertInCreateInInit_d0g0v0_Byzantium");
params.blacklist("RevertInCreateInInit_d0g0v0_Constantinople");
}
public static Collection<Object[]> generateTestParametersForConfig(final String[] filePath) {
@ -86,8 +95,12 @@ public class BlockchainReferenceTestTools {
final ProtocolSpec<Void> protocolSpec =
schedule.getByBlockNumber(block.getHeader().getNumber());
final BlockImporter<Void> blockImporter = protocolSpec.getBlockImporter();
final HeaderValidationMode validationMode =
"NoProof".equalsIgnoreCase(spec.getSealEngine())
? HeaderValidationMode.LIGHT
: HeaderValidationMode.FULL;
final boolean imported =
blockImporter.importBlock(context, block, HeaderValidationMode.FULL);
blockImporter.importBlock(context, block, validationMode, validationMode);
assertThat(imported).isEqualTo(candidateBlock.isValid());
} catch (final RLPException e) {

@ -71,6 +71,67 @@ public class GeneralStateReferenceTestTools {
params.blacklist("OverflowGasRequire");
// Consumes a huge amount of memory
params.blacklist("static_Call1MB1024Calldepth-Byzantium");
// Needs investigation (tests pass in other clients)
params.blacklist("createNameRegistratorPerTxsNotEnoughGas-Frontier\\[0\\]");
params.blacklist("NotEnoughCashContractCreation-Frontier");
params.blacklist("NotEnoughCashContractCreation-Homestead");
params.blacklist("NotEnoughCashContractCreation-EIP150");
params.blacklist("OutOfGasContractCreation-EIP150\\[0\\]");
params.blacklist("OutOfGasContractCreation-EIP150\\[2\\]");
params.blacklist("OutOfGasContractCreation-Homestead\\[0\\]");
params.blacklist("OutOfGasContractCreation-Homestead\\[2\\]");
params.blacklist("OutOfGasPrefundedContractCreation-EIP150");
params.blacklist("OutOfGasPrefundedContractCreation-Homestead");
params.blacklist("201503110226PYTHON_DUP6-EIP150");
params.blacklist("201503110226PYTHON_DUP6-Frontier");
params.blacklist("201503110226PYTHON_DUP6-Homestead");
params.blacklist("RevertOpcodeWithBigOutputInInit-EIP150\\[2\\]");
params.blacklist("RevertOpcodeWithBigOutputInInit-EIP150\\[3\\]");
params.blacklist("RevertOpcodeWithBigOutputInInit-Homestead\\[2\\]");
params.blacklist("RevertOpcodeWithBigOutputInInit-Homestead\\[3\\]");
params.blacklist("RevertInCreateInInit-Byzantium");
params.blacklist("RevertOpcodeInInit-EIP150\\[2\\]");
params.blacklist("RevertOpcodeInInit-EIP150\\[3\\]");
params.blacklist("RevertOpcodeInInit-Homestead\\[2\\]");
params.blacklist("RevertOpcodeInInit-Homestead\\[3\\]");
params.blacklist("suicideCoinbase-Frontier");
params.blacklist("suicideCoinbase-Homestead");
params.blacklist("TransactionNonceCheck-EIP150");
params.blacklist("TransactionNonceCheck-Frontier");
params.blacklist("TransactionNonceCheck-Homestead");
params.blacklist("EmptyTransaction-EIP150");
params.blacklist("EmptyTransaction-Frontier");
params.blacklist("EmptyTransaction-Homestead");
params.blacklist("RefundOverflow-EIP150");
params.blacklist("RefundOverflow-Frontier");
params.blacklist("RefundOverflow-Homestead");
params.blacklist("TransactionToItselfNotEnoughFounds-EIP150");
params.blacklist("TransactionToItselfNotEnoughFounds-Frontier");
params.blacklist("TransactionToItselfNotEnoughFounds-Homestead");
params.blacklist("TransactionNonceCheck2-EIP150");
params.blacklist("TransactionNonceCheck2-Frontier");
params.blacklist("TransactionNonceCheck2-Homestead");
params.blacklist("CreateTransactionReverted-EIP150");
params.blacklist("CreateTransactionReverted-Frontier");
params.blacklist("CreateTransactionReverted-Homestead");
params.blacklist("RefundOverflow2-EIP150");
params.blacklist("RefundOverflow2-Frontier");
params.blacklist("RefundOverflow2-Homestead");
params.blacklist("SuicidesMixingCoinbase-Frontier\\[0\\]");
params.blacklist("SuicidesMixingCoinbase-Frontier\\[1\\]");
params.blacklist("SuicidesMixingCoinbase-Homestead\\[0\\]");
params.blacklist("SuicidesMixingCoinbase-Homestead\\[1\\]");
params.blacklist("createNameRegistratorPerTxsNotEnoughGasBefore-EIP150");
params.blacklist("createNameRegistratorPerTxsNotEnoughGasBefore-Homestead");
params.blacklist("createNameRegistratorPerTxsNotEnoughGasAfter-EIP150");
params.blacklist("createNameRegistratorPerTxsNotEnoughGasAfter-Homestead");
params.blacklist("createNameRegistratorPerTxsNotEnoughGasAt-EIP150");
params.blacklist("createNameRegistratorPerTxsNotEnoughGasAt-Homestead");
params.blacklist("UserTransactionGasLimitIsTooLowWhenZeroCost-EIP150");
params.blacklist("UserTransactionGasLimitIsTooLowWhenZeroCost-Frontier");
params.blacklist("UserTransactionGasLimitIsTooLowWhenZeroCost-Homestead");
params.blacklist("ecmul_0-3_5616_28000_96-Byzantium\\[3\\]");
}
public static Collection<Object[]> generateTestParametersForConfig(final String[] filePath) {

@ -31,7 +31,11 @@ public class ReferenceTestProtocolSchedules {
builder.put(
"Byzantium",
createSchedule(
protocolSpecLookup -> MainnetProtocolSpecs.byzantium(CHAIN_ID, protocolSpecLookup)));
protocolSchedule -> MainnetProtocolSpecs.byzantium(CHAIN_ID, protocolSchedule)));
builder.put(
"Constantinople",
createSchedule(
protocolSchedule -> MainnetProtocolSpecs.constantinople(CHAIN_ID, protocolSchedule)));
return new ReferenceTestProtocolSchedules(builder.build());
}

@ -26,7 +26,9 @@ public class %%TESTS_NAME%% {
private final String name;
private final BlockchainReferenceTestCaseSpec spec;
public %%TESTS_NAME%%(String name, BlockchainReferenceTestCaseSpec spec) {
public %%TESTS_NAME%%(
final String name,
final BlockchainReferenceTestCaseSpec spec) {
this.name = name;
this.spec = spec;
}

@ -26,7 +26,9 @@ public class %%TESTS_NAME%% {
private final String name;
private final GeneralStateTestCaseEipSpec spec;
public %%TESTS_NAME%%(String name, GeneralStateTestCaseEipSpec spec) {
public %%TESTS_NAME%%(
final String name,
final GeneralStateTestCaseEipSpec spec) {
this.name = name;
this.spec = spec;
}

@ -1 +1 @@
Subproject commit 2bb0c3da3bbb15c528bcef2a7e5ac4bd73f81f87
Subproject commit 0c76bf7d18e63bb65e4b8ffdd20e602e97e1c83b
Loading…
Cancel
Save