Skip to content

Commit e353e04

Browse files
authored
Merge branch 'main' into feat/issue-7273/parse-geth-genesis
2 parents 087a91c + 3997ffb commit e353e04

File tree

36 files changed

+868
-431
lines changed

36 files changed

+868
-431
lines changed

.github/workflows/develop-pr.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,6 @@ jobs:
7373
uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1
7474
with:
7575
cache-disabled: true
76-
- name: install goss
77-
run: |
78-
mkdir -p docker/reports
79-
curl -L https://github.com/aelsabbahy/goss/releases/download/v0.4.4/goss-${{ steps.prep.outputs.PLATFORM_PAIR }} -o ./docker/tests/goss-${{ steps.prep.outputs.PLATFORM_PAIR }}
8076
- name: build and test docker
8177
uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1
8278
env:

.github/workflows/develop.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,6 @@ jobs:
7272
uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1
7373
with:
7474
cache-disabled: true
75-
- name: install goss
76-
run: |
77-
mkdir -p docker/reports
78-
curl -L https://github.com/aelsabbahy/goss/releases/download/v0.4.4/goss-${{ steps.prep.outputs.PLATFORM_PAIR }} -o ./docker/tests/goss-${{ steps.prep.outputs.PLATFORM_PAIR }}
7975
- name: login to ${{ env.registry }}
8076
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
8177
with:

.github/workflows/draft-release.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,6 @@ jobs:
226226
with:
227227
cache-disabled: true
228228

229-
- name: install goss
230-
run: |
231-
mkdir -p docker/reports
232-
curl -L https://github.com/aelsabbahy/goss/releases/download/v0.4.4/goss-${{ steps.prep.outputs.PLATFORM_PAIR }} -o ./docker/tests/goss-${{ steps.prep.outputs.PLATFORM_PAIR }}
233-
234229
- name: login to ${{ env.registry }}
235230
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
236231
with:

app/src/main/java/org/hyperledger/besu/cli/BesuCommand.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -777,16 +777,6 @@ protected BesuCommand(
777777
this.transactionValidatorServiceImpl = transactionValidatorServiceImpl;
778778
}
779779

780-
/**
781-
* Parse Besu command line arguments. Visible for testing.
782-
*
783-
* @param resultHandler execution strategy. See PicoCLI. Typical argument is RunLast.
784-
* @param parameterExceptionHandler Exception handler for handling parameters
785-
* @param executionExceptionHandler Exception handler for business logic
786-
* @param in Standard input stream
787-
* @param args arguments to Besu command
788-
* @return success or failure exit code.
789-
*/
790780
/**
791781
* Parses command line arguments and configures the application accordingly.
792782
*
@@ -798,6 +788,7 @@ protected BesuCommand(
798788
* @param args The command line arguments.
799789
* @return The execution result status code.
800790
*/
791+
@VisibleForTesting
801792
public int parse(
802793
final IExecutionStrategy resultHandler,
803794
final BesuParameterExceptionHandler parameterExceptionHandler,

app/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@
9999
import java.io.PrintStream;
100100
import java.nio.file.Files;
101101
import java.nio.file.Path;
102+
import java.nio.file.Paths;
102103
import java.util.ArrayList;
104+
import java.util.Arrays;
103105
import java.util.Collection;
104106
import java.util.HashMap;
105107
import java.util.List;
@@ -110,6 +112,7 @@
110112
import java.util.function.BiFunction;
111113
import java.util.function.Function;
112114
import java.util.function.Supplier;
115+
import javax.annotation.Nonnull;
113116

114117
import io.opentelemetry.api.GlobalOpenTelemetry;
115118
import io.vertx.core.Vertx;
@@ -455,26 +458,65 @@ protected TestBesuCommand parseCommand(
455458
final TestBesuCommand besuCommand = getTestBesuCommand(testType);
456459
besuCommands.add(besuCommand);
457460

458-
final File defaultKeyFile =
459-
KeyPairUtil.getDefaultKeyFile(DefaultCommandValues.getDefaultBesuDataPath(besuCommand));
461+
besuCommand.setBesuConfiguration(commonPluginConfiguration);
462+
463+
final List<String> argsList = constructArgsWithTmpDataPathIfNotSpecified(args);
464+
465+
// Determine the data directory that will be used and write the key file there
466+
final Path dataDir = determineDataDir(argsList);
467+
final File defaultKeyFile = KeyPairUtil.getDefaultKeyFile(dataDir);
460468
try {
469+
// Ensure parent directory exists
470+
defaultKeyFile.getParentFile().mkdirs();
461471
Files.writeString(defaultKeyFile.toPath(), keyPair.getPrivateKey().toString());
462472
} catch (final IOException e) {
463473
throw new RuntimeException(e);
464474
}
465-
besuCommand.setBesuConfiguration(commonPluginConfiguration);
466475

467-
// parse using Ansi.OFF to be able to assert on non formatted output results
476+
// parse using Ansi.OFF to be able to assert on non-formatted output results
468477
besuCommand.parse(
469478
new RunLast(),
470479
besuCommand.parameterExceptionHandler(),
471480
besuCommand.executionExceptionHandler(),
472481
in,
473482
mockBesuComponent,
474-
args);
483+
argsList.toArray(new String[0]));
475484
return besuCommand;
476485
}
477486

487+
@Nonnull
488+
private static Path determineDataDir(final List<String> argsList) {
489+
// Look for --data-path in the arguments
490+
for (int i = 0; i < argsList.size() - 1; i++) {
491+
if ("--data-path".equals(argsList.get(i))) {
492+
return Paths.get(argsList.get(i + 1));
493+
}
494+
}
495+
// If no explicit data-path, use default
496+
return DefaultCommandValues.getDefaultBesuDataPath(null);
497+
}
498+
499+
@Nonnull
500+
private static List<String> constructArgsWithTmpDataPathIfNotSpecified(final String[] args) {
501+
final List<String> argsList = new ArrayList<>(Arrays.asList(args));
502+
503+
boolean hasDataPath = argsList.stream().anyMatch(arg -> arg.contains("data-path"));
504+
boolean hasConfigFile = argsList.stream().anyMatch(arg -> arg.contains("config-file"));
505+
506+
// if data-path is not set, set to a tmp dir
507+
if (!hasDataPath && !hasConfigFile) {
508+
try {
509+
final Path tmpDir = Files.createTempDirectory("besu-test-");
510+
tmpDir.toFile().deleteOnExit();
511+
argsList.add(0, "--data-path");
512+
argsList.add(1, tmpDir.toString());
513+
} catch (IOException e) {
514+
throw new RuntimeException("Failed to create temporary directory", e);
515+
}
516+
}
517+
return argsList;
518+
}
519+
478520
private TestBesuCommand getTestBesuCommand(final TestType testType) {
479521
switch (testType) {
480522
case REQUIRED_OPTION:

build.gradle

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ plugins {
3131
id 'jacoco'
3232
id 'jacoco-report-aggregation'
3333
id 'org.sonarqube' version '6.2.0.5505'
34+
id 'de.undercouch.download' version '5.6.0'
3435
}
3536

3637
sonarqube {
@@ -880,24 +881,70 @@ task distDocker {
880881
}
881882
}
882883

883-
task testDocker {
884-
dependsOn distDocker
885-
def dockerReportsDir = "docker/reports/"
884+
tasks.register("downloadGossBinaries") {
885+
def gossVersion = 'v0.4.9'
886+
def baseUrl = "https://github.com/goss-org/goss/releases/download/${gossVersion}"
887+
def testDir = "${projectDir}/docker/tests"
886888

887-
doFirst {
888-
new File(dockerReportsDir).mkdir()
889-
}
889+
// Detect current architecture
890+
def osArch = System.getProperty("os.arch").toLowerCase()
891+
def currentArch = (osArch.contains("aarch64") || osArch.contains("arm64")) ? "arm64" : "amd64"
890892

891893
doLast {
892-
exec {
893-
def image = project.hasProperty('release.releaseVersion') ? "${dockerImageName}:" + project.property('release.releaseVersion') : "${dockerImageName}:${project.version}"
894-
workingDir "${projectDir}/docker"
895-
executable shell
896-
args "-c", "./test.sh ${image}"
894+
// Download goss binary for current architecture
895+
def binaryFile = new File(testDir, "goss-linux-${currentArch}")
896+
897+
// Download binary if it doesn't exist
898+
if (!binaryFile.exists()) {
899+
println "Downloading goss-linux-${currentArch}..."
900+
download.run {
901+
src "${baseUrl}/goss-linux-${currentArch}"
902+
dest binaryFile
903+
overwrite false
904+
onlyIfModified true
905+
}
906+
907+
binaryFile.setExecutable(true)
908+
println "Successfully downloaded goss-linux-${currentArch}"
909+
} else {
910+
println "goss-linux-${currentArch} already exists"
911+
}
912+
913+
// Download dgoss if it doesn't exist
914+
def dgossFile = new File(testDir, 'dgoss')
915+
if (!dgossFile.exists()) {
916+
println "Downloading dgoss..."
917+
download.run {
918+
src "${baseUrl}/dgoss"
919+
dest dgossFile
920+
overwrite false
921+
onlyIfModified true
922+
}
923+
924+
dgossFile.setExecutable(true)
925+
println "Successfully downloaded dgoss"
926+
} else {
927+
println "dgoss already exists"
897928
}
898929
}
899930
}
900931

932+
tasks.register("testDocker", Exec) {
933+
dependsOn("distDocker", "downloadGossBinaries")
934+
935+
doFirst {
936+
new File("docker/reports/").mkdir()
937+
}
938+
939+
def image = project.hasProperty('release.releaseVersion')
940+
? "${dockerImageName}:" + project.property('release.releaseVersion')
941+
: "${dockerImageName}:${project.version}"
942+
943+
workingDir "${projectDir}/docker"
944+
executable shell
945+
args "-c", "./test.sh ${image}"
946+
}
947+
901948
task dockerUpload {
902949
dependsOn distDocker
903950
def architecture = System.getenv('architecture')

consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/payload/SignedData.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
package org.hyperledger.besu.consensus.common.bft.payload;
1616

1717
import org.hyperledger.besu.crypto.SECPSignature;
18+
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
1819
import org.hyperledger.besu.datatypes.Address;
1920
import org.hyperledger.besu.datatypes.Hash;
2021
import org.hyperledger.besu.ethereum.core.Util;
2122
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
2223
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
2324

25+
import java.math.BigInteger;
2426
import java.util.Objects;
2527
import java.util.StringJoiner;
2628

@@ -33,6 +35,9 @@
3335
*/
3436
public class SignedData<M extends Payload> implements Authored {
3537

38+
private static final BigInteger HALF_CURVE_ORDER =
39+
SignatureAlgorithmFactory.getInstance().getHalfCurveOrder();
40+
3641
private final Address sender;
3742
private final SECPSignature signature;
3843
private final M unsignedPayload;
@@ -44,6 +49,7 @@ public class SignedData<M extends Payload> implements Authored {
4449
* @param payload the payload
4550
* @param signature the signature
4651
* @return the signed data
52+
* @throws IllegalArgumentException if the signature is invalid
4753
*/
4854
public static <T extends Payload> SignedData<T> create(
4955
final T payload, final SECPSignature signature) {
@@ -52,6 +58,9 @@ public static <T extends Payload> SignedData<T> create(
5258
}
5359

5460
private SignedData(final M unsignedPayload, final Address sender, final SECPSignature signature) {
61+
if (!(signature.getS().compareTo(HALF_CURVE_ORDER) <= 0)) {
62+
throw new IllegalArgumentException("Signature is invalid");
63+
}
5564
this.unsignedPayload = unsignedPayload;
5665
this.sender = sender;
5766
this.signature = signature;

consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/RoundState.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
import org.hyperledger.besu.consensus.ibft.messagewrappers.Proposal;
2222
import org.hyperledger.besu.consensus.ibft.validation.MessageValidator;
2323
import org.hyperledger.besu.crypto.SECPSignature;
24+
import org.hyperledger.besu.datatypes.Address;
2425
import org.hyperledger.besu.ethereum.core.Block;
2526

2627
import java.util.Collection;
28+
import java.util.LinkedHashMap;
29+
import java.util.Map;
2730
import java.util.Optional;
28-
import java.util.Set;
2931
import java.util.stream.Collectors;
3032

31-
import com.google.common.collect.Sets;
3233
import org.slf4j.Logger;
3334
import org.slf4j.LoggerFactory;
3435

@@ -45,8 +46,8 @@ public class RoundState {
4546

4647
// Must track the actual Prepare message, not just the sender, as these may need to be reused
4748
// to send out in a PrepareCertificate.
48-
private final Set<Prepare> prepareMessages = Sets.newLinkedHashSet();
49-
private final Set<Commit> commitMessages = Sets.newLinkedHashSet();
49+
private final Map<Address, Prepare> prepareMessages = new LinkedHashMap<>();
50+
private final Map<Address, Commit> commitMessages = new LinkedHashMap<>();
5051

5152
private boolean prepared = false;
5253
private boolean committed = false;
@@ -87,8 +88,8 @@ public boolean setProposedBlock(final Proposal msg) {
8788
if (!proposalMessage.isPresent()) {
8889
if (validator.validateProposal(msg)) {
8990
proposalMessage = Optional.of(msg);
90-
prepareMessages.removeIf(p -> !validator.validatePrepare(p));
91-
commitMessages.removeIf(p -> !validator.validateCommit(p));
91+
prepareMessages.entrySet().removeIf(e -> !validator.validatePrepare(e.getValue()));
92+
commitMessages.entrySet().removeIf(e -> !validator.validateCommit(e.getValue()));
9293
updateState();
9394
return true;
9495
}
@@ -104,7 +105,7 @@ public boolean setProposedBlock(final Proposal msg) {
104105
*/
105106
public void addPrepareMessage(final Prepare msg) {
106107
if (!proposalMessage.isPresent() || validator.validatePrepare(msg)) {
107-
prepareMessages.add(msg);
108+
prepareMessages.putIfAbsent(msg.getAuthor(), msg);
108109
LOG.trace("Round state added prepare message prepare={}", msg);
109110
}
110111
updateState();
@@ -117,7 +118,7 @@ public void addPrepareMessage(final Prepare msg) {
117118
*/
118119
public void addCommitMessage(final Commit msg) {
119120
if (!proposalMessage.isPresent() || validator.validateCommit(msg)) {
120-
commitMessages.add(msg);
121+
commitMessages.putIfAbsent(msg.getAuthor(), msg);
121122
LOG.trace("Round state added commit message commit={}", msg);
122123
}
123124

@@ -173,7 +174,7 @@ public boolean isCommitted() {
173174
* @return the commit seals
174175
*/
175176
public Collection<SECPSignature> getCommitSeals() {
176-
return commitMessages.stream()
177+
return commitMessages.values().stream()
177178
.map(cp -> cp.getSignedPayload().getPayload().getCommitSeal())
178179
.collect(Collectors.toList());
179180
}
@@ -185,7 +186,8 @@ public Collection<SECPSignature> getCommitSeals() {
185186
*/
186187
public Optional<PreparedRoundArtifacts> constructPreparedRoundArtifacts() {
187188
if (isPrepared()) {
188-
return Optional.of(new PreparedRoundArtifacts(proposalMessage.get(), prepareMessages));
189+
return Optional.of(
190+
new PreparedRoundArtifacts(proposalMessage.get(), prepareMessages.values()));
189191
}
190192
return Optional.empty();
191193
}

0 commit comments

Comments
 (0)