Skip to content

Commit

Permalink
Add clients information to user's graffiti when producing a block (#8107
Browse files Browse the repository at this point in the history
)
  • Loading branch information
zilm13 authored Mar 26, 2024
1 parent 9ce484a commit 02110f1
Show file tree
Hide file tree
Showing 23 changed files with 1,058 additions and 256 deletions.
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

0 comments on commit 02110f1

Please sign in to comment.