Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add clients information to user's graffiti when producing a block #8107

Merged
merged 11 commits into from
Mar 26, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright Consensys Software Inc., 2022
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package tech.pegasys.teku.test.acceptance;

import static org.assertj.core.api.Assertions.assertThat;

import com.google.common.io.Resources;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Locale;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.api.schema.bellatrix.SignedBeaconBlockBellatrix;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.test.acceptance.dsl.AcceptanceTestBase;
import tech.pegasys.teku.test.acceptance.dsl.GenesisGenerator.InitialStateData;
import tech.pegasys.teku.test.acceptance.dsl.TekuBeaconNode;
import tech.pegasys.teku.test.acceptance.dsl.TekuNodeConfigBuilder;
import tech.pegasys.teku.test.acceptance.dsl.TekuValidatorNode;
import tech.pegasys.teku.test.acceptance.dsl.tools.deposits.ValidatorKeystores;

public class BlockProposalAcceptanceTest extends AcceptanceTestBase {
private static final URL JWT_FILE = Resources.getResource("auth/ee-jwt-secret.hex");

@Test
void shouldHaveCorrectFeeRecipientAndGraffiti() throws Exception {
final String networkName = "swift";

final ValidatorKeystores validatorKeystores =
createTekuDepositSender(networkName).generateValidatorKeys(8);

final InitialStateData genesis =
createGenesisGenerator()
.network(networkName)
.withAltairEpoch(UInt64.ZERO)
.withBellatrixEpoch(UInt64.ZERO)
.validatorKeys(validatorKeystores, validatorKeystores)
.generate();

final String defaultFeeRecipient = "0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73";
final String userGraffiti = "My block \uD83D\uDE80"; // 13 bytes
final TekuBeaconNode beaconNode =
createTekuBeaconNode(
TekuNodeConfigBuilder.createBeaconNode()
.withStubExecutionEngine()
.withJwtSecretFile(JWT_FILE)
.withNetwork(networkName)
.withInitialState(genesis)
.withAltairEpoch(UInt64.ZERO)
.withBellatrixEpoch(UInt64.ZERO)
.withValidatorProposerDefaultFeeRecipient(defaultFeeRecipient)
.build());
final TekuValidatorNode validatorClient =
createValidatorNode(
TekuNodeConfigBuilder.createValidatorClient()
.withReadOnlyKeystorePath(validatorKeystores)
.withValidatorProposerDefaultFeeRecipient(defaultFeeRecipient)
.withInteropModeDisabled()
.withBeaconNodes(beaconNode)
.withGraffiti(userGraffiti)
.withNetwork("auto")
.build());

beaconNode.start();
validatorClient.start();

beaconNode.waitForBlockSatisfying(
block -> {
assertThat(block).isInstanceOf(SignedBeaconBlockBellatrix.class);
final SignedBeaconBlockBellatrix bellatrixBlock = (SignedBeaconBlockBellatrix) block;
assertThat(
bellatrixBlock.getMessage().getBody().executionPayload.feeRecipient.toHexString())
.isEqualTo(defaultFeeRecipient.toLowerCase(Locale.ROOT));
final Bytes32 graffiti = bellatrixBlock.getMessage().getBody().graffiti;
final String graffitiMessage =
new String(
Arrays.copyOfRange(
graffiti.toArray(), 0, 32 - graffiti.numberOfTrailingZeroBytes()),
StandardCharsets.UTF_8);
// 13 bytes + 1 byte
assertThat(graffitiMessage).startsWith(userGraffiti + " ");
// 18 bytes left, so 12 bytes client footprint: TKxxxxELxxxx. 20 bytes with full commits
// doesn't fit
assertThat(graffitiMessage).contains("TK");
// stub execution endpoint.
assertThat(graffitiMessage).endsWith("SB0000");
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.assertj.core.api.ThrowingConsumer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
import tech.pegasys.teku.api.response.v1.EventType;
Expand Down Expand Up @@ -484,6 +485,19 @@ public void waitForNonDefaultExecutionPayload() {
MINUTES);
}

public void waitForBlockSatisfying(final ThrowingConsumer<? super SignedBlock> assertions) {
LOG.debug("Wait for a block satisfying certain assertions");

waitFor(
() -> {
final Optional<SignedBlock> block = fetchHeadBlock();
assertThat(block).isPresent();
assertThat(block.get()).satisfies(assertions);
},
1,
MINUTES);
}

public void waitForGenesisWithNonDefaultExecutionPayload() {
LOG.debug("Wait for genesis block containing a non default execution payload");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,12 @@ public TekuNodeConfigBuilder withGenesisTime(int time) {
return this;
}

public TekuNodeConfigBuilder withGraffiti(final String graffiti) {
LOG.debug("validators-graffiti: {}", graffiti);
configMap.put("validators-graffiti", graffiti);
return this;
}

private TekuNodeConfigBuilder withPrivateKey(PrivKey privKey) throws IOException {
mustBe(NodeType.BEACON_NODE);
this.maybePrivKey = Optional.ofNullable(privKey);
Expand Down
1 change: 1 addition & 0 deletions beacon/validator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies {
implementation project(':ethereum:pow:api')
implementation project(':ethereum:pow:merkletree')
implementation project(':ethereum:spec')
implementation project(':ethereum:executionclient')
implementation project(':networking:eth2')
implementation project(':infrastructure:logging')
implementation project(':infrastructure:ssz')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public class BlockOperationSelectorFactory {
private final SyncCommitteeContributionPool contributionPool;
private final DepositProvider depositProvider;
private final Eth1DataCache eth1DataCache;
private final DefaultGraffitiProvider defaultGraffitiProvider;
private final GraffitiBuilder graffitiBuilder;
private final ForkChoiceNotifier forkChoiceNotifier;
private final ExecutionLayerBlockProductionManager executionLayerBlockProductionManager;

Expand All @@ -87,7 +87,7 @@ public BlockOperationSelectorFactory(
final SyncCommitteeContributionPool contributionPool,
final DepositProvider depositProvider,
final Eth1DataCache eth1DataCache,
final DefaultGraffitiProvider defaultGraffitiProvider,
final GraffitiBuilder graffitiBuilder,
final ForkChoiceNotifier forkChoiceNotifier,
final ExecutionLayerBlockProductionManager executionLayerBlockProductionManager) {
this.spec = spec;
Expand All @@ -99,7 +99,7 @@ public BlockOperationSelectorFactory(
this.contributionPool = contributionPool;
this.depositProvider = depositProvider;
this.eth1DataCache = eth1DataCache;
this.defaultGraffitiProvider = defaultGraffitiProvider;
this.graffitiBuilder = graffitiBuilder;
this.forkChoiceNotifier = forkChoiceNotifier;
this.executionLayerBlockProductionManager = executionLayerBlockProductionManager;
}
Expand Down Expand Up @@ -146,7 +146,7 @@ public Function<BeaconBlockBodyBuilder, SafeFuture<Void>> createSelector(
bodyBuilder
.randaoReveal(randaoReveal)
.eth1Data(eth1Data)
.graffiti(optionalGraffiti.orElse(defaultGraffitiProvider.getDefaultGraffiti()))
.graffiti(graffitiBuilder.buildGraffiti(optionalGraffiti))
.attestations(attestations)
.proposerSlashings(proposerSlashings)
.attesterSlashings(attesterSlashings)
Expand Down

This file was deleted.

Loading