Skip to content

Commit 02110f1

Browse files
authored
Add clients information to user's graffiti when producing a block (Consensys#8107)
1 parent 9ce484a commit 02110f1

File tree

23 files changed

+1058
-256
lines changed

23 files changed

+1058
-256
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright Consensys Software Inc., 2022
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package tech.pegasys.teku.test.acceptance;
15+
16+
import static org.assertj.core.api.Assertions.assertThat;
17+
18+
import com.google.common.io.Resources;
19+
import java.net.URL;
20+
import java.nio.charset.StandardCharsets;
21+
import java.util.Arrays;
22+
import java.util.Locale;
23+
import org.apache.tuweni.bytes.Bytes32;
24+
import org.junit.jupiter.api.Test;
25+
import tech.pegasys.teku.api.schema.bellatrix.SignedBeaconBlockBellatrix;
26+
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
27+
import tech.pegasys.teku.test.acceptance.dsl.AcceptanceTestBase;
28+
import tech.pegasys.teku.test.acceptance.dsl.GenesisGenerator.InitialStateData;
29+
import tech.pegasys.teku.test.acceptance.dsl.TekuBeaconNode;
30+
import tech.pegasys.teku.test.acceptance.dsl.TekuNodeConfigBuilder;
31+
import tech.pegasys.teku.test.acceptance.dsl.TekuValidatorNode;
32+
import tech.pegasys.teku.test.acceptance.dsl.tools.deposits.ValidatorKeystores;
33+
34+
public class BlockProposalAcceptanceTest extends AcceptanceTestBase {
35+
private static final URL JWT_FILE = Resources.getResource("auth/ee-jwt-secret.hex");
36+
37+
@Test
38+
void shouldHaveCorrectFeeRecipientAndGraffiti() throws Exception {
39+
final String networkName = "swift";
40+
41+
final ValidatorKeystores validatorKeystores =
42+
createTekuDepositSender(networkName).generateValidatorKeys(8);
43+
44+
final InitialStateData genesis =
45+
createGenesisGenerator()
46+
.network(networkName)
47+
.withAltairEpoch(UInt64.ZERO)
48+
.withBellatrixEpoch(UInt64.ZERO)
49+
.validatorKeys(validatorKeystores, validatorKeystores)
50+
.generate();
51+
52+
final String defaultFeeRecipient = "0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73";
53+
final String userGraffiti = "My block \uD83D\uDE80"; // 13 bytes
54+
final TekuBeaconNode beaconNode =
55+
createTekuBeaconNode(
56+
TekuNodeConfigBuilder.createBeaconNode()
57+
.withStubExecutionEngine()
58+
.withJwtSecretFile(JWT_FILE)
59+
.withNetwork(networkName)
60+
.withInitialState(genesis)
61+
.withAltairEpoch(UInt64.ZERO)
62+
.withBellatrixEpoch(UInt64.ZERO)
63+
.withValidatorProposerDefaultFeeRecipient(defaultFeeRecipient)
64+
.build());
65+
final TekuValidatorNode validatorClient =
66+
createValidatorNode(
67+
TekuNodeConfigBuilder.createValidatorClient()
68+
.withReadOnlyKeystorePath(validatorKeystores)
69+
.withValidatorProposerDefaultFeeRecipient(defaultFeeRecipient)
70+
.withInteropModeDisabled()
71+
.withBeaconNodes(beaconNode)
72+
.withGraffiti(userGraffiti)
73+
.withNetwork("auto")
74+
.build());
75+
76+
beaconNode.start();
77+
validatorClient.start();
78+
79+
beaconNode.waitForBlockSatisfying(
80+
block -> {
81+
assertThat(block).isInstanceOf(SignedBeaconBlockBellatrix.class);
82+
final SignedBeaconBlockBellatrix bellatrixBlock = (SignedBeaconBlockBellatrix) block;
83+
assertThat(
84+
bellatrixBlock.getMessage().getBody().executionPayload.feeRecipient.toHexString())
85+
.isEqualTo(defaultFeeRecipient.toLowerCase(Locale.ROOT));
86+
final Bytes32 graffiti = bellatrixBlock.getMessage().getBody().graffiti;
87+
final String graffitiMessage =
88+
new String(
89+
Arrays.copyOfRange(
90+
graffiti.toArray(), 0, 32 - graffiti.numberOfTrailingZeroBytes()),
91+
StandardCharsets.UTF_8);
92+
// 13 bytes + 1 byte
93+
assertThat(graffitiMessage).startsWith(userGraffiti + " ");
94+
// 18 bytes left, so 12 bytes client footprint: TKxxxxELxxxx. 20 bytes with full commits
95+
// doesn't fit
96+
assertThat(graffitiMessage).contains("TK");
97+
// stub execution endpoint.
98+
assertThat(graffitiMessage).endsWith("SB0000");
99+
});
100+
}
101+
}

Diff for: acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuBeaconNode.java

+14
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.apache.logging.log4j.Logger;
4747
import org.apache.tuweni.bytes.Bytes;
4848
import org.apache.tuweni.bytes.Bytes32;
49+
import org.assertj.core.api.ThrowingConsumer;
4950
import org.testcontainers.containers.Network;
5051
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
5152
import tech.pegasys.teku.api.response.v1.EventType;
@@ -484,6 +485,19 @@ public void waitForNonDefaultExecutionPayload() {
484485
MINUTES);
485486
}
486487

488+
public void waitForBlockSatisfying(final ThrowingConsumer<? super SignedBlock> assertions) {
489+
LOG.debug("Wait for a block satisfying certain assertions");
490+
491+
waitFor(
492+
() -> {
493+
final Optional<SignedBlock> block = fetchHeadBlock();
494+
assertThat(block).isPresent();
495+
assertThat(block.get()).satisfies(assertions);
496+
},
497+
1,
498+
MINUTES);
499+
}
500+
487501
public void waitForGenesisWithNonDefaultExecutionPayload() {
488502
LOG.debug("Wait for genesis block containing a non default execution payload");
489503

Diff for: acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuNodeConfigBuilder.java

+6
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,12 @@ public TekuNodeConfigBuilder withGenesisTime(int time) {
520520
return this;
521521
}
522522

523+
public TekuNodeConfigBuilder withGraffiti(final String graffiti) {
524+
LOG.debug("validators-graffiti: {}", graffiti);
525+
configMap.put("validators-graffiti", graffiti);
526+
return this;
527+
}
528+
523529
private TekuNodeConfigBuilder withPrivateKey(PrivKey privKey) throws IOException {
524530
mustBe(NodeType.BEACON_NODE);
525531
this.maybePrivKey = Optional.ofNullable(privKey);

Diff for: beacon/validator/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ dependencies {
1818
implementation project(':ethereum:pow:api')
1919
implementation project(':ethereum:pow:merkletree')
2020
implementation project(':ethereum:spec')
21+
implementation project(':ethereum:executionclient')
2122
implementation project(':networking:eth2')
2223
implementation project(':infrastructure:logging')
2324
implementation project(':infrastructure:ssz')

Diff for: beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/BlockOperationSelectorFactory.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public class BlockOperationSelectorFactory {
7373
private final SyncCommitteeContributionPool contributionPool;
7474
private final DepositProvider depositProvider;
7575
private final Eth1DataCache eth1DataCache;
76-
private final DefaultGraffitiProvider defaultGraffitiProvider;
76+
private final GraffitiBuilder graffitiBuilder;
7777
private final ForkChoiceNotifier forkChoiceNotifier;
7878
private final ExecutionLayerBlockProductionManager executionLayerBlockProductionManager;
7979

@@ -87,7 +87,7 @@ public BlockOperationSelectorFactory(
8787
final SyncCommitteeContributionPool contributionPool,
8888
final DepositProvider depositProvider,
8989
final Eth1DataCache eth1DataCache,
90-
final DefaultGraffitiProvider defaultGraffitiProvider,
90+
final GraffitiBuilder graffitiBuilder,
9191
final ForkChoiceNotifier forkChoiceNotifier,
9292
final ExecutionLayerBlockProductionManager executionLayerBlockProductionManager) {
9393
this.spec = spec;
@@ -99,7 +99,7 @@ public BlockOperationSelectorFactory(
9999
this.contributionPool = contributionPool;
100100
this.depositProvider = depositProvider;
101101
this.eth1DataCache = eth1DataCache;
102-
this.defaultGraffitiProvider = defaultGraffitiProvider;
102+
this.graffitiBuilder = graffitiBuilder;
103103
this.forkChoiceNotifier = forkChoiceNotifier;
104104
this.executionLayerBlockProductionManager = executionLayerBlockProductionManager;
105105
}
@@ -146,7 +146,7 @@ public Function<BeaconBlockBodyBuilder, SafeFuture<Void>> createSelector(
146146
bodyBuilder
147147
.randaoReveal(randaoReveal)
148148
.eth1Data(eth1Data)
149-
.graffiti(optionalGraffiti.orElse(defaultGraffitiProvider.getDefaultGraffiti()))
149+
.graffiti(graffitiBuilder.buildGraffiti(optionalGraffiti))
150150
.attestations(attestations)
151151
.proposerSlashings(proposerSlashings)
152152
.attesterSlashings(attesterSlashings)

Diff for: beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/DefaultGraffitiProviderImpl.java

-117
This file was deleted.

0 commit comments

Comments
 (0)