diff --git a/build.gradle b/build.gradle index 0adad56b0ce..853ff96fa44 100644 --- a/build.gradle +++ b/build.gradle @@ -531,7 +531,7 @@ allprojects { } def nightly = System.getenv("NIGHTLY") != null -def refTestVersion = nightly ? "nightly" : "v1.7.0-alpha.14" +def refTestVersion = nightly ? "nightly" : "v1.7.0-beta.0" def blsRefTestVersion = 'v0.1.2' def slashingProtectionInterchangeRefTestVersion = 'v5.3.0' def refTestBaseUrl = 'https://github.com/ethereum/consensus-specs/releases/download' diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/altair/fork/ForkUpgradeTestExecutor.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/altair/fork/ForkUpgradeTestExecutor.java index e617079020c..42cd4249119 100644 --- a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/altair/fork/ForkUpgradeTestExecutor.java +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/altair/fork/ForkUpgradeTestExecutor.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableMap; import tech.pegasys.teku.ethtests.finder.TestDefinition; +import tech.pegasys.teku.reference.BlsSetting; import tech.pegasys.teku.reference.TestDataUtils; import tech.pegasys.teku.reference.TestExecutor; import tech.pegasys.teku.spec.SpecMilestone; @@ -44,13 +45,17 @@ public class ForkUpgradeTestExecutor implements TestExecutor { public void runTest(final TestDefinition testDefinition) throws Throwable { final MetaData metadata = TestDataUtils.loadYaml(testDefinition, "meta.yaml", MetaData.class); final SpecMilestone specMilestone = SpecMilestone.forName(metadata.fork); - processUpgrade(testDefinition, specMilestone); + final boolean blsEnabled = metadata.getBlsSetting() != BlsSetting.IGNORED; + processUpgrade(testDefinition, specMilestone, blsEnabled); } - private void processUpgrade(final TestDefinition testDefinition, final SpecMilestone milestone) { + private void processUpgrade( + final TestDefinition testDefinition, + final SpecMilestone milestone, + final boolean blsEnabled) { final SpecMilestone previousMilestone = milestone.getPreviousMilestone(); final SpecVersion previousMilestoneSpecVersion = - testDefinition.getSpec().forMilestone(previousMilestone); + testDefinition.getSpec(blsEnabled).forMilestone(previousMilestone); final BeaconStateSchema fromMilestoneSchema = switch (milestone) { case ALTAIR -> BeaconStateSchemaPhase0.create(previousMilestoneSpecVersion.getConfig()); @@ -92,7 +97,7 @@ private void processUpgrade(final TestDefinition testDefinition, final SpecMiles final BeaconState postState = TestDataUtils.loadStateFromSsz(testDefinition, "post.ssz_snappy"); final StateUpgrade stateUpgrade = - testDefinition.getSpec().getGenesisSpec().getStateUpgrade().orElseThrow(); + testDefinition.getSpec(blsEnabled).getGenesisSpec().getStateUpgrade().orElseThrow(); final BeaconState updated = stateUpgrade.upgrade(preState); @@ -102,5 +107,12 @@ private void processUpgrade(final TestDefinition testDefinition, final SpecMiles private static class MetaData { @JsonProperty(value = "fork", required = true) private String fork; + + @JsonProperty(value = "bls_setting", required = false, defaultValue = "1") + private int blsSetting; + + public BlsSetting getBlsSetting() { + return BlsSetting.forCode(blsSetting); + } } } diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/gossip/GossipExecutionPayloadBidTestExecutor.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/gossip/GossipExecutionPayloadBidTestExecutor.java index c7af889300a..6e1baace90d 100644 --- a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/gossip/GossipExecutionPayloadBidTestExecutor.java +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/gossip/GossipExecutionPayloadBidTestExecutor.java @@ -29,6 +29,7 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import org.apache.tuweni.bytes.Bytes32; +import org.opentest4j.TestAbortedException; import tech.pegasys.teku.ethtests.finder.TestDefinition; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.unsigned.UInt64; @@ -64,11 +65,21 @@ import tech.pegasys.teku.storage.store.UpdatableStore; public class GossipExecutionPayloadBidTestExecutor implements TestExecutor { + private final List testsToSkip; private static final int MIN_BID_INCREMENT_PERCENTAGE = 1; + public GossipExecutionPayloadBidTestExecutor(final String... testsToSkip) { + this.testsToSkip = List.of(testsToSkip); + } + @Override public void runTest(final TestDefinition testDefinition) throws Throwable { + if (testsToSkip.contains(testDefinition.getTestName())) { + throw new TestAbortedException( + "Test " + testDefinition.getDisplayName() + " has been ignored"); + } + final GossipExecutionPayloadBidMetaData metaData = loadYaml(testDefinition, "meta.yaml", GossipExecutionPayloadBidMetaData.class); final boolean signatureVerificationDisabled = metaData.getBlsSetting() == BlsSetting.IGNORED; diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/gossip/GossipTests.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/gossip/GossipTests.java index 6a49d72a380..659a05faac7 100644 --- a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/gossip/GossipTests.java +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/gossip/GossipTests.java @@ -21,7 +21,8 @@ public class GossipTests { public static final ImmutableMap GOSSIP_TEST_TYPES = ImmutableMap.builder() - .put("networking/gossip_attester_slashing", new GossipAttesterSlashingTestExecutor()) + // TODO: https://github.com/Consensys-Incorporated/teku/issues/11229 + .put("networking/gossip_attester_slashing", TestExecutor.IGNORE_TESTS) .put( "networking/gossip_beacon_aggregate_and_proof", new GossipBeaconAggregateAndProofTestExecutor( @@ -48,18 +49,24 @@ public class GossipTests { .put( "networking/gossip_sync_committee_message", new GossipSyncCommitteeMessageTestExecutor()) - .put("networking/gossip_proposer_slashing", new GossipProposerSlashingTestExecutor()) - .put("networking/gossip_voluntary_exit", new GossipVoluntaryExitTestExecutor()) + // TODO: https://github.com/Consensys-Incorporated/teku/issues/11229 + .put("networking/gossip_proposer_slashing", TestExecutor.IGNORE_TESTS) + // TODO: https://github.com/Consensys-Incorporated/teku/issues/11229 + .put("networking/gossip_voluntary_exit", TestExecutor.IGNORE_TESTS) .put( "networking/gossip_payload_attestation_message", new GossipPayloadAttestationMessageTestExecutor()) .put( - "networking/gossip_proposer_preferences", new GossipProposerPreferencesTestExecutor()) + // TODO: https://github.com/Consensys-Incorporated/teku/issues/11232 + "networking/gossip_proposer_preferences", TestExecutor.IGNORE_TESTS) .put( "networking/gossip_execution_payload_envelope", new GossipExecutionPayloadEnvelopeTestExecutor()) .put( "networking/gossip_execution_payload_bid", - new GossipExecutionPayloadBidTestExecutor()) + // TODO: https://github.com/Consensys-Incorporated/teku/issues/11233 + new GossipExecutionPayloadBidTestExecutor( + "gossip_execution_payload_bid__ignore_builder_exit_in_parent_payload", + "gossip_execution_payload_bid__ignore_builder_exit_with_pending_balance")) .build(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/gloas/block/BlockProcessorGloas.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/gloas/block/BlockProcessorGloas.java index 2d852ee0893..173a34f656b 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/gloas/block/BlockProcessorGloas.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/gloas/block/BlockProcessorGloas.java @@ -319,6 +319,12 @@ public UInt64 processExecutionPayloadBid( beaconStateAccessors.getBlockRootAtSlot(state, state.getSlot().minusMinZero(1)))) { throw new BlockProcessingException("Bid is not for the right parent block"); } + + // Verify that the bid's block hash differs from its parent block hash + if (bid.getBlockHash().equals(bid.getParentBlockHash())) { + throw new BlockProcessingException("Bid's block hash is the same as the parent block hash"); + } + if (!bid.getPrevRandao() .equals( beaconStateAccessors.getRandaoMix( diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/gloas/block/BlockProcessorGloasTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/gloas/block/BlockProcessorGloasTest.java index 2d91f64e0e5..b30b1ccfe1b 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/gloas/block/BlockProcessorGloasTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/gloas/block/BlockProcessorGloasTest.java @@ -223,6 +223,37 @@ void processExecutionPayloadBid_shouldReturnPreviousBidSlot() throws BlockProces assertThat(mutableState.getLatestExecutionPayloadBid()).isEqualTo(bid); } + @Test + void processExecutionPayloadBid_shouldRejectWhenBlockHashEqualsParentBlockHash() { + final UInt64 currentSlot = UInt64.valueOf(8); + final MutableBeaconStateGloas mutableState = + BeaconStateGloas.required(dataStructureUtil.randomBeaconState(currentSlot)) + .createWritableCopy(); + final Bytes32 parentBlockHash = mutableState.getLatestBlockHash(); + final ExecutionPayloadBid bid = + schemaDefinitions + .getExecutionPayloadBidSchema() + .create( + parentBlockHash, + spec.getBlockRootAtSlot(mutableState, mutableState.getSlot().minusMinZero(1)), + parentBlockHash, + spec.getRandaoMix(mutableState, spec.getCurrentEpoch(mutableState)), + dataStructureUtil.randomBytes20(), + UInt64.ZERO, + SpecConfigGloas.BUILDER_INDEX_SELF_BUILD, + mutableState.getSlot(), + UInt64.ZERO, + UInt64.ZERO, + schemaDefinitions.getExecutionPayloadBidSchema().getBlobKzgCommitmentsSchema().of(), + dataStructureUtil.randomBytes32()); + final SignedExecutionPayloadBid signedBid = + schemaDefinitions.getSignedExecutionPayloadBidSchema().create(bid, BLSSignature.infinity()); + + assertThatThrownBy(() -> blockProcessor().processExecutionPayloadBid(mutableState, signedBid)) + .isInstanceOf(BlockProcessingException.class) + .hasMessage("Bid's block hash is the same as the parent block hash"); + } + @Test void processAttestation_shouldUseExplicitParentSlotForRewards() { final MismatchedParentFixture fixture = mismatchedParentFixture(); diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadBidGossipValidator.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadBidGossipValidator.java index 62ff2cd1935..778c3b3f21b 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadBidGossipValidator.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadBidGossipValidator.java @@ -87,6 +87,14 @@ public SafeFuture validate( rejectBid(bid, "execution payment should be 0 but was %s", executionPayment)); } + /* + * [REJECT] The bid's block hash is not equal to its parent block hash + */ + + if (bid.getBlockHash().equals(bid.getParentBlockHash())) { + return completedFuture(rejectBid(bid, "block hash and parent block hash are the same")); + } + /* * [IGNORE] bid.slot is the current slot or the next slot. */ diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadBidGossipValidatorTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadBidGossipValidatorTest.java index 4fd35d990bc..59b33402db2 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadBidGossipValidatorTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadBidGossipValidatorTest.java @@ -437,6 +437,16 @@ void shouldReject_whenBidSlotIsNotGreaterThanParentBlockSlot() { rejectBid(signedBid, "slot %s is not greater than parent block slot %s", slot, slot)); } + @TestTemplate + void shouldReject_whenBlockHashEqualsParentBlockHash() { + final SignedExecutionPayloadBid bidWithMatchingBlockHashes = + signedBidWithBlockHash(parentBlockHash); + + assertThatSafeFuture(bidValidator.validate(bidWithMatchingBlockHashes)) + .isCompletedWithValue( + rejectBid(bidWithMatchingBlockHashes, "block hash and parent block hash are the same")); + } + @TestTemplate void shouldSaveForFuture_whenStateIsUnavailable() { when(gossipValidationHelper.getParentStateInBlockEpoch(slot.decrement(), parentBlockRoot, slot)) @@ -790,6 +800,25 @@ private SignedExecutionPayloadBid signedBidWithGasLimit(final UInt64 gasLimit) { return dataStructureUtil.randomSignedExecutionPayloadBid(bidWithGasLimit); } + private SignedExecutionPayloadBid signedBidWithBlockHash(final Bytes32 blockHash) { + final ExecutionPayloadBid bidWithBlockHash = + bid.getSchema() + .create( + bid.getParentBlockHash(), + bid.getParentBlockRoot(), + blockHash, + bid.getPrevRandao(), + bid.getFeeRecipient(), + bid.getGasLimit(), + bid.getBuilderIndex(), + bid.getSlot(), + bid.getValue(), + bid.getExecutionPayment(), + bid.getBlobKzgCommitments(), + bid.getExecutionRequestsRoot()); + return dataStructureUtil.randomSignedExecutionPayloadBid(bidWithBlockHash); + } + private SignedExecutionPayloadBid signedBidForParent( final Bytes32 parentHash, final Bytes32 parentRoot, diff --git a/specrefs/.ethspecify.yml b/specrefs/.ethspecify.yml index 610be9b5862..74a3f09042c 100644 --- a/specrefs/.ethspecify.yml +++ b/specrefs/.ethspecify.yml @@ -1,4 +1,4 @@ -version: v1.7.0-alpha.14 +version: v1.7.0-beta.0 style: full specrefs: