Skip to content

Commit

Permalink
External signer Altair block (#4282)
Browse files Browse the repository at this point in the history
* External signer Altair support

 -- send milestone and Altair specific block to external signer

Signed-off-by: Usman Saleem <usman@usmans.info>
  • Loading branch information
usmansaleem authored Aug 25, 2021
1 parent 6c859fa commit 2737b80
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 12 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ For information on changes in released versions of Teku, see the [releases page]
- Reduced CPU and GC pressure during epoch processing by avoiding setting validator effective balances to an unchanged value.
- Reduced memory usage and GC pressure created by state caches.
- Optimised length validation of gossip and RPC messages.
- Introduced new sign type for block signing requests for external signers, `block_v2`, to support Altair and future
milestones. Existing Sign type `block` is backward compatible with phase0.


### Bug Fixes
- Fixed `IllegalStateException: New response submitted after closing AsyncResponseProcessor` errors.
Expand Down
1 change: 1 addition & 0 deletions validator/client/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies {
implementation project(':validator:remote')
implementation project(':util')
implementation project(':data:serializer')
implementation project(':data:provider')

implementation 'org.apache.tuweni:tuweni-bytes'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@
import tech.pegasys.teku.bls.BLSKeyPair;
import tech.pegasys.teku.bls.BLSSignature;
import tech.pegasys.teku.bls.BLSTestUtil;
import tech.pegasys.teku.core.signatures.SigningRootUtil;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.async.ThrottlingTaskQueue;
import tech.pegasys.teku.infrastructure.metrics.StubMetricsSystem;
import tech.pegasys.teku.infrastructure.metrics.TekuMetricCategory;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock;
import tech.pegasys.teku.spec.datastructures.operations.versions.altair.ContributionAndProof;
import tech.pegasys.teku.spec.datastructures.operations.versions.altair.SyncAggregatorSelectionData;
import tech.pegasys.teku.spec.datastructures.operations.versions.altair.SyncCommitteeContribution;
Expand All @@ -59,6 +61,8 @@ public class ExternalSignerAltairIntegrationTest {
private static final Duration TIMEOUT = Duration.ofMillis(500);
private final Spec spec = TestSpecFactory.createMinimalAltair();
private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec);
private final SigningRootUtil signingRootUtil = new SigningRootUtil(spec);
private final ForkInfo fork = dataStructureUtil.randomForkInfo();
private final SyncCommitteeUtil syncCommitteeUtil =
spec.getSyncCommitteeUtilRequired(UInt64.ZERO);
private final UInt64 slot = UInt64.ZERO;
Expand Down Expand Up @@ -112,6 +116,33 @@ void tearDown() {
client.reset();
}

@Test
void shouldSignAltairBlock() throws Exception {
final BeaconBlock block = dataStructureUtil.randomBeaconBlock(10);
final BLSSignature expectedSignature =
BLSSignature.fromBytesCompressed(
Bytes.fromBase64String(
"luIZGEgsjSbFo4MEPVeqaqqm1AnnTODcxFy9gPmdAywVmDIpqkzYed8DJ2l4zx5WAejUTox+NO5HQ4M2APMNovd7FuqnCSVUEftrL4WtJqegPrING2ZCtVTrcaUzFpUQ"));
client.when(request()).respond(response().withBody(expectedSignature.toString()));

final BLSSignature response = externalSigner.signBlock(block, fork).join();
assertThat(response).isEqualTo(expectedSignature);

final ExternalSignerBlockRequestProvider externalSignerBlockRequestProvider =
new ExternalSignerBlockRequestProvider(spec, block);

final SigningRequestBody signingRequestBody =
new SigningRequestBody(
signingRootUtil.signingRootForSignBlock(block, fork),
externalSignerBlockRequestProvider.getSignType(),
externalSignerBlockRequestProvider.getBlockMetadata(
Map.of("fork_info", createForkInfo(fork))));

verifySignRequest(client, KEYPAIR.getPublicKey().toString(), signingRequestBody);

validateMetrics(metricsSystem, 1, 0, 0);
}

@Test
public void shouldSignSyncCommitteeMessage() throws Exception {
final Bytes expectedSigningRoot =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,15 @@ void shouldSignsBlock() throws Exception {
final BLSSignature response = externalSigner.signBlock(block, fork).join();
assertThat(response).isEqualTo(expectedSignature);

final ExternalSignerBlockRequestProvider externalSignerBlockRequestProvider =
new ExternalSignerBlockRequestProvider(spec, block);

final SigningRequestBody signingRequestBody =
new SigningRequestBody(
signingRootUtil.signingRootForSignBlock(block, fork),
SignType.BLOCK,
Map.of(
"fork_info",
createForkInfo(fork),
"block",
new tech.pegasys.teku.api.schema.BeaconBlock(block)));
externalSignerBlockRequestProvider.getSignType(),
externalSignerBlockRequestProvider.getBlockMetadata(
Map.of("fork_info", createForkInfo(fork))));

verifySignRequest(client, KEYPAIR.getPublicKey().toString(), signingRequestBody);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2020 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.teku.validator.client.signer;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import tech.pegasys.teku.api.schema.BeaconBlock;
import tech.pegasys.teku.spec.SpecMilestone;

public class BlockRequestBody {
private final SpecMilestone version;
private final BeaconBlock beaconBlock;

@JsonCreator
public BlockRequestBody(
@JsonProperty("version") final SpecMilestone version,
@JsonProperty("block") final BeaconBlock beaconBlock) {
this.version = version;
this.beaconBlock = beaconBlock;
}

@JsonProperty("version")
public SpecMilestone getVersion() {
return version;
}

@JsonProperty("block")
public BeaconBlock getBeaconBlock() {
return beaconBlock;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,13 @@ public SafeFuture<BLSSignature> createRandaoReveal(final UInt64 epoch, final For

@Override
public SafeFuture<BLSSignature> signBlock(final BeaconBlock block, final ForkInfo forkInfo) {
final ExternalSignerBlockRequestProvider blockRequestProvider =
new ExternalSignerBlockRequestProvider(spec, block);

return sign(
signingRootUtil.signingRootForSignBlock(block, forkInfo),
SignType.BLOCK,
Map.of(
"block",
new tech.pegasys.teku.api.schema.BeaconBlock(block),
FORK_INFO,
forkInfo(forkInfo)),
blockRequestProvider.getSignType(),
blockRequestProvider.getBlockMetadata(Map.of(FORK_INFO, forkInfo(forkInfo))),
slashableBlockMessage(block));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2021 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.teku.validator.client.signer;

import java.util.HashMap;
import java.util.Map;
import tech.pegasys.teku.api.SchemaObjectProvider;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock;

public class ExternalSignerBlockRequestProvider {
private final Spec spec;
private final SchemaObjectProvider schemaObjectProvider;
private final BeaconBlock block;
private final SignType signType;

public ExternalSignerBlockRequestProvider(final Spec spec, final BeaconBlock block) {
this.spec = spec;
this.block = block;
schemaObjectProvider = new SchemaObjectProvider(spec);
// backward compatible with phase 0
if (spec.atSlot(block.getSlot()).getMilestone().equals(SpecMilestone.PHASE0)) {
signType = SignType.BLOCK;
} else {
signType = SignType.BLOCK_V2;
}
}

public Map<String, Object> getBlockMetadata(final Map<String, Object> additionalEntries) {
final Map<String, Object> metadata = new HashMap<>(additionalEntries);

final tech.pegasys.teku.api.schema.BeaconBlock beaconBlock =
schemaObjectProvider.getBeaconBlock(block);
if (signType == SignType.BLOCK) {
metadata.put("block", beaconBlock); // backward compatible with phase0
} else {
metadata.put(
"beacon_block",
new BlockRequestBody(spec.atSlot(block.getSlot()).getMilestone(), beaconBlock));
}

return metadata;
}

public SignType getSignType() {
return signType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public enum SignType {
RANDAO_REVEAL,
@JsonProperty("block")
BLOCK,
@JsonProperty("block_v2")
BLOCK_V2,
@JsonProperty("attestation")
ATTESTATION,
@JsonProperty("aggregation_slot")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2021 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.teku.validator.client.signer;

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

import java.util.Map;
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock;
import tech.pegasys.teku.spec.util.DataStructureUtil;

class ExternalSignerBlockRequestProviderTest {

@Test
void phase0BlockGeneratesCorrectSignTypeAndMetadata() {
final Spec spec = TestSpecFactory.createMinimalPhase0();
final BeaconBlock block = new DataStructureUtil(spec).randomBeaconBlock(10);

final ExternalSignerBlockRequestProvider externalSignerBlockRequestProvider =
new ExternalSignerBlockRequestProvider(spec, block);
final SignType signType = externalSignerBlockRequestProvider.getSignType();
final Map<String, Object> blockMetadata =
externalSignerBlockRequestProvider.getBlockMetadata(Map.of());

assertThat(signType).isEqualTo(SignType.BLOCK);
assertThat(blockMetadata).containsKey("block");
}

@Test
void altairBlockGeneratesCorrectSignTypeAndMetadata() {
final Spec spec = TestSpecFactory.createMinimalAltair();
final BeaconBlock block = new DataStructureUtil(spec).randomBeaconBlock(10);

final ExternalSignerBlockRequestProvider externalSignerBlockRequestProvider =
new ExternalSignerBlockRequestProvider(spec, block);
final SignType signType = externalSignerBlockRequestProvider.getSignType();
final Map<String, Object> blockMetadata =
externalSignerBlockRequestProvider.getBlockMetadata(Map.of());

assertThat(signType).isEqualTo(SignType.BLOCK_V2);
assertThat(blockMetadata).containsKey("beacon_block");
assertThat(blockMetadata.get("beacon_block")).isExactlyInstanceOf(BlockRequestBody.class);
}
}

0 comments on commit 2737b80

Please sign in to comment.