Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate that blockperiodseconds is set to a positive integer #3186

Merged
merged 36 commits into from
Jan 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a1599f1
Created function to validate blockperiodseconds as positive int
georgep9 Dec 16, 2021
d1a642e
unit tests for nonpositive or demical BlockPeriodSeconds
georgep9 Dec 17, 2021
07d6bb7
updated getBlockPeriodSeconds() to throw on nonpositive or demical va…
georgep9 Dec 17, 2021
e0f08fc
updated getBlockPeriodSeconds() to handle nonexistent blockperiodseco…
georgep9 Dec 17, 2021
fabc34b
Merge branch 'main' of github.com:hyperledger/besu into validate_bloc…
georgep9 Dec 17, 2021
aaa0e77
spotlessApply
georgep9 Dec 17, 2021
5b3e5fc
Merge branch 'main' of github.com:hyperledger/besu into validate_bloc…
georgep9 Dec 18, 2021
05644aa
removed validate function from operator subcommand
georgep9 Dec 20, 2021
7f057b7
refactored getBlockPeriodSeconds to use preexisting util function
georgep9 Dec 20, 2021
65cfb5b
Merge branch 'main' of github.com:hyperledger/besu into validate_bloc…
georgep9 Dec 20, 2021
69ed209
spotlessApply
georgep9 Dec 20, 2021
8516f1b
minor changes to error message
georgep9 Dec 20, 2021
4fa187d
Merge branch 'main' of github.com:hyperledger/besu into validate_bloc…
georgep9 Dec 21, 2021
b8d4002
re-added NonPositive blockperiod test
georgep9 Dec 21, 2021
129f006
added same validation + unit test for CliqueConfigOptions
georgep9 Dec 21, 2021
176392c
reverted GenerateBlockchainConfig changes
georgep9 Dec 21, 2021
324237a
removed duplicate line from GenerateBlockchainConfig
georgep9 Dec 21, 2021
f18393b
refactored validation logic into a generic getPostiveNumber function …
georgep9 Dec 21, 2021
101b3c6
renamed to getPositiveInt
georgep9 Dec 21, 2021
3ff9259
unit tests for getPostiveInt
georgep9 Dec 21, 2021
aeaee24
apply validation in IbftLegacyConfigOptions
georgep9 Dec 21, 2021
bcaff86
Merge branch 'main' of github.com:hyperledger/besu into validate_bloc…
georgep9 Dec 21, 2021
65e3e43
reformatted getPositiveInt error message
georgep9 Dec 21, 2021
94812b7
added unit tests for PositiveNumber
georgep9 Dec 21, 2021
ae62318
removed redundant tests from ConfigOptions classes
georgep9 Dec 21, 2021
75296f0
Merge branch 'main' of github.com:hyperledger/besu into validate_bloc…
georgep9 Dec 21, 2021
b1dba93
prepended copyright header to PositiveNumberTest
georgep9 Dec 22, 2021
20bb802
minor changes as per review
georgep9 Dec 22, 2021
f4481f2
apply changes for BftFork
georgep9 Dec 22, 2021
b71dffe
minor change
georgep9 Dec 22, 2021
2db9939
minor fix
georgep9 Dec 22, 2021
57b33ba
reverted copyright header changes
georgep9 Dec 22, 2021
8a307bb
Refactored getPositiveInt to handle optional default value + unit tes…
georgep9 Dec 22, 2021
b3f207c
Merge branch 'main' of github.com:hyperledger/besu into validate_bloc…
georgep9 Jan 3, 2022
cd3cd85
Merge branch 'main' of github.com:hyperledger/besu into validate_bloc…
georgep9 Jan 5, 2022
d0ca8fc
Updated changelog
georgep9 Jan 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
# Changelog

## Next RC

### Additions and Improvements
- Genesis file parameter `blockperiodseconds` is validated as a positive integer on startup to prevent unexpected runtime behaviour [#3186](https://github.com/hyperledger/besu/pull/3186)

## 22.1.0-RC2

### 22.1.0-RC2 Breaking Changes
- Removed deprecated hash variable `protected volatile Hash hash;` which was used for private transactions [#3110](https://github.com/hyperledger/besu/pull/3110)

### Additions and Improvements
- Re-order external services (e.g JsonRpcHttpService) to start before blocks start processing [#3118](https://github.com/hyperledger/besu/pull/3118)
- Stream JSON RPC responses to avoid creating big JSON strings in memory [#3076] (https://github.com/hyperledger/besu/pull/3076)
- Stream JSON RPC responses to avoid creating big JSON strings in memory [#3076](https://github.com/hyperledger/besu/pull/3076)

### Bug Fixes
- Make 'to' field optional in eth_call method according to the spec [#3177] (https://github.com/hyperledger/besu/pull/3177)
- Make 'to' field optional in eth_call method according to the spec [#3177](https://github.com/hyperledger/besu/pull/3177)
- Update to log4j 2.17.1. Resolves potential vulnerability only exploitable when using custom log4j configurations that are writable by untrusted users.

## 21.10.6
Expand Down
1 change: 1 addition & 0 deletions config/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jar {

dependencies {
implementation project(':datatypes')
implementation project(':util')

implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'com.google.guava:guava'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public long getForkBlock() {
}

public OptionalInt getBlockPeriodSeconds() {
return JsonUtil.getInt(forkConfigRoot, BLOCK_PERIOD_SECONDS_KEY);
return JsonUtil.getPositiveInt(forkConfigRoot, BLOCK_PERIOD_SECONDS_KEY);
}

public Optional<BigInteger> getBlockRewardWei() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public long getEpochLength() {
}

public int getBlockPeriodSeconds() {
return JsonUtil.getInt(cliqueConfigRoot, "blockperiodseconds", DEFAULT_BLOCK_PERIOD_SECONDS);
return JsonUtil.getPositiveInt(
cliqueConfigRoot, "blockperiodseconds", DEFAULT_BLOCK_PERIOD_SECONDS);
}

Map<String, Object> asMap() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public long getEpochLength() {
}

public int getBlockPeriodSeconds() {
return JsonUtil.getInt(ibftConfigRoot, "blockperiodseconds", DEFAULT_BLOCK_PERIOD_SECONDS);
return JsonUtil.getPositiveInt(
ibftConfigRoot, "blockperiodseconds", DEFAULT_BLOCK_PERIOD_SECONDS);
}

public int getRequestTimeoutSeconds() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public long getEpochLength() {

@Override
public int getBlockPeriodSeconds() {
return JsonUtil.getInt(bftConfigRoot, "blockperiodseconds", DEFAULT_BLOCK_PERIOD_SECONDS);
return JsonUtil.getPositiveInt(
bftConfigRoot, "blockperiodseconds", DEFAULT_BLOCK_PERIOD_SECONDS);
}

@Override
Expand Down
23 changes: 23 additions & 0 deletions config/src/main/java/org/hyperledger/besu/config/JsonUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.config;

import org.hyperledger.besu.util.number.PositiveNumber;

import java.io.IOException;
import java.util.Locale;
import java.util.Map;
Expand Down Expand Up @@ -141,6 +143,27 @@ public static int getInt(final ObjectNode node, final String key, final int defa
return getInt(node, key).orElse(defaultValue);
}

public static OptionalInt getPositiveInt(final ObjectNode node, final String key) {
return getValueAsString(node, key)
.map(v -> OptionalInt.of(parsePositiveInt(key, v)))
.orElse(OptionalInt.empty());
}

public static int getPositiveInt(
final ObjectNode node, final String key, final int defaultValue) {
final String value = getValueAsString(node, key, String.valueOf(defaultValue));
return parsePositiveInt(key, value);
}

private static int parsePositiveInt(final String key, final String value) {
try {
return PositiveNumber.fromString(value).getValue();
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
"Invalid property value, " + key + " should be a positive integer: " + value);
}
}

public static OptionalLong getLong(final ObjectNode json, final String key) {
return getValue(json, key)
.filter(jsonNode -> validateType(jsonNode, JsonNodeType.NUMBER))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.util.Map;

Expand All @@ -30,7 +31,7 @@ public class CliqueConfigOptionsTest {

@Test
public void shouldGetEpochLengthFromConfig() {
final CliqueConfigOptions config = fromConfigOptions(singletonMap("EpochLength", 10_000));
final CliqueConfigOptions config = fromConfigOptions(singletonMap("epochlength", 10_000));
assertThat(config.getEpochLength()).isEqualTo(10_000);
}

Expand All @@ -48,7 +49,7 @@ public void shouldGetDefaultEpochLengthFromDefaultConfig() {

@Test
public void shouldGetBlockPeriodFromConfig() {
final CliqueConfigOptions config = fromConfigOptions(singletonMap("BlockPeriodSeconds", 5));
final CliqueConfigOptions config = fromConfigOptions(singletonMap("blockperiodseconds", 5));
assertThat(config.getBlockPeriodSeconds()).isEqualTo(5);
}

Expand All @@ -64,6 +65,13 @@ public void shouldGetDefaultBlockPeriodFromDefaultConfig() {
.isEqualTo(EXPECTED_DEFAULT_BLOCK_PERIOD);
}

@Test
public void shouldThrowOnNonPositiveBlockPeriod() {
final CliqueConfigOptions config = fromConfigOptions(singletonMap("blockperiodseconds", -1));
assertThatThrownBy(() -> config.getBlockPeriodSeconds())
.isInstanceOf(IllegalArgumentException.class);
}

private CliqueConfigOptions fromConfigOptions(final Map<String, Object> cliqueConfigOptions) {
final ObjectNode rootNode = JsonUtil.createEmptyObjectNode();
final ObjectNode configNode = JsonUtil.createEmptyObjectNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.util.Map;

Expand All @@ -36,7 +37,7 @@ public class JsonBftConfigOptionsTest {

@Test
public void shouldGetEpochLengthFromConfig() {
final BftConfigOptions config = fromConfigOptions(singletonMap("EpochLength", 10_000));
final BftConfigOptions config = fromConfigOptions(singletonMap("epochlength", 10_000));
assertThat(config.getEpochLength()).isEqualTo(10_000);
}

Expand All @@ -54,7 +55,7 @@ public void shouldGetDefaultEpochLengthFromDefaultConfig() {

@Test
public void shouldGetBlockPeriodFromConfig() {
final BftConfigOptions config = fromConfigOptions(singletonMap("BlockPeriodSeconds", 5));
final BftConfigOptions config = fromConfigOptions(singletonMap("blockperiodseconds", 5));
assertThat(config.getBlockPeriodSeconds()).isEqualTo(5);
}

Expand All @@ -70,9 +71,16 @@ public void shouldGetDefaultBlockPeriodFromDefaultConfig() {
.isEqualTo(EXPECTED_DEFAULT_BLOCK_PERIOD);
}

@Test
georgep9 marked this conversation as resolved.
Show resolved Hide resolved
public void shouldThrowOnNonPositiveBlockPeriod() {
final BftConfigOptions config = fromConfigOptions(singletonMap("blockperiodseconds", -1));
assertThatThrownBy(() -> config.getBlockPeriodSeconds())
.isInstanceOf(IllegalArgumentException.class);
}

@Test
public void shouldGetRequestTimeoutFromConfig() {
final BftConfigOptions config = fromConfigOptions(singletonMap("RequestTimeoutSeconds", 5));
final BftConfigOptions config = fromConfigOptions(singletonMap("requesttimeoutseconds", 5));
assertThat(config.getRequestTimeoutSeconds()).isEqualTo(5);
}

Expand All @@ -90,7 +98,7 @@ public void shouldGetDefaultRequestTimeoutFromDefaultConfig() {

@Test
public void shouldGetGossipedHistoryLimitFromConfig() {
final BftConfigOptions config = fromConfigOptions(singletonMap("GossipedHistoryLimit", 100));
final BftConfigOptions config = fromConfigOptions(singletonMap("gossipedhistorylimit", 100));
assertThat(config.getGossipedHistoryLimit()).isEqualTo(100);
}

Expand All @@ -108,7 +116,7 @@ public void shouldGetDefaultGossipedHistoryLimitFromDefaultConfig() {

@Test
public void shouldGetMessageQueueLimitFromConfig() {
final BftConfigOptions config = fromConfigOptions(singletonMap("MessageQueueLimit", 100));
final BftConfigOptions config = fromConfigOptions(singletonMap("messagequeuelimit", 100));
assertThat(config.getMessageQueueLimit()).isEqualTo(100);
}

Expand All @@ -126,7 +134,7 @@ public void shouldGetDefaultMessageQueueLimitFromDefaultConfig() {

@Test
public void shouldGetDuplicateMessageLimitFromConfig() {
final BftConfigOptions config = fromConfigOptions(singletonMap("DuplicateMessageLimit", 50));
final BftConfigOptions config = fromConfigOptions(singletonMap("duplicatemessagelimit", 50));
assertThat(config.getDuplicateMessageLimit()).isEqualTo(50);
}

Expand All @@ -145,7 +153,7 @@ public void shouldGetDefaultDuplicateMessageLimitFromDefaultConfig() {

@Test
public void shouldGetFutureMessagesLimitFromConfig() {
final BftConfigOptions config = fromConfigOptions(singletonMap("FutureMessagesLimit", 50));
final BftConfigOptions config = fromConfigOptions(singletonMap("futuremessageslimit", 50));
assertThat(config.getFutureMessagesLimit()).isEqualTo(50);
}

Expand All @@ -164,7 +172,7 @@ public void shouldGetDefaultFutureMessagesLimitsFromDefaultConfig() {
@Test
public void shouldGetFutureMessagesMaxDistanceFromConfig() {
final BftConfigOptions config =
fromConfigOptions(singletonMap("FutureMessagesMaxDistance", 50));
fromConfigOptions(singletonMap("futuremessagesmaxdistance", 50));
assertThat(config.getFutureMessagesMaxDistance()).isEqualTo(50);
}

Expand Down
95 changes: 95 additions & 0 deletions config/src/test/java/org/hyperledger/besu/config/JsonUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,101 @@ public void getBoolean_wrongType_withDefault() {
.hasMessageContaining("Expected boolean value but got number");
}

@Test
public void getPositiveInt_validValue() {
final ObjectNode node = mapper.createObjectNode();
final int validValue = 2;
node.put("test", validValue);
final OptionalInt result = JsonUtil.getPositiveInt(node, "test");
assertThat(result).hasValue(validValue);
}

@Test
public void getPositiveInt_nonExistentKey() {
final ObjectNode node = mapper.createObjectNode();
final OptionalInt result = JsonUtil.getPositiveInt(node, "test");
assertThat(result).isEmpty();
}

@Test
public void getPositiveInt_decimalValue() {
final ObjectNode node = mapper.createObjectNode();
final float decimalValue = Float.MAX_VALUE;
node.put("test", decimalValue);
assertThatThrownBy(() -> JsonUtil.getPositiveInt(node, "test"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Invalid property value, test should be a positive integer: " + decimalValue);
}

@Test
public void getPositiveInt_nonPositiveValue() {
final ObjectNode node = mapper.createObjectNode();
final int nonPositiveValue = 0;
node.put("test", nonPositiveValue);
assertThatThrownBy(() -> JsonUtil.getPositiveInt(node, "test"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(
"Invalid property value, test should be a positive integer: " + nonPositiveValue);
}

@Test
public void getPositiveInt_negativeValue() {
final ObjectNode node = mapper.createObjectNode();
final int negativeValue = Integer.MIN_VALUE;
node.put("test", negativeValue);
assertThatThrownBy(() -> JsonUtil.getPositiveInt(node, "test"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Invalid property value, test should be a positive integer: " + negativeValue);
}

@Test
public void getPositiveInt_validValue_withDefault() {
final ObjectNode node = mapper.createObjectNode();
final int validValue = 2;
node.put("test", validValue);
final int result = JsonUtil.getPositiveInt(node, "test", 1);
assertThat(result).isEqualTo(validValue);
}

@Test
public void getPositiveInt_nonExistentKey_withDefault() {
final ObjectNode node = mapper.createObjectNode();
final int defaultValue = 1;
final int result = JsonUtil.getPositiveInt(node, "test", defaultValue);
assertThat(result).isEqualTo(defaultValue);
}

@Test
public void getPositiveInt_decimalValue_withDefault() {
final ObjectNode node = mapper.createObjectNode();
final float decimalValue = Float.MAX_VALUE;
node.put("test", decimalValue);
assertThatThrownBy(() -> JsonUtil.getPositiveInt(node, "test", 1))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Invalid property value, test should be a positive integer: " + decimalValue);
}

@Test
public void getPositiveInt_nonPositiveValue_withDefault() {
final ObjectNode node = mapper.createObjectNode();
final int nonPositiveValue = 0;
node.put("test", nonPositiveValue);
assertThatThrownBy(() -> JsonUtil.getPositiveInt(node, "test", 1))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(
"Invalid property value, test should be a positive integer: " + nonPositiveValue);
}

@Test
public void getPositiveInt_negativeValue_withDefault() {
final ObjectNode node = mapper.createObjectNode();
final int negativeValue = Integer.MIN_VALUE;
node.put("test", negativeValue);
assertThatThrownBy(() -> JsonUtil.getPositiveInt(node, "test", 1))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Invalid property value, test should be a positive integer: " + negativeValue);
}

@Test
public void objectNodeFromMap() {
final Map<String, Object> map = new TreeMap<>();
Expand Down
Loading