Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5d18960
Add read functionality to blobs archiving (#9318)
StefanBratanov Apr 9, 2025
2477b9a
Schedule Gnosis Pectra hard-fork (#9340)
StefanBratanov Apr 10, 2025
6510fb3
Updated ref tests v1.5.0-beta.5 (#9341)
lucassaldanha Apr 10, 2025
023fa8a
Created Fulu skeleton (#9325)
lucassaldanha Apr 10, 2025
fff2385
Made checkpoint-state-url and initial-state mutually exclusive (#9342)
rolfyone Apr 10, 2025
bbf12b2
partial 3rd party updates and errorprone updates (#9351)
rolfyone Apr 14, 2025
ddca83b
Make builder timeouts only for the HTTP call (#9353)
StefanBratanov Apr 14, 2025
4d354eb
more 3rd party updates (#9355)
rolfyone Apr 15, 2025
b706f5b
KZG updates from das branch (#9335)
lucassaldanha Apr 15, 2025
f8389db
Avoid combining validators by aggregating committee when using DVT (#…
lucassaldanha Apr 16, 2025
e3259c5
builder json format, make media type more compatible (#9360)
tbenr Apr 16, 2025
5a695c7
refactored expected withdrawals and added test cases (#9361)
rolfyone Apr 16, 2025
4f92f4c
Use `URI.create(...).toURL()` removing URL constructor deprecation (#…
tbenr Apr 17, 2025
c2442a4
clear-changelog (#9366)
tbenr Apr 23, 2025
e4adc71
New infra stream module (#9362)
lucassaldanha Apr 27, 2025
5dad0ed
feat: Add support for reading static peers from file (#9328)
crStiv Apr 28, 2025
fe4a939
Start cleaning up `api/schema` (#9376)
rolfyone Apr 28, 2025
f93c8ff
cleanup the rest of api/schema (#9377)
rolfyone Apr 28, 2025
9af5370
Added KZG computeCells method (#9375)
lucassaldanha Apr 28, 2025
178a6bd
Fulu Schemas (ssz + datastructures) - including fulu ssz ref tests (#…
lucassaldanha Apr 28, 2025
dd40b5c
Added context to the sync committee duties error (#9380)
rolfyone May 1, 2025
4391e87
Returning custody_group_count on node/identity Beacon API (#9381)
lucassaldanha May 5, 2025
d3ee2d4
may 3rd party updates (#9388)
rolfyone May 5, 2025
6e54398
Added snakeyaml to allow more complicated config reading (#9390)
rolfyone May 6, 2025
7005739
Add FULU to the Spec Factory (#9373)
mehdi-aouadi May 6, 2025
5150373
Improve attestation bits aggregator electra (#9393)
tbenr May 7, 2025
10d8263
added a DeserializableConfigTypeDefinition (#9396)
rolfyone May 8, 2025
2fd5eb6
Updating ref test to 1.5.0 stable (#9398)
lucassaldanha May 8, 2025
39b3df8
Adding DataColumnsByRootIdentifier container
lucassaldanha May 8, 2025
bccab1b
PR comments
lucassaldanha May 8, 2025
40e7839
need more coffee...
lucassaldanha May 8, 2025
f13b314
uniforms the AggregatingAttestationPool interface (#9401)
tbenr May 8, 2025
9d26d07
Avoids potential mutability of the result of getCommitteeBits (#9402)
tbenr May 8, 2025
bdb6d17
Merge remote-tracking branch 'lucassaldanha/data-columns-by-root-id' …
zilm13 May 8, 2025
58dcdfc
Merge branch 'master' into das-master
zilm13 May 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
### Breaking Changes

### Additions and Improvements
- Updated Teku bootnode ENR on Sepolia and Mainnet
- Scheduled Electra for Mainnet at epoch 364032 (May 7, 2025, 10:05:11am UTC)
- Added `--p2p-static-peers-url` option to read static peers from a URL or file
- Added node epoch and computed slot to the sync committee duties failure message for more context about the failure condition.
- Updated third party libraries.

### Bug Fixes
### Bug Fixes
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.io.IOException;
import java.util.List;
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.api.response.v1.EventType;
import tech.pegasys.teku.api.response.EventType;
import tech.pegasys.teku.bls.BLSKeyPair;
import tech.pegasys.teku.ethereum.execution.types.Eth1Address;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,28 +75,22 @@ private static TekuNodeConfigBuilder createTekuNodeBuilderForMilestone(
.withInteropNumberOfValidators(64)
.withValidatorProposerDefaultFeeRecipient("0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73");

switch (specMilestone) {
// We do not need to consider PHASE0, ALTAIR or BELLATRIX as they are all pre-Merge
// milestones
case CAPELLA:
tekuNodeConfigBuilder.withCapellaEpoch(UInt64.ZERO);
break;
case DENEB:
tekuNodeConfigBuilder.withCapellaEpoch(UInt64.ZERO);
tekuNodeConfigBuilder.withDenebEpoch(UInt64.ZERO);
break;
case ELECTRA:
tekuNodeConfigBuilder.withCapellaEpoch(UInt64.ZERO);
tekuNodeConfigBuilder.withDenebEpoch(UInt64.ZERO);
tekuNodeConfigBuilder.withElectraEpoch(UInt64.ZERO);
break;
default:
// Test will reach this whenever a new milestone is added and isn't mapped on the switch.
// This is a way to force us to always remember to validate that a new milestone can start
// from a merged
// state.
fail("Milestone %s not used on merged genesis interop test", specMilestone);
if (specMilestone.isGreaterThanOrEqualTo(SpecMilestone.CAPELLA)) {
tekuNodeConfigBuilder.withCapellaEpoch(UInt64.ZERO);
}
if (specMilestone.isGreaterThanOrEqualTo(SpecMilestone.DENEB)) {
tekuNodeConfigBuilder.withDenebEpoch(UInt64.ZERO);
}
if (specMilestone.isGreaterThanOrEqualTo(SpecMilestone.ELECTRA)) {
tekuNodeConfigBuilder.withElectraEpoch(UInt64.ZERO);
}
if (specMilestone.isGreaterThanOrEqualTo(SpecMilestone.FULU)) {
tekuNodeConfigBuilder.withFuluEpoch(UInt64.ZERO);
}
if (specMilestone.isGreaterThan(SpecMilestone.FULU)) {
fail("Milestone %s not used on merged genesis interop test", specMilestone);
}

return tekuNodeConfigBuilder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.io.IOException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.api.response.v1.EventType;
import tech.pegasys.teku.api.response.EventType;
import tech.pegasys.teku.infrastructure.time.SystemTimeProvider;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.test.acceptance.dsl.AcceptanceTestBase;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
import tech.pegasys.teku.api.migrated.ValidatorLivenessAtEpoch;
import tech.pegasys.teku.api.response.v1.EventType;
import tech.pegasys.teku.api.response.EventType;
import tech.pegasys.teku.bls.BLS;
import tech.pegasys.teku.bls.BLSKeyPair;
import tech.pegasys.teku.bls.BLSSecretKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.utility.MountableFile;
import tech.pegasys.teku.api.response.v1.EventType;
import tech.pegasys.teku.api.response.EventType;

public abstract class TekuNode extends Node {
public static final int VALIDATOR_API_PORT = 9052;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,18 @@ public TekuNodeConfigBuilder withElectraEpoch(final UInt64 electraForkEpoch) {
return this;
}

public TekuNodeConfigBuilder withFuluEpoch(final UInt64 fuluForkEpoch) {
mustBe(NodeType.BEACON_NODE);
LOG.debug("Xnetwork-fulu-fork-epoch={}", fuluForkEpoch);
configMap.put("Xnetwork-fulu-fork-epoch", fuluForkEpoch.toString());
specConfigModifier =
specConfigModifier.andThen(
specConfigBuilder ->
specConfigBuilder.fuluBuilder(
fuluBuilder -> fuluBuilder.fuluForkEpoch(fuluForkEpoch)));
return this;
}

public TekuNodeConfigBuilder withTrustedSetupFromClasspath(final String trustedSetup)
throws Exception {
mustBe(NodeType.BEACON_NODE);
Expand Down Expand Up @@ -224,19 +236,6 @@ public TekuNodeConfigBuilder withTerminalBlockHash(
return this;
}

public TekuNodeConfigBuilder withFuluEpoch(final UInt64 fuluForkEpoch) {

mustBe(NodeType.BEACON_NODE);
LOG.debug("Xnetwork-fulu-fork-epoch={}", fuluForkEpoch);
configMap.put("Xnetwork-fulu-fork-epoch", fuluForkEpoch.toString());
specConfigModifier =
specConfigModifier.andThen(
specConfigBuilder ->
specConfigBuilder.fuluBuilder(
fuluBuilder -> fuluBuilder.fuluForkEpoch(fuluForkEpoch)));
return this;
}

public TekuNodeConfigBuilder withTotalTerminalDifficulty(final long totalTerminalDifficulty) {
return withTotalTerminalDifficulty(UInt256.valueOf(totalTerminalDifficulty));
}
Expand Down Expand Up @@ -560,6 +559,13 @@ public TekuNodeConfigBuilder withPeers(final TekuBeaconNode... nodes) {
return this;
}

public TekuNodeConfigBuilder withPeersUrl(final String peersUrl) {
mustBe(NodeType.BEACON_NODE);
LOG.debug("p2p-static-peers-url={}", peersUrl);
configMap.put("p2p-static-peers-url", peersUrl);
return this;
}

public TekuNodeConfigBuilder withExternalSignerUrl(final String externalSignerUrl) {
LOG.debug("validators-external-signer-url={}", externalSignerUrl);
configMap.put("validators-external-signer-url", externalSignerUrl);
Expand Down
1 change: 1 addition & 0 deletions beacon/validator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ dependencies {
testImplementation testFixtures(project(':infrastructure:logging'))
testImplementation testFixtures(project(':infrastructure:metrics'))
testImplementation testFixtures(project(':infrastructure:time'))
testImplementation testFixtures(project(':infrastructure:kzg'))

integrationTestImplementation testFixtures(project(':ethereum:spec'))
integrationTestImplementation testFixtures(project(':infrastructure:async'))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -505,8 +505,7 @@ public SafeFuture<Optional<Attestation>> createAggregate(
return SafeFuture.completedFuture(
attestationPool
.createAggregateFor(attestationHashTreeRoot, committeeIndex)
.filter(attestation -> attestation.getData().getSlot().equals(slot))
.map(ValidatableAttestation::getAttestation));
.filter(attestation -> attestation.getData().getSlot().equals(slot)));
}

@Override
Expand Down Expand Up @@ -802,15 +801,17 @@ private SafeFuture<Optional<BeaconState>> getStateForCommitteeDuties(
return SafeFuture.completedFuture(Optional.of(bestState));
}

final UInt64 lastQueryableEpoch =
final UInt64 maxQueryableEpoch =
syncCommitteeUtil.computeLastEpochOfNextSyncCommitteePeriod(
combinedChainDataClient.getCurrentEpoch());
if (lastQueryableEpoch.isLessThan(epoch)) {
if (maxQueryableEpoch.isLessThan(epoch)) {
final Optional<UInt64> networkCurrentSlot =
chainDataProvider.getNetworkCurrentSlot();
return SafeFuture.failedFuture(
new IllegalArgumentException(
"Cannot calculate sync committee duties for epoch "
+ epoch
+ " because it is not within the current or next sync committee periods"));
String.format(
"Cannot calculate sync committee duties for epoch %s because it is not within the current or next sync committee periods (node current epoch %s, computed current slot %s)",
epoch, combinedChainDataClient.getCurrentEpoch(), networkCurrentSlot)));
}

final UInt64 requiredEpoch;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import tech.pegasys.teku.infrastructure.ssz.SszList;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.kzg.KZG;
import tech.pegasys.teku.kzg.NoOpKZG;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.DataColumnSidecar;
Expand Down Expand Up @@ -339,7 +340,9 @@ void shouldCreateDataColumnSidecarsForBlockContents() {

assertThatThrownBy(
() ->
factory.createDataColumnSidecarsSelector(KZG.NOOP).apply(signedBlindedBeaconBlock))
factory
.createDataColumnSidecarsSelector(NoOpKZG.INSTANCE)
.apply(signedBlindedBeaconBlock))
.isInstanceOf(IllegalStateException.class)
.hasMessage(
"Commitments in the builder BlobsCellBundle don't match the commitments in the block");
Expand All @@ -362,7 +365,9 @@ void shouldFailCreatingBlobSidecarsIfBuilderBlobsBundleProofsIsNotConsistent() {

assertThatThrownBy(
() ->
factory.createDataColumnSidecarsSelector(KZG.NOOP).apply(signedBlindedBeaconBlock))
factory
.createDataColumnSidecarsSelector(NoOpKZG.INSTANCE)
.apply(signedBlindedBeaconBlock))
.isInstanceOf(IllegalStateException.class)
.hasMessage(
"The number of blobs in the builder BlobsCellBundle doesn't match the number of commitments in the block");
Expand All @@ -385,7 +390,9 @@ void shouldFailCreatingDataColumnSidecarsIfBuilderBlobsBundleBlobsIsNotConsisten

assertThatThrownBy(
() ->
factory.createDataColumnSidecarsSelector(KZG.NOOP).apply(signedBlindedBeaconBlock))
factory
.createDataColumnSidecarsSelector(NoOpKZG.INSTANCE)
.apply(signedBlindedBeaconBlock))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Expected 128 proofs but got 3");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
import tech.pegasys.teku.api.NetworkDataProvider;
import tech.pegasys.teku.api.NodeDataProvider;
import tech.pegasys.teku.api.migrated.ValidatorLivenessAtEpoch;
import tech.pegasys.teku.api.response.v1.beacon.ValidatorStatus;
import tech.pegasys.teku.api.response.ValidatorStatus;
import tech.pegasys.teku.beacon.sync.events.SyncState;
import tech.pegasys.teku.beacon.sync.events.SyncStateProvider;
import tech.pegasys.teku.bls.BLSPublicKey;
Expand Down Expand Up @@ -734,7 +734,7 @@ public void createAggregate_shouldReturnAggregateFromAttestationPool() {
final Optional<Attestation> aggregate = Optional.of(dataStructureUtil.randomAttestation());
when(attestationPool.createAggregateFor(
eq(attestationData.hashTreeRoot()), eq(Optional.empty())))
.thenReturn(aggregate.map(attestation -> ValidatableAttestation.from(spec, attestation)));
.thenReturn(aggregate);

assertThat(
validatorApiHandler.createAggregate(
Expand Down
9 changes: 6 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ buildscript {
}

plugins {
id 'com.diffplug.spotless' version '7.0.2'
id 'com.diffplug.spotless' version '7.0.3'
id 'com.github.ben-manes.versions' version '0.52.0'
id 'com.github.jk1.dependency-license-report' version '2.9'
id 'io.spring.dependency-management' version '1.1.7'
id 'net.ltgt.errorprone' version '4.1.0' apply false
id 'net.ltgt.errorprone' version '4.2.0' apply false
id 'de.undercouch.download' version '5.6.0'
id 'org.ajoberstar.grgit' version '5.3.0'
}
Expand Down Expand Up @@ -249,6 +249,9 @@ allprojects {
check('BannedMethod', net.ltgt.gradle.errorprone.CheckSeverity.OFF)
check('ExperimentalCliOptionMustBeCorrectlyDisplayed', net.ltgt.gradle.errorprone.CheckSeverity.OFF)

// ignore PatternMatchingInstanceof for now
check("PatternMatchingInstanceof", net.ltgt.gradle.errorprone.CheckSeverity.OFF)

// These are experimental checks that we want enabled
check('ClassName', net.ltgt.gradle.errorprone.CheckSeverity.WARN)
check('DeduplicateConstants', net.ltgt.gradle.errorprone.CheckSeverity.WARN)
Expand Down Expand Up @@ -324,7 +327,7 @@ allprojects {
}

def nightly = System.getenv("NIGHTLY") != null
def refTestVersion = nightly ? "nightly" : "v1.5.0-beta.4"
def refTestVersion = nightly ? "nightly" : "v1.5.0"
def blsRefTestVersion = 'v0.1.2'
def slashingProtectionInterchangeRefTestVersion = 'v5.3.0'
def refTestBaseUrl = 'https://github.com/ethereum/consensus-spec-tests/releases/download'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import static tech.pegasys.teku.infrastructure.restapi.SwaggerUIBuilder.SWAGGER_INITIALIZER_JS;

import java.io.IOException;
import java.net.URL;
import java.net.URI;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -79,18 +79,18 @@ private static Set<String> findAssets(final String url) throws IOException {
Document doc =
Jsoup.connect(url).data("query", "Java").userAgent("Mozilla").timeout(3000).get();

final URL baseUrl = new URL(url);
final URI baseUrl = URI.create(url);

// Resources
Elements resources = doc.select("link[href]");
for (Element element : resources) {
links.add(new URL(baseUrl, element.attr("href")).getPath());
links.add(baseUrl.resolve(element.attr("href")).getPath());
}

// Scripts
Elements scripts = doc.select("script");
for (Element element : scripts) {
links.add(new URL(baseUrl, element.attr("src")).getPath());
links.add(baseUrl.resolve(element.attr("src")).getPath());
}

return links;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.api.schema.Eth1Data;
import tech.pegasys.teku.beaconrestapi.AbstractDataBackedRestAPIIntegrationTest;
import tech.pegasys.teku.beaconrestapi.handlers.tekuv1.beacon.GetEth1DataCache;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.datastructures.blocks.Eth1Data;
import tech.pegasys.teku.spec.util.DataStructureUtil;

public class GetEth1DataCacheIntegrationTest extends AbstractDataBackedRestAPIIntegrationTest {
Expand All @@ -45,15 +45,11 @@ public void setup() {

@Test
public void shouldReturnAllEth1BlocksFromCache() throws IOException {
List<tech.pegasys.teku.spec.datastructures.blocks.Eth1Data> eth1DataCacheList =
new ArrayList<>();
final List<Eth1Data> eth1DataCacheList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
eth1DataCacheList.add(dataStructureUtil.randomEth1Data());
}
List<Eth1Data> eth1DataCacheBlocks = new ArrayList<>();
eth1DataCacheList.stream()
.map(Eth1Data::new)
.forEach(eth1Block -> eth1DataCacheBlocks.add(eth1Block));
final List<Eth1Data> eth1DataCacheBlocks = new ArrayList<>(eth1DataCacheList);
when(eth1DataProvider.getEth1CachedBlocks()).thenReturn(eth1DataCacheList);
final Response response = get();
assertThat(response.code()).isEqualTo(SC_OK);
Expand All @@ -63,11 +59,11 @@ public void shouldReturnAllEth1BlocksFromCache() throws IOException {
final JsonNode block = data.get(i);
final Eth1Data eth1Data = eth1DataCacheBlocks.get(i);
assertThat(Bytes32.fromHexString(block.get("deposit_root").asText()))
.isEqualTo(eth1Data.deposit_root);
.isEqualTo(eth1Data.getDepositRoot());
assertThat(UInt64.valueOf(block.get("deposit_count").asText()))
.isEqualTo(eth1Data.deposit_count);
.isEqualTo(eth1Data.getDepositCount());
assertThat(Bytes32.fromHexString(block.get("block_hash").asText()))
.isEqualTo(eth1Data.block_hash);
.isEqualTo(eth1Data.getBlockHash());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import okhttp3.Response;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.api.schema.Version;
import tech.pegasys.teku.beaconrestapi.AbstractDataBackedRestAPIIntegrationTest;
import tech.pegasys.teku.beaconrestapi.handlers.v1.beacon.GetBlindedBlock;
import tech.pegasys.teku.ethereum.json.types.SharedApiTypes;
Expand All @@ -46,7 +45,8 @@ public void shouldGetBlindedPhase0Block() throws IOException {
assertThat(result.isBlinded()).isFalse();
assertThat(result).isEqualTo(created.get(0).getBlock());
assertThat(result.hashTreeRoot()).isEqualTo(created.get(0).getBlock().hashTreeRoot());
assertThat(response.header(HEADER_CONSENSUS_VERSION)).isEqualTo(Version.phase0.name());
assertThat(response.header(HEADER_CONSENSUS_VERSION))
.isEqualTo(SpecMilestone.PHASE0.lowerCaseName());
}

@Test
Expand All @@ -59,7 +59,8 @@ public void shouldGetBlindedBellatrixBlock() throws IOException {

assertThat(result.isBlinded()).isTrue();
assertThat(result.hashTreeRoot()).isEqualTo(created.get(0).getBlock().hashTreeRoot());
assertThat(response.header(HEADER_CONSENSUS_VERSION)).isEqualTo(Version.bellatrix.name());
assertThat(response.header(HEADER_CONSENSUS_VERSION))
.isEqualTo(SpecMilestone.BELLATRIX.lowerCaseName());
}

@Test
Expand All @@ -75,7 +76,8 @@ public void shouldGetBellatrixBlockAsSsz() throws IOException {
.sszDeserialize(Bytes.of(response.body().bytes()));
assertThat(result.isBlinded()).isTrue();
assertThat(result.hashTreeRoot()).isEqualTo(created.get(0).getBlock().hashTreeRoot());
assertThat(response.header(HEADER_CONSENSUS_VERSION)).isEqualTo(Version.bellatrix.name());
assertThat(response.header(HEADER_CONSENSUS_VERSION))
.isEqualTo(SpecMilestone.BELLATRIX.lowerCaseName());
}

public Response get(final String blockIdString, final String contentType) throws IOException {
Expand Down
Loading