Skip to content

Commit

Permalink
Capella changes (#722)
Browse files Browse the repository at this point in the history
Updated OpenApi spec
Introduced manual fork overridden cli option
Updated Acceptance Test
Updated Teku library to 23.2.0
  • Loading branch information
usmansaleem authored Feb 23, 2023
1 parent e8b60af commit 7edd73b
Show file tree
Hide file tree
Showing 16 changed files with 278 additions and 20 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## Next release
### Features Added
-
- Add Block signing support for Capella milestone

### Bugs fixed
- Upgrade to Vertx 4.3.8 to address CVE-2023-24815
-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import tech.pegasys.web3signer.core.service.jsonrpc.FilecoinSignature;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;

Expand Down Expand Up @@ -116,7 +117,7 @@ public Boolean walletVerify(
public String executeRawJsonRpcRequest(final String request) throws IOException {
final String url = getUrl() + rpcPath;
final HttpPost post = new HttpPost(url);
post.setEntity(new StringEntity(request, Charsets.UTF_8));
post.setEntity(new StringEntity(request, StandardCharsets.UTF_8));
post.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
AUTH_TOKEN.ifPresent(token -> post.setHeader("Authorization", "Bearer " + token));
try (final CloseableHttpClient httpClient = HttpClients.createDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class SignerConfiguration {
private final Optional<Long> altairForkEpoch;

private final Optional<Long> bellatrixForkEpoch;
private final Optional<Long> capellaForkEpoch;
private final Optional<String> network;
private final boolean keyManagerApiEnabled;
private Optional<WatermarkRepairParameters> watermarkRepairParameters;
Expand Down Expand Up @@ -104,6 +105,7 @@ public SignerConfiguration(
final Optional<Path> slashingDbPoolConfigurationFile,
final Optional<Long> altairForkEpoch,
final Optional<Long> bellatrixForkEpoch,
final Optional<Long> capellaForkEpoch,
final Optional<String> network,
final boolean keyManagerApiEnabled,
final Optional<WatermarkRepairParameters> watermarkRepairParameters) {
Expand Down Expand Up @@ -141,6 +143,7 @@ public SignerConfiguration(
this.slashingProtectionDbPoolConfigurationFile = slashingDbPoolConfigurationFile;
this.altairForkEpoch = altairForkEpoch;
this.bellatrixForkEpoch = bellatrixForkEpoch;
this.capellaForkEpoch = capellaForkEpoch;
this.network = network;
this.keyManagerApiEnabled = keyManagerApiEnabled;
this.watermarkRepairParameters = watermarkRepairParameters;
Expand Down Expand Up @@ -282,6 +285,10 @@ public Optional<Long> getBellatrixForkEpoch() {
return bellatrixForkEpoch;
}

public Optional<Long> getCapellaForkEpoch() {
return capellaForkEpoch;
}

public Optional<String> getNetwork() {
return network;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public class SignerConfigurationBuilder {
private long slashingPruningInterval = 1;
private Long altairForkEpoch = null;
private Long bellatrixForkEpoch = null;
private Long capellaForkEpoch = null;
private String network = null;
private boolean keyManagerApiEnabled = false;
private KeystoresParameters keystoresParameters;
Expand Down Expand Up @@ -243,6 +244,11 @@ public SignerConfigurationBuilder withBellatrixForkEpoch(final long bellatrixFor
return this;
}

public SignerConfigurationBuilder withCapellaForkEpoch(final long capellaForkEpoch) {
this.capellaForkEpoch = capellaForkEpoch;
return this;
}

public SignerConfigurationBuilder withNetwork(final String network) {
this.network = network;
return this;
Expand Down Expand Up @@ -307,6 +313,7 @@ public SignerConfiguration build() {
Optional.ofNullable(slashingProtectionDbPoolConfigurationFile),
Optional.ofNullable(altairForkEpoch),
Optional.ofNullable(bellatrixForkEpoch),
Optional.ofNullable(capellaForkEpoch),
Optional.ofNullable(network),
keyManagerApiEnabled,
Optional.ofNullable(watermarkRepairParameters));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,14 @@ private String createEth2SlashingProtectionArgs() {
signerConfig.getBellatrixForkEpoch().get()));
}

if (signerConfig.getCapellaForkEpoch().isPresent()) {
yamlConfig.append(
String.format(
YAML_NUMERIC_FMT,
"eth2.Xnetwork-capella-fork-epoch",
signerConfig.getCapellaForkEpoch().get()));
}

if (signerConfig.getNetwork().isPresent()) {
yamlConfig.append(
String.format(YAML_STRING_FMT, "eth2.network", signerConfig.getNetwork().get()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ private Collection<String> createEth2Args() {
params.add(Long.toString(signerConfig.getBellatrixForkEpoch().get()));
}

if (signerConfig.getCapellaForkEpoch().isPresent()) {
params.add("--Xnetwork-capella-fork-epoch");
params.add(Long.toString(signerConfig.getCapellaForkEpoch().get()));
}

if (signerConfig.getNetwork().isPresent()) {
params.add("--network");
params.add(signerConfig.getNetwork().get());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
* Copyright 2023 ConsenSys AG.
*
* 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.web3signer.dsl.utils;

import static java.util.stream.Collectors.toList;

import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.ssz.SszList;
import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecVersion;
import tech.pegasys.teku.spec.config.SpecConfigBellatrix;
import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock;
import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody;
import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodySchema;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload;
import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal;
import tech.pegasys.teku.spec.datastructures.operations.BlsToExecutionChange;
import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsCapella;
import tech.pegasys.teku.spec.util.DataStructureUtil;

import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

import org.apache.tuweni.bytes.Bytes32;

/**
* This class provide different implementation of randomBeaconBlock than Teku's DataStructureUtil.
* Instead of using genesis schema definition, our implementation uses spec at slot number to derive
* the schema definition.
*/
public class DataStructureUtilAdapter {
private static final int MAX_EP_RANDOM_WITHDRAWALS = 4;
private final DataStructureUtil util;
private int seed = 92892824;
private final Spec spec;

public DataStructureUtilAdapter(final Spec spec) {
this.spec = spec;
util = new DataStructureUtil(spec);
}

public BeaconBlock randomBeaconBlock(final UInt64 slotNum) {
final UInt64 proposerIndex = util.randomUInt64();
final Bytes32 previousRoot = util.randomBytes32();
final Bytes32 stateRoot = util.randomBytes32();
final BeaconBlockBody body = randomBeaconBlockBody(slotNum);
return new BeaconBlock(
spec.atSlot(slotNum).getSchemaDefinitions().getBeaconBlockSchema(),
slotNum,
proposerIndex,
previousRoot,
stateRoot,
body);
}

private BeaconBlockBody randomBeaconBlockBody(final UInt64 slotNum) {
final BeaconBlockBodySchema<?> schema =
spec.atSlot(slotNum).getSchemaDefinitions().getBeaconBlockBodySchema();
return schema
.createBlockBody(
builder -> {
builder
.randaoReveal(util.randomSignature())
.eth1Data(util.randomEth1Data())
.graffiti(Bytes32.ZERO)
.proposerSlashings(
util.randomSszList(
schema.getProposerSlashingsSchema(), util::randomProposerSlashing, 1))
.attesterSlashings(
util.randomSszList(
schema.getAttesterSlashingsSchema(), util::randomAttesterSlashing, 1))
.attestations(
util.randomSszList(
schema.getAttestationsSchema(), util::randomAttestation, 3))
.deposits(
util.randomSszList(
schema.getDepositsSchema(), util::randomDepositWithoutIndex, 1))
.voluntaryExits(
util.randomSszList(
schema.getVoluntaryExitsSchema(), util::randomSignedVoluntaryExit, 1));
if (builder.supportsSyncAggregate()) {
builder.syncAggregate(util.randomSyncAggregateIfRequiredBySchema(schema));
}
if (builder.supportsExecutionPayload()) {
builder.executionPayload(
SafeFuture.completedFuture(randomExecutionPayload(spec.atSlot(slotNum))));
}
if (builder.supportsBlsToExecutionChanges()) {
builder.blsToExecutionChanges(
randomSignedBlsToExecutionChangesList(spec.atSlot(slotNum)));
}
if (builder.supportsKzgCommitments()) {
builder.blobKzgCommitments(
SafeFuture.completedFuture(util.randomSszKzgCommitmentList()));
}
})
.join();
}

private ExecutionPayload randomExecutionPayload(final SpecVersion specVersion) {
final SpecConfigBellatrix specConfigBellatrix =
SpecConfigBellatrix.required(specVersion.getConfig());
return SchemaDefinitionsBellatrix.required(specVersion.getSchemaDefinitions())
.getExecutionPayloadSchema()
.createExecutionPayload(
builder ->
builder
.parentHash(util.randomBytes32())
.feeRecipient(util.randomBytes20())
.stateRoot(util.randomBytes32())
.receiptsRoot(util.randomBytes32())
.logsBloom(util.randomBytes(specConfigBellatrix.getBytesPerLogsBloom()))
.prevRandao(util.randomBytes32())
.blockNumber(util.randomUInt64())
.gasLimit(util.randomUInt64())
.gasUsed(util.randomUInt64())
.timestamp(util.randomUInt64())
.extraData(util.randomBytes(specConfigBellatrix.getMaxExtraDataBytes()))
.baseFeePerGas(util.randomUInt256())
.blockHash(util.randomBytes32())
.transactions(util.randomExecutionPayloadTransactions())
.withdrawals(() -> randomExecutionPayloadWithdrawals(specVersion))
.excessDataGas(util::randomUInt256));
}

private List<Withdrawal> randomExecutionPayloadWithdrawals(final SpecVersion specVersion) {
return IntStream.rangeClosed(0, randomInt(MAX_EP_RANDOM_WITHDRAWALS))
.mapToObj(__ -> randomWithdrawal(specVersion))
.collect(toList());
}

private Withdrawal randomWithdrawal(final SpecVersion specVersion) {
return SchemaDefinitionsCapella.required(specVersion.getSchemaDefinitions())
.getWithdrawalSchema()
.create(
util.randomUInt64(),
util.randomValidatorIndex(),
util.randomBytes20(),
util.randomUInt64());
}

private SszList<SignedBlsToExecutionChange> randomSignedBlsToExecutionChangesList(
final SpecVersion specVersion) {
final SszListSchema<SignedBlsToExecutionChange, ?> signedBlsToExecutionChangeSchema =
SchemaDefinitionsCapella.required(specVersion.getSchemaDefinitions())
.getBeaconBlockBodySchema()
.toVersionCapella()
.orElseThrow()
.getBlsToExecutionChangesSchema();
final int maxBlsToExecutionChanges =
specVersion.getConfig().toVersionCapella().orElseThrow().getMaxBlsToExecutionChanges();

return util.randomSszList(
signedBlsToExecutionChangeSchema,
maxBlsToExecutionChanges,
() -> randomSignedBlsToExecutionChange(specVersion));
}

private SignedBlsToExecutionChange randomSignedBlsToExecutionChange(
final SpecVersion specVersion) {
return SchemaDefinitionsCapella.required(specVersion.getSchemaDefinitions())
.getSignedBlsToExecutionChangeSchema()
.create(randomBlsToExecutionChange(specVersion), util.randomSignature());
}

private BlsToExecutionChange randomBlsToExecutionChange(final SpecVersion specVersion) {
return SchemaDefinitionsCapella.required(specVersion.getSchemaDefinitions())
.getBlsToExecutionChangeSchema()
.create(util.randomValidatorIndex(), util.randomPublicKey(), util.randomBytes20());
}

private int randomInt(final int bound) {
return new Random(nextSeed()).nextInt(bound);
}

private int nextSeed() {
return seed++;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock;
import tech.pegasys.teku.spec.datastructures.state.ForkInfo;
import tech.pegasys.teku.spec.signatures.SigningRootUtil;
import tech.pegasys.teku.spec.util.DataStructureUtil;
import tech.pegasys.web3signer.core.service.http.ArtifactType;
import tech.pegasys.web3signer.core.service.http.handlers.signing.eth2.BlockRequest;
import tech.pegasys.web3signer.core.service.http.handlers.signing.eth2.Eth2SigningRequestBody;
Expand All @@ -33,7 +32,7 @@

public class Eth2BlockSigningRequestUtil {
private final SpecMilestone specMilestone;
private final DataStructureUtil beaconBlockUtil;
private final DataStructureUtilAdapter beaconBlockUtil;
private final SigningRootUtil signingRootUtil;
private final ForkInfo tekuForkInfo;
private final Fork tekuFork;
Expand All @@ -44,7 +43,7 @@ public class Eth2BlockSigningRequestUtil {
public Eth2BlockSigningRequestUtil(final SpecMilestone specMilestone) {
final Spec spec = TestSpecFactory.createMinimal(specMilestone);
this.specMilestone = specMilestone;
beaconBlockUtil = new DataStructureUtil(spec);
beaconBlockUtil = new DataStructureUtilAdapter(spec);
signingRootUtil = new SigningRootUtil(spec);
tekuForkInfo = Eth2RequestUtils.forkInfo().asInternalForkInfo();
tekuFork = new Fork(tekuForkInfo.getFork());
Expand All @@ -58,7 +57,7 @@ public Eth2BlockSigningRequestUtil(final SpecMilestone specMilestone) {
public Eth2BlockSigningRequestUtil(
final Spec spec, final UInt64 forkEpoch, final UInt64 beaconBlockSlot) {
specMilestone = spec.atEpoch(forkEpoch).getMilestone();
beaconBlockUtil = new DataStructureUtil(spec);
beaconBlockUtil = new DataStructureUtilAdapter(spec);
signingRootUtil = new SigningRootUtil(spec);
tekuForkInfo = Eth2RequestUtils.forkInfo(forkEpoch.longValue()).asInternalForkInfo();
tekuFork = new Fork(tekuForkInfo.getFork());
Expand All @@ -75,6 +74,7 @@ public Eth2SigningRequestBody createBlockV2Request() {
case ALTAIR:
return createBlockV2Request(new BlockRequest(specMilestone, getBeaconBlock()));
case BELLATRIX:
case CAPELLA:
return createBlockV2Request(new BlockRequest(specMilestone, getBeaconBlockHeader()));
default:
throw new IllegalStateException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ void setup() {
METADATA_FILE_HELPERS.createUnencryptedYamlFileAt(keyConfigFile, PRIVATE_KEY, KeyType.BLS);
}

@ParameterizedTest
@ParameterizedTest(name = "#{index} - Sign and verify BlockV2 Signature for spec {0}")
@EnumSource(
value = SpecMilestone.class,
names = {"PHASE0", "ALTAIR", "BELLATRIX"})
names = {"PHASE0", "ALTAIR", "BELLATRIX", "CAPELLA"})
void signAndVerifyBlockV2Signature(final SpecMilestone specMilestone) throws Exception {
final Eth2BlockSigningRequestUtil util = new Eth2BlockSigningRequestUtil(specMilestone);

Expand Down Expand Up @@ -88,14 +88,18 @@ void signAndVerifyLegacyBlockSignature() throws Exception {
assertThat(signature).isEqualTo(expectedSignature.toBytesCompressed());
}

@Test
void emptyBlockRequestReturnsBadRequestStatus() throws JsonProcessingException {
final Eth2BlockSigningRequestUtil util =
new Eth2BlockSigningRequestUtil(SpecMilestone.BELLATRIX);
setupEth2Signer(Eth2Network.MINIMAL, SpecMilestone.BELLATRIX);
@ParameterizedTest(
name = "#{index} - Empty block request for spec {0} should return bad request status")
@EnumSource(
value = SpecMilestone.class,
names = {"PHASE0", "ALTAIR", "BELLATRIX", "CAPELLA"})
void emptyBlockRequestReturnsBadRequestStatus(final SpecMilestone specMilestone)
throws JsonProcessingException {
final Eth2BlockSigningRequestUtil util = new Eth2BlockSigningRequestUtil(specMilestone);
setupEth2Signer(Eth2Network.MINIMAL, specMilestone);

final Eth2SigningRequestBody request =
util.createBlockV2Request(new BlockRequest(SpecMilestone.BELLATRIX));
util.createBlockV2Request(new BlockRequest(specMilestone));
final Response response =
signer.eth2Sign(KEY_PAIR.getPublicKey().toString(), request, ContentType.JSON);

Expand Down
Loading

0 comments on commit 7edd73b

Please sign in to comment.