diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000000..6552dc52c30 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,225 @@ +--- +version: 2.1 +executors: + besu_executor_med: + docker: + - image: circleci/openjdk:11.0.4-jdk-stretch + resource_class: medium + working_directory: ~/project + environment: + JAVA_TOOL_OPTIONS: -Xmx2048m + GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=2 -Xmx2048m + + besu_executor_xl: + docker: + - image: circleci/openjdk:11.0.4-jdk-stretch + resource_class: xlarge + working_directory: ~/project + environment: + JAVA_TOOL_OPTIONS: -Xmx2048m + GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=6 -Xmx2048m + +commands: + prepare: + description: "Prepare" + steps: + - checkout + - run: + name: Install Packages - LibSodium + command: | + sudo apt-get update + sudo apt-get install -y libsodium18 libsodium-dev apt-transport-https + - restore_cache: + name: Restore cached gradle dependencies + keys: + - deps-{{ checksum "build.gradle" }}-{{ .Branch }}-{{ .Revision }} + - deps-{{ checksum "build.gradle" }} + - deps- + + capture_test_results: + description: "Capture test results" + steps: + - run: + name: Gather test results + when: always + command: | + FILES=`find . -name test-results` + for FILE in $FILES + do + MODULE=`echo "$FILE" | sed -e 's@./\(.*\)/build/test-results@\1@'` + TARGET="build/test-results/$MODULE" + mkdir -p "$TARGET" + cp -rf ${FILE}/*/* "$TARGET" + done + - store_test_results: + path: build/test-results + +jobs: + assemble: + executor: besu_executor_xl + steps: + - prepare + - run: + name: DCO check + command: | + ./scripts/dco_check.sh + - run: + name: Assemble + command: | + ./gradlew --no-daemon --parallel clean spotlessCheck compileJava compileTestJava assemble + - save_cache: + name: Caching gradle dependencies + key: deps-{{ checksum "build.gradle" }}-{{ .Branch }}-{{ .Revision }} + paths: + - .gradle + - ~/.gradle + - persist_to_workspace: + root: ~/project + paths: + - ./ + + unitTests: + executor: besu_executor_xl + steps: + - prepare + - attach_workspace: + at: ~/project + - run: + name: Build + no_output_timeout: 20m + command: | + ./gradlew --no-daemon --parallel build + - capture_test_results + + integrationTests: + executor: besu_executor_med + steps: + - prepare + - attach_workspace: + at: ~/project + - run: + name: IntegrationTests + command: | + ./gradlew --no-daemon --parallel integrationTest + - run: + name: Javadoc + command: | + ./gradlew --no-daemon --parallel javadoc + - run: + name: CompileJmh + command: | + ./gradlew --no-daemon --parallel compileJmh + - capture_test_results + + referenceTests: + executor: besu_executor_xl + steps: + - prepare + - attach_workspace: + at: ~/project + - run: + name: ReferenceTests + no_output_timeout: 20m + command: | + git submodule update --init --recursive + ./gradlew --no-daemon --parallel referenceTest + - capture_test_results + + acceptanceTests: + executor: besu_executor_xl + steps: + - prepare + - attach_workspace: + at: ~/project + - run: + name: AcceptanceTests + no_output_timeout: 40m + command: | + ./gradlew --no-daemon --parallel acceptanceTest + - capture_test_results + + buildDocker: + executor: besu_executor_med + steps: + - prepare + - attach_workspace: + at: ~/project + - setup_remote_docker + - run: + name: hadoLint + command: | + docker run --rm -i hadolint/hadolint < docker/Dockerfile + - run: + name: build image + command: | + ./gradlew --no-daemon distDocker + + publish: + executor: besu_executor_med + steps: + - prepare + - attach_workspace: + at: ~/project + - run: + name: Publish + command: | + ./gradlew --no-daemon --parallel bintrayUpload + + publishDocker: + executor: besu_executor_med + steps: + - prepare + - attach_workspace: + at: ~/project + - setup_remote_docker + - run: + name: Publish Docker + command: | + docker login --username "${DOCKER_USER}" --password "${DOCKER_PASSWORD}" + ./gradlew --no-daemon --parallel "-Pbranch=${CIRCLE_BRANCH}" dockerUpload + +workflows: + version: 2 + default: + jobs: + - assemble + - unitTests: + requires: + - assemble + - referenceTests: + requires: + - assemble + - integrationTests: + requires: + - assemble + - acceptanceTests: + requires: + - assemble + - buildDocker: + requires: + - unitTests + - publish: + filters: + branches: + only: + - master + #- /^release-.*/ + requires: + - integrationTests + - unitTests + - acceptanceTests + - referenceTests + - buildDocker + - publishDocker: + filters: + branches: + only: + - master + #- /^release-.*/ + requires: + - integrationTests + - unitTests + - acceptanceTests + - referenceTests + - buildDocker + diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f0d8d0eb8e..3f12bc76704 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,5 @@ # Changelog - ### Java 11 Required from v1.2 From v1.2, Besu requires Java 11. Besu on Java 8 is no longer supported. @@ -10,6 +9,45 @@ From v1.2, Besu requires Java 11. Besu on Java 8 is no longer supported. In v1.2, we removed the entry-point script from our Docker image. Refer to the [migration guide](https://besu.hyperledger.org/en/latest/HowTo/Get-Started/Migration-Docker/) for information on options that were previously automatically added to the Besu command line. +### 1.3.2 + +### Additions and Improvements + +- besu -v to print plugin versions[\#123](https://github.com/hyperledger/besu/pull/123) + +### Technical Improvements + +- Update Governance and Code of Conduct verbiage [\#120](https://github.com/hyperledger/besu/pull/120) +- Fix private transaction root mismatch [\#118](https://github.com/hyperledger/besu/pull/118) +- Programatically enforce plugin CLI variable names [\#117](https://github.com/hyperledger/besu/pull/117) +- Additional unit test for selecting replaced pending transactions [\#116](https://github.com/hyperledger/besu/pull/116) +- Only set sync targets that have an estimated height value [\#115](https://github.com/hyperledger/besu/pull/115) +- Fix rlpx startup [\#114](https://github.com/hyperledger/besu/pull/114) +- Expose getPayload in Transaction plugin-api interface. [\#113](https://github.com/hyperledger/besu/pull/113) +- Dependency Version Upgrades [\#112](https://github.com/hyperledger/besu/pull/112) +- Add hash field in Transaction plugin interface. [\#111](https://github.com/hyperledger/besu/pull/111) +- Rework sync status events [\#106](https://github.com/hyperledger/besu/pull/106) + +### 1.3.1 + +### Additions and Improvements + +- Added GraphQL query/logs support [\#94](https://github.com/hyperledger/besu/pull/94) + +### Technical Improvements + +- Add totalDiffculty to BlockPropagated events. [\#97](https://github.com/hyperledger/besu/pull/97) +- Merge BlockchainQueries classes [\#101](https://github.com/hyperledger/besu/pull/101) +- Fixed casing of dynamic MetricCategorys [\#99](https://github.com/hyperledger/besu/pull/99) +- Fix private transactions breaking evm [\#96](https://github.com/hyperledger/besu/pull/96) +- Make SyncState variables thread-safe [\#95](https://github.com/hyperledger/besu/pull/95) +- Fix transaction tracking by sender [\#93](https://github.com/hyperledger/besu/pull/93) +- Make logic in PersistBlockTask more explicit to fix a LGTM warning [\#92](https://github.com/hyperledger/besu/pull/92) +- Removed Unused methods in the transaction simulator. [\#91](https://github.com/hyperledger/besu/pull/91) +- Fix ThreadBesuNodeRunner BesuConfiguration setup [\#90](https://github.com/hyperledger/besu/pull/90) +- JsonRpc method disabled error condition rewrite and unit test [\#80](https://github.com/hyperledger/besu/pull/80) +- Round trip testing of state trie account values [\#31](https://github.com/hyperledger/besu/pull/31) + ### 1.3 ### Breaking Change @@ -18,6 +56,7 @@ for information on options that were previously automatically added to the Besu ### Additions and Improvements +- Add `--required-block` command line option to deal with chain splits [\#79](https://github.com/hyperledger/besu/pull/79) - Store db metadata file in the root data directory. [\#46](https://github.com/hyperledger/besu/pull/46) - Add `--target-gas-limit` command line option. [\#24](https://github.com/hyperledger/besu/pull/24)(thanks to new contributor [cfelde](https://github.com/cfelde)) - Allow private contracts to access public state. [\#9](https://github.com/hyperledger/besu/pull/9) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20ab21368f0..13d33e71f1e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,6 +29,14 @@ and feel free to propose changes to this document in a pull request. This project and everyone participating in it is governed by the [Besu Code of Conduct](CODE-OF-CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [private@pegasys.tech]. +The [Hyperledger Code of Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct) +also applies to participants in this project. + +## Governance + +Hyperledger Besu is managed under an open governance model as described in the [HyperLedger +charter](https://www.hyperledger.org/about/charter). Hyperledger Besu is lead by a set of [maintainers](MAINTAINERS.md). + ## I just have a quick question > **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below. diff --git a/DCO.md b/DCO.md index a10deeec06a..771aaef1414 100644 --- a/DCO.md +++ b/DCO.md @@ -5,5 +5,4 @@ As per section 13.a of the [Hyperledger Charter](https://www.hyperledger.org/abo The sign off needs to be using your legal name, not a pseudonym. Git has a built-in mechanism to allow this with the `-s` or `--signoff` argument to `git commit` command, providing your `user.name` and `user.email` have been setup correctly. -If you have any questions, you can reach us on [Besu chat]. -[Besu chat]: https://chat.hyperledger.org/channel/besu +If you have any questions, you can reach us on [Besu chat](https://chat.hyperledger.org/channel/besu). diff --git a/GOVERNANCE.md b/GOVERNANCE.md deleted file mode 100644 index c91a54a1330..00000000000 --- a/GOVERNANCE.md +++ /dev/null @@ -1,39 +0,0 @@ -# Overview -This project is led by a benevolent dictator (PegaSys) and managed by the community. That is, the community actively contributes to the day-to-day maintenance of the project, but the general strategic line is drawn by the benevolent dictator. In case of disagreement, they have the last word. It is the benevolent dictator’s job to resolve disputes within the community and to ensure that the project is able to progress in a coordinated way. In turn, it is the community’s job to guide the decisions of the benevolent dictator through active engagement and contribution. - - -# Principles - -The community adheres to the following principles: -* Open: Besu is open source. See repository guidelines and CLA, below. -* Welcoming and respectful: See Code of Conduct, below. -* Transparent and accessible: Work and collaboration should be done in public. -* Merit: Ideas and contributions are accepted according to their technical merit and alignment with project objectives and design principles. - -# Code of Conduct -See [code of conduct] - -# Community membership - -See [community membership] - -# Decision Making -Decision making will be handled by the Approvers (see [community membership]). If consensus cannot be reached, the Benevolent Dictator will provide the final word on the decision. - - -# DCO - -All contributors must send commits with sign-off to comply with [DCO](DCO.md) -## Attribution - -This document was influenced by the following: -- Kubernetes community-membership.md, available at [kub community membership]. -- Kubernetes governance.md, available at [kub governance] -- OSSWatch Benevolent Dictator Governance Model, available at [oss watch benevolent dictator]. - -[CLA.md]: /CLA.md -[community membership]: /docs/community/community-membership.md -[code of conduct]: /CODE-OF-CONDUCT.md -[oss watch benevolent dictator]: http://oss-watch.ac.uk/resources/benevolentdictatorgovernancemodel -[kub community membership]: https://raw.githubusercontent.com/kubernetes/community/master/community-membership.md -[kub governance]:https://github.com/kubernetes/community/blob/master/governance.md diff --git a/Jenkinsfile b/Jenkinsfile index 24113b50403..48faf373832 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -92,7 +92,7 @@ exit $status docker.image(build_image).inside("--link ${d.id}:docker") { try { stage(stage_name + 'Prepare') { - sh './gradlew --no-daemon --parallel clean compileJava compileTestJava assemble' + sh './gradlew --no-daemon --parallel clean spotlessCheck compileJava compileTestJava assemble' } stage(stage_name + 'Unit tests') { sh './gradlew --no-daemon --parallel build' diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 7abcc372fe5..ab0477379c9 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -11,6 +11,7 @@ | Byron Gravenorst | bgravenorst | bgravenorst | | Chris Hare | CjHare | cjhare | | Edward Evans | EdJoJob | EdJoJob | +| Ivaylo Kirilov | iikirilov | iikirilov | | Jason Frame | jframe | jframe | | Joshua Fernandes | joshuafernandes | joshuafernandes | | Lucas Saldanha | lucassaldanha | lucassaldanha | diff --git a/ROADMAP.md b/ROADMAP.md index cc92d49e380..83a0b5a8bd2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -10,7 +10,6 @@ Our key areas for now are: * Making Besu a First Class Client * Istanbul Support * State Pruning -* Tracing APIs * Disaster recovery ### Making Besu a First Class Client @@ -28,24 +27,20 @@ Besu will support the upcoming Istanbul network upgrade and implement all requir State pruning will be implemented. State pruning reduces the disk space required for the Besu database by discarding outdated world state data. -### Tracing APIs - -Additional tracing APIs to be added. - ### Disaster Recovery Support key-value storage in relational databases to solidify a robust Disaster Recovery process. Note: Orion to support Oracle and Postgres in 1.3. ## Next (v1.4) The key areas for next are: -* Privacy group modification +* Tracing APIs * Enhancing key management capabilities * Migration tools * Ethereum 1.x -### Privacy Group Modification +### Tracing APIs -Add the ability to add and remove privacy group members. +Additional tracing APIs to be added. ### Enhancing Key Management diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Account.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Account.java index b1b35fc4606..180f54343da 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Account.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Account.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions; import org.hyperledger.besu.util.bytes.Bytes32; +import java.math.BigDecimal; import java.math.BigInteger; import org.web3j.crypto.Credentials; @@ -66,12 +67,8 @@ public String getAddress() { return Address.extract(Hash.hash(keyPair.getPublicKey().getEncodedBytes())).toString(); } - public Condition balanceEquals(final String expectedBalance, final Unit balanceUnit) { - return new ExpectAccountBalance(eth, this, expectedBalance, balanceUnit); - } - public Condition balanceEquals(final int expectedBalance) { - return balanceEquals(String.valueOf(expectedBalance), Unit.ETHER); + return new ExpectAccountBalance(eth, this, BigDecimal.valueOf(expectedBalance), Unit.ETHER); } public Condition balanceEquals(final Amount expectedBalance) { @@ -79,12 +76,9 @@ public Condition balanceEquals(final Amount expectedBalance) { eth, this, expectedBalance.getValue(), expectedBalance.getUnit()); } - public Condition balanceDoesNotChange(final String startingBalance, final Unit balanceUnit) { - return new ExpectAccountBalanceNotChanging(eth, this, startingBalance, balanceUnit); - } - public Condition balanceDoesNotChange(final int startingBalance) { - return balanceDoesNotChange(String.valueOf(startingBalance), Unit.ETHER); + return new ExpectAccountBalanceNotChanging( + eth, this, BigDecimal.valueOf(startingBalance), Unit.ETHER); } @Override diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/blockchain/Amount.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/blockchain/Amount.java index b743e000c46..4c103fdf1b7 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/blockchain/Amount.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/blockchain/Amount.java @@ -17,6 +17,9 @@ import static org.web3j.utils.Convert.Unit.ETHER; import static org.web3j.utils.Convert.Unit.WEI; +import org.hyperledger.besu.ethereum.core.Wei; + +import java.math.BigDecimal; import java.math.BigInteger; import org.web3j.utils.Convert; @@ -24,20 +27,27 @@ public class Amount { - private String value; + private BigDecimal value; private Unit unit; - private Amount(final long value, final Unit unit) { - this.value = String.valueOf(value); + private Amount(final BigDecimal value, final Unit unit) { + this.value = value; this.unit = unit; } - private Amount(final BigInteger value, final Unit unit) { - this.value = value.toString(); - this.unit = unit; + public static Amount ether(final long value) { + return new Amount(BigDecimal.valueOf(value), ETHER); + } + + public static Amount wei(final BigInteger value) { + return new Amount(new BigDecimal(value), WEI); + } + + public static Amount wei(final Wei wei) { + return wei(new BigInteger(wei.toUnprefixedHexString(), 16)); } - public String getValue() { + public BigDecimal getValue() { return value; } @@ -54,21 +64,11 @@ public Amount subtract(final Amount subtracting) { denominator = subtracting.unit; } - final BigInteger result = + final BigDecimal result = Convert.fromWei( - Convert.toWei(value, unit) - .subtract(Convert.toWei(subtracting.value, subtracting.unit)), - denominator) - .toBigInteger(); + Convert.toWei(value, unit).subtract(Convert.toWei(subtracting.value, subtracting.unit)), + denominator); return new Amount(result, denominator); } - - public static Amount ether(final long value) { - return new Amount(value, ETHER); - } - - public static Amount wei(final BigInteger value) { - return new Amount(value, WEI); - } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/account/ExpectAccountBalance.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/account/ExpectAccountBalance.java index cca7b896677..91cfaf57d78 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/account/ExpectAccountBalance.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/account/ExpectAccountBalance.java @@ -23,31 +23,30 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.Node; import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions; +import java.math.BigDecimal; +import java.math.BigInteger; + import org.web3j.utils.Convert.Unit; public class ExpectAccountBalance implements Condition { private final EthTransactions eth; private final Account account; - private final String expectedBalance; - private final Unit balanceUnit; + private final BigInteger expectedBalance; public ExpectAccountBalance( final EthTransactions eth, final Account account, - final String expectedBalance, + final BigDecimal expectedBalance, final Unit balanceUnit) { - this.expectedBalance = expectedBalance; - this.balanceUnit = balanceUnit; this.account = account; this.eth = eth; + this.expectedBalance = toWei(expectedBalance, balanceUnit).toBigIntegerExact(); } @Override public void verify(final Node node) { WaitUtils.waitFor( - () -> - assertThat(node.execute(eth.getBalance((account)))) - .isEqualTo(toWei(expectedBalance, balanceUnit).toBigIntegerExact())); + () -> assertThat(node.execute(eth.getBalance((account)))).isEqualTo(expectedBalance)); } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/account/ExpectAccountBalanceNotChanging.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/account/ExpectAccountBalanceNotChanging.java index 840fe47122f..e54cef45a3c 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/account/ExpectAccountBalanceNotChanging.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/account/ExpectAccountBalanceNotChanging.java @@ -22,6 +22,8 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.Node; import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.concurrent.TimeUnit; import org.awaitility.Awaitility; @@ -31,18 +33,16 @@ public class ExpectAccountBalanceNotChanging implements Condition { private final EthTransactions eth; private final Account account; - private final String startBalance; - private final Unit balanceUnit; + private final BigInteger startBalance; public ExpectAccountBalanceNotChanging( final EthTransactions eth, final Account account, - final String startBalance, + final BigDecimal startBalance, final Unit balanceUnit) { - this.startBalance = startBalance; - this.balanceUnit = balanceUnit; this.account = account; this.eth = eth; + this.startBalance = toWei(startBalance, balanceUnit).toBigIntegerExact(); } @Override @@ -51,8 +51,6 @@ public void verify(final Node node) { .ignoreExceptions() .pollDelay(5, TimeUnit.SECONDS) .untilAsserted( - () -> - assertThat(node.execute(eth.getBalance((account)))) - .isEqualTo(toWei(startBalance, balanceUnit).toBigIntegerExact())); + () -> assertThat(node.execute(eth.getBalance((account)))).isEqualTo(startBalance)); } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java index cf6edb5a618..ab4918f2364 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.tests.acceptance.dsl.node; import static org.hyperledger.besu.cli.config.NetworkName.DEV; +import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH; import org.hyperledger.besu.Runner; import org.hyperledger.besu.RunnerBuilder; @@ -57,7 +58,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import com.google.common.io.Files; import io.vertx.core.Vertx; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -107,8 +107,9 @@ public void startNode(final BesuNode node) { } final StorageServiceImpl storageService = new StorageServiceImpl(); - final Path path = Files.createTempDir().toPath(); - final BesuConfiguration commonPluginConfiguration = new BesuConfigurationImpl(path, path); + final Path dataDir = node.homeDirectory(); + final BesuConfiguration commonPluginConfiguration = + new BesuConfigurationImpl(dataDir, dataDir.resolve(DATABASE_PATH)); final BesuPluginContextImpl besuPluginContext = besuPluginContextMap.computeIfAbsent( node, n -> buildPluginContext(node, storageService, commonPluginConfiguration)); diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransaction.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransaction.java index f515788c784..1993e5c62b0 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransaction.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransaction.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction; import java.io.IOException; +import java.math.BigDecimal; import java.math.BigInteger; import java.util.Optional; @@ -41,7 +42,7 @@ public class TransferTransaction implements Transaction { private final Account sender; private final Account recipient; - private final String transferAmount; + private final BigDecimal transferAmount; private final Unit transferUnit; private final BigInteger gasPrice; private final BigInteger nonce; diff --git a/acceptance-tests/tests/build.gradle b/acceptance-tests/tests/build.gradle index 13690596a8b..6dad2afdf0d 100644 --- a/acceptance-tests/tests/build.gradle +++ b/acceptance-tests/tests/build.gradle @@ -38,7 +38,11 @@ dependencies { test.enabled = false sourceSets { - test { resources { srcDirs "${rootDir}/besu/build/libs" } } + test { + resources { + srcDirs "${rootDir}/besu/build/libs" + } + } } processTestResources.dependsOn(':besu:testJar') diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AccountLocalConfigPermissioningAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AccountLocalConfigPermissioningAcceptanceTest.java index 0479292411b..4131ee03425 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AccountLocalConfigPermissioningAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AccountLocalConfigPermissioningAcceptanceTest.java @@ -14,8 +14,6 @@ */ package org.hyperledger.besu.tests.acceptance.permissioning; -import static org.web3j.utils.Convert.Unit.ETHER; - import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.account.Account; import org.hyperledger.besu.tests.acceptance.dsl.node.Node; @@ -52,7 +50,7 @@ public void onlyAllowedAccountCanSubmitTransactions() { Account beneficiary = accounts.createAccount("beneficiary"); node.execute(accountTransactions.createTransfer(senderA, beneficiary, 1)); - node.verify(beneficiary.balanceEquals("1", ETHER)); + node.verify(beneficiary.balanceEquals(1)); verifyTransferForbidden(senderB, beneficiary); } @@ -60,7 +58,7 @@ public void onlyAllowedAccountCanSubmitTransactions() { @Test public void manipulatingAccountsWhitelistViaJsonRpc() { Account beneficiary = accounts.createAccount("beneficiary"); - node.verify(beneficiary.balanceEquals("0", ETHER)); + node.verify(beneficiary.balanceEquals(0)); verifyTransferForbidden(senderB, beneficiary); @@ -68,7 +66,7 @@ public void manipulatingAccountsWhitelistViaJsonRpc() { node.verify(perm.expectAccountsWhitelist(senderA.getAddress(), senderB.getAddress())); node.execute(accountTransactions.createTransfer(senderB, beneficiary, 1)); - node.verify(beneficiary.balanceEquals("1", ETHER)); + node.verify(beneficiary.balanceEquals(1)); node.execute(permissioningTransactions.removeAccountsFromWhitelist(senderB.getAddress())); node.verify(perm.expectAccountsWhitelist(senderA.getAddress())); diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/BadCLIOptionsPluginTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/BadCLIOptionsPluginTest.java new file mode 100644 index 00000000000..2d29d05e0ef --- /dev/null +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/BadCLIOptionsPluginTest.java @@ -0,0 +1,85 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.tests.acceptance.plugins; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; +import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +import org.awaitility.Awaitility; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +public class BadCLIOptionsPluginTest extends AcceptanceTestBase { + private BesuNode node; + + @Before + public void setUp() throws Exception { + node = + besu.createPluginsNode( + "node1", Collections.singletonList("testPlugins"), Collections.emptyList()); + cluster.start(node); + } + + @Test + public void shouldNotRegister() { + final Path registrationFile = node.homeDirectory().resolve("plugins/badCLIOptions.init"); + waitForFile(registrationFile); + assertThat(node.homeDirectory().resolve("plugins/badCliOptions.register")).doesNotExist(); + } + + @Test + public void shouldNotStart() { + // depend on the good PicoCLIOptions to tell us when it should be up + final Path registrationFile = node.homeDirectory().resolve("plugins/pluginLifecycle.started"); + waitForFile(registrationFile); + + assertThat(node.homeDirectory().resolve("plugins/badCliOptions.start")).doesNotExist(); + } + + @Test + @Ignore("No way to do a graceful shutdown of Besu at the moment.") + public void shouldNotStop() { + cluster.stopNode(node); + waitForFile(node.homeDirectory().resolve("plugins/pluginLifecycle.stopped")); + assertThat(node.homeDirectory().resolve("plugins/badCliOptions.start")).doesNotExist(); + assertThat(node.homeDirectory().resolve("plugins/badCliOptions.stop")).doesNotExist(); + } + + private void waitForFile(final Path path) { + final File file = path.toFile(); + Awaitility.waitAtMost(30, TimeUnit.SECONDS) + .until( + () -> { + if (file.exists()) { + try (final Stream s = Files.lines(path)) { + return s.count() > 0; + } + } else { + return false; + } + }); + } +} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/PicoCLIOptionsPluginTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/PicoCLIOptionsPluginTest.java index 648c6e1feeb..d1a1154de69 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/PicoCLIOptionsPluginTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/PicoCLIOptionsPluginTest.java @@ -44,7 +44,7 @@ public void setUp() throws Exception { besu.createPluginsNode( "node1", Collections.singletonList("testPlugins"), - Collections.singletonList("--Xtest-option=" + MAGIC_WORDS)); + Collections.singletonList("--Xplugin-test-option=" + MAGIC_WORDS)); cluster.start(node); } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivacyClusterAcceptanceTest.java index 2a7e19cd079..97a12eb92d5 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivacyClusterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivacyClusterAcceptanceTest.java @@ -98,7 +98,29 @@ public void onlyAliceAndBobCanExecuteContract() { bob.verify( privateTransactionVerifier.validPrivateTransactionReceipt( transactionHash, expectedReceipt)); + charlie.verify(privateTransactionVerifier.noPrivateTransactionReceipt(transactionHash)); + + // When Alice executes a contract call in the wrong privacy group the transaction should pass + // but it should NOT return any output + final String transactionHash2 = + alice.execute( + privateContractTransactions.callSmartContract( + eventEmitter.getContractAddress(), + eventEmitter.value().encodeFunctionCall(), + alice.getTransactionSigningKey(), + POW_CHAIN_ID, + alice.getEnclaveKey(), + charlie.getEnclaveKey())); + + final PrivateTransactionReceipt expectedReceipt2 = + alice.execute(privacyTransactions.getPrivateTransactionReceipt(transactionHash2)); + + assertThat(expectedReceipt2.getOutput()).isEqualTo("0x"); + + charlie.verify( + privateTransactionVerifier.validPrivateTransactionReceipt( + transactionHash2, expectedReceipt2)); } @Test diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivateContractPublicStateAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivateContractPublicStateAcceptanceTest.java index 2672d24faf7..f53bbfb183e 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivateContractPublicStateAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivateContractPublicStateAcceptanceTest.java @@ -33,32 +33,34 @@ public class PrivateContractPublicStateAcceptanceTest extends PrivacyAcceptanceT private static final long POW_CHAIN_ID = 2018; private PrivacyNode minerNode; + private PrivacyNode transactionNode; @Before public void setUp() throws Exception { minerNode = privacyBesu.createPrivateTransactionEnabledMinerNode( "miner-node", privacyAccountResolver.resolve(0)); - privacyCluster.start(minerNode); + transactionNode = + privacyBesu.createPrivateTransactionEnabledNode( + "transaction-node", privacyAccountResolver.resolve(1)); + privacyCluster.start(minerNode, transactionNode); } @Test public void mustAllowAccessToPublicStateFromPrivateTx() throws Exception { final EventEmitter publicEventEmitter = - minerNode.getBesu().execute((contractTransactions.createSmartContract(EventEmitter.class))); + transactionNode.execute((contractTransactions.createSmartContract(EventEmitter.class))); final TransactionReceipt receipt = publicEventEmitter.store(BigInteger.valueOf(12)).send(); assertThat(receipt).isNotNull(); final CrossContractReader reader = - minerNode - .getBesu() - .execute( - privateContractTransactions.createSmartContract( - CrossContractReader.class, - minerNode.getTransactionSigningKey(), - POW_CHAIN_ID, - minerNode.getEnclaveKey())); + transactionNode.execute( + privateContractTransactions.createSmartContract( + CrossContractReader.class, + transactionNode.getTransactionSigningKey(), + POW_CHAIN_ID, + transactionNode.getEnclaveKey())); assertThat(reader.read(publicEventEmitter.getContractAddress()).send()) .isEqualTo(BigInteger.valueOf(12)); @@ -67,22 +69,19 @@ public void mustAllowAccessToPublicStateFromPrivateTx() throws Exception { @Test(expected = ContractCallException.class) public void mustNotAllowAccessToPrivateStateFromPublicTx() throws Exception { final EventEmitter privateEventEmitter = - minerNode - .getBesu() - .execute( - (privateContractTransactions.createSmartContract( - EventEmitter.class, - minerNode.getTransactionSigningKey(), - POW_CHAIN_ID, - minerNode.getEnclaveKey()))); + transactionNode.execute( + (privateContractTransactions.createSmartContract( + EventEmitter.class, + transactionNode.getTransactionSigningKey(), + POW_CHAIN_ID, + transactionNode.getEnclaveKey()))); final TransactionReceipt receipt = privateEventEmitter.store(BigInteger.valueOf(12)).send(); assertThat(receipt).isNotNull(); final CrossContractReader publicReader = - minerNode - .getBesu() - .execute(contractTransactions.createSmartContract(CrossContractReader.class)); + transactionNode.execute( + contractTransactions.createSmartContract(CrossContractReader.class)); publicReader.read(privateEventEmitter.getContractAddress()).send(); } @@ -90,19 +89,16 @@ public void mustNotAllowAccessToPrivateStateFromPublicTx() throws Exception { @Test public void privateContractMustNotBeAbleToCallPublicContractWhichChangesState() throws Exception { final CrossContractReader privateReader = - minerNode - .getBesu() - .execute( - privateContractTransactions.createSmartContract( - CrossContractReader.class, - minerNode.getTransactionSigningKey(), - POW_CHAIN_ID, - minerNode.getEnclaveKey())); + transactionNode.execute( + privateContractTransactions.createSmartContract( + CrossContractReader.class, + transactionNode.getTransactionSigningKey(), + POW_CHAIN_ID, + transactionNode.getEnclaveKey())); final CrossContractReader publicReader = - minerNode - .getBesu() - .execute(contractTransactions.createSmartContract(CrossContractReader.class)); + transactionNode.execute( + contractTransactions.createSmartContract(CrossContractReader.class)); final PrivateTransactionReceipt transactionReceipt = (PrivateTransactionReceipt) @@ -115,19 +111,16 @@ public void privateContractMustNotBeAbleToCallPublicContractWhichChangesState() public void privateContractMustNotBeAbleToCallPublicContractWhichInstantiatesContract() throws Exception { final CrossContractReader privateReader = - minerNode - .getBesu() - .execute( - privateContractTransactions.createSmartContract( - CrossContractReader.class, - minerNode.getTransactionSigningKey(), - POW_CHAIN_ID, - minerNode.getEnclaveKey())); + transactionNode.execute( + privateContractTransactions.createSmartContract( + CrossContractReader.class, + transactionNode.getTransactionSigningKey(), + POW_CHAIN_ID, + transactionNode.getEnclaveKey())); final CrossContractReader publicReader = - minerNode - .getBesu() - .execute(contractTransactions.createSmartContract(CrossContractReader.class)); + transactionNode.execute( + contractTransactions.createSmartContract(CrossContractReader.class)); final PrivateTransactionReceipt transactionReceipt = (PrivateTransactionReceipt) @@ -137,19 +130,17 @@ public void privateContractMustNotBeAbleToCallPublicContractWhichInstantiatesCon } @Test - public void privateContractMustNotBeAbleToCallSelfDetructOfPublicContract() throws Exception { + public void privateContractMustNotBeAbleToCallSelfDestructOnPublicContract() throws Exception { final CrossContractReader privateReader = - minerNode - .getBesu() - .execute( - privateContractTransactions.createSmartContract( - CrossContractReader.class, - minerNode.getTransactionSigningKey(), - POW_CHAIN_ID, - minerNode.getEnclaveKey())); + transactionNode.execute( + privateContractTransactions.createSmartContract( + CrossContractReader.class, + transactionNode.getTransactionSigningKey(), + POW_CHAIN_ID, + transactionNode.getEnclaveKey())); final CrossContractReader publicReader = - minerNode + transactionNode .getBesu() .execute(contractTransactions.createSmartContract(CrossContractReader.class)); diff --git a/besu/src/main/java/org/hyperledger/besu/BesuInfo.java b/besu/src/main/java/org/hyperledger/besu/BesuInfo.java index aae241da000..00e458f5590 100644 --- a/besu/src/main/java/org/hyperledger/besu/BesuInfo.java +++ b/besu/src/main/java/org/hyperledger/besu/BesuInfo.java @@ -16,20 +16,23 @@ import org.hyperledger.besu.util.PlatformDetector; +import java.util.Optional; + public final class BesuInfo { - private static final String CLIENT_IDENTITY = "besu"; - private static final String VERSION = - CLIENT_IDENTITY - + "/v" - + BesuInfo.class.getPackage().getImplementationVersion() - + "/" - + PlatformDetector.getOS() - + "/" - + PlatformDetector.getVM(); + private static final String CLIENT = "besu"; + private static final String VERSION = BesuInfo.class.getPackage().getImplementationVersion(); + private static final String OS = PlatformDetector.getOS(); + private static final String VM = PlatformDetector.getVM(); private BesuInfo() {} public static String version() { - return VERSION; + return String.format("%s/v%s/%s/%s", CLIENT, VERSION, OS, VM); + } + + public static String nodeName(final Optional maybeIdentity) { + return maybeIdentity + .map(identity -> String.format("%s/%s/v%s/%s/%s", CLIENT, identity, VERSION, OS, VM)) + .orElse(version()); } } diff --git a/besu/src/main/java/org/hyperledger/besu/Runner.java b/besu/src/main/java/org/hyperledger/besu/Runner.java index 3c6db9d98de..d7229c56616 100644 --- a/besu/src/main/java/org/hyperledger/besu/Runner.java +++ b/besu/src/main/java/org/hyperledger/besu/Runner.java @@ -29,6 +29,7 @@ import java.util.Optional; import java.util.Properties; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -43,6 +44,8 @@ public class Runner implements AutoCloseable { private static final Logger LOG = LogManager.getLogger(); private final Vertx vertx; + private final CountDownLatch vertxShutdownLatch = new CountDownLatch(1); + private final CountDownLatch shutdown = new CountDownLatch(1); private final NetworkRunner networkRunner; private final Optional natManager; @@ -78,13 +81,12 @@ public class Runner implements AutoCloseable { public void start() { try { LOG.info("Starting Ethereum main loop ... "); - if (natManager.isPresent()) { - natManager.get().start(); - } + natManager.ifPresent(UpnpNatManager::start); networkRunner.start(); if (networkRunner.getNetwork().isP2pEnabled()) { besuController.getSynchronizer().start(); } + besuController.getMiningCoordinator().start(); vertx.setPeriodic( TimeUnit.MINUTES.toMillis(1), time -> @@ -101,9 +103,32 @@ public void start() { } } + public void stop() { + jsonRpc.ifPresent(service -> waitForServiceToStop("jsonRpc", service.stop())); + graphQLHttp.ifPresent(service -> waitForServiceToStop("graphQLHttp", service.stop())); + websocketRpc.ifPresent(service -> waitForServiceToStop("websocketRpc", service.stop())); + metrics.ifPresent(service -> waitForServiceToStop("metrics", service.stop())); + + besuController.getMiningCoordinator().stop(); + waitForServiceToStop("Mining Coordinator", besuController.getMiningCoordinator()::awaitStop); + if (networkRunner.getNetwork().isP2pEnabled()) { + besuController.getSynchronizer().stop(); + waitForServiceToStop("Synchronizer", besuController.getSynchronizer()::awaitStop); + } + + networkRunner.stop(); + waitForServiceToStop("Network", networkRunner::awaitStop); + + natManager.ifPresent(UpnpNatManager::stop); + besuController.close(); + vertx.close((res) -> vertxShutdownLatch.countDown()); + waitForServiceToStop("Vertx", vertxShutdownLatch::await); + shutdown.countDown(); + } + public void awaitStop() { try { - networkRunner.awaitStop(); + shutdown.await(); } catch (final InterruptedException e) { LOG.debug("Interrupted, exiting", e); Thread.currentThread().interrupt(); @@ -111,30 +136,9 @@ public void awaitStop() { } @Override - public void close() throws Exception { - try { - if (networkRunner.getNetwork().isP2pEnabled()) { - besuController.getSynchronizer().stop(); - } - - networkRunner.stop(); - networkRunner.awaitStop(); - - jsonRpc.ifPresent(service -> waitForServiceToStop("jsonRpc", service.stop())); - graphQLHttp.ifPresent(service -> waitForServiceToStop("graphQLHttp", service.stop())); - websocketRpc.ifPresent(service -> waitForServiceToStop("websocketRpc", service.stop())); - metrics.ifPresent(service -> waitForServiceToStop("metrics", service.stop())); - - if (natManager.isPresent()) { - natManager.get().stop(); - } - } finally { - try { - vertx.close(); - } finally { - besuController.close(); - } - } + public void close() { + stop(); + awaitStop(); } private void waitForServiceToStop( @@ -151,6 +155,15 @@ private void waitForServiceToStop( } } + private void waitForServiceToStop(final String serviceName, final SynchronousShutdown shutdown) { + try { + shutdown.await(); + } catch (final InterruptedException e) { + LOG.debug("Interrupted while waiting for service " + serviceName + " to stop", e); + Thread.currentThread().interrupt(); + } + } + private void waitForServiceToStart( final String serviceName, final CompletableFuture startFuture) { while (!startFuture.isDone()) { @@ -236,4 +249,9 @@ public Optional getMetricsPort() { Optional getLocalEnode() { return networkRunner.getNetwork().getLocalEnode(); } + + @FunctionalInterface + private interface SynchronousShutdown { + void await() throws InterruptedException; + } } diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index b12b2e0f419..6251f1cfbf8 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -28,7 +28,6 @@ import org.hyperledger.besu.ethereum.api.graphql.GraphQLProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcHttpService; -import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; import org.hyperledger.besu.ethereum.api.jsonrpc.health.HealthService; import org.hyperledger.besu.ethereum.api.jsonrpc.health.LivenessCheck; @@ -37,7 +36,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterRepository; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketRequestHandler; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketService; @@ -48,6 +47,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.pending.PendingTransactionDroppedSubscriptionService; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.pending.PendingTransactionSubscriptionService; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.syncing.SyncingSubscriptionService; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.PrivacyParameters; @@ -131,6 +131,7 @@ public class RunnerBuilder { private ObservableMetricsSystem metricsSystem; private Optional permissioningConfiguration = Optional.empty(); private Collection staticNodes = Collections.emptyList(); + private Optional identityString = Optional.empty(); public RunnerBuilder vertx(final Vertx vertx) { this.vertx = vertx; @@ -247,6 +248,11 @@ public RunnerBuilder staticNodes(final Collection staticNodes) { return this; } + public RunnerBuilder identityString(final Optional identityString) { + this.identityString = identityString; + return this; + } + public Runner build() { Preconditions.checkNotNull(besuController); @@ -290,7 +296,7 @@ public Runner build() { .setBindPort(p2pListenPort) .setMaxPeers(maxPeers) .setSupportedProtocols(subProtocols) - .setClientId(BesuInfo.version()) + .setClientId(BesuInfo.nodeName(identityString)) .setLimitRemoteWireConnectionsEnabled(limitRemoteWireConnectionsEnabled) .setFractionRemoteWireConnectionsAllowed(fractionRemoteConnectionsAllowed); networkingConfiguration.setRlpx(rlpxConfiguration).setDiscovery(discoveryConfiguration); @@ -453,8 +459,7 @@ public Runner build() { final SubscriptionManager subscriptionManager = createSubscriptionManager(vertx, transactionPool); - createLogsSubscriptionService( - context.getBlockchain(), context.getWorldStateArchive(), subscriptionManager); + createLogsSubscriptionService(context.getBlockchain(), subscriptionManager); createNewBlockHeadersSubscriptionService( context.getBlockchain(), context.getWorldStateArchive(), subscriptionManager); @@ -582,7 +587,7 @@ private Map jsonRpcMethods( final Map methods = new JsonRpcMethodsFactory() .methods( - BesuInfo.version(), + BesuInfo.nodeName(identityString), ethNetworkConfig.getNetworkId(), besuController.getGenesisConfigOptions(), network, @@ -621,12 +626,9 @@ private SubscriptionManager createSubscriptionManager( } private void createLogsSubscriptionService( - final Blockchain blockchain, - final WorldStateArchive worldStateArchive, - final SubscriptionManager subscriptionManager) { + final Blockchain blockchain, final SubscriptionManager subscriptionManager) { final LogsSubscriptionService logsSubscriptionService = - new LogsSubscriptionService( - subscriptionManager, new BlockchainQueries(blockchain, worldStateArchive)); + new LogsSubscriptionService(subscriptionManager); blockchain.observeBlockAdded(logsSubscriptionService); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 5fae5ba3a75..50eca10ca02 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -56,12 +56,11 @@ import org.hyperledger.besu.cli.subcommands.blocks.BlocksSubCommand.RlpBlockExporterFactory; import org.hyperledger.besu.cli.subcommands.operator.OperatorSubCommand; import org.hyperledger.besu.cli.subcommands.rlp.RLPSubCommand; +import org.hyperledger.besu.cli.util.BesuCommandCustomFactory; import org.hyperledger.besu.cli.util.CommandLineUtils; import org.hyperledger.besu.cli.util.ConfigOptionSearchAndRunHandler; import org.hyperledger.besu.cli.util.VersionProvider; import org.hyperledger.besu.config.GenesisConfigFile; -import org.hyperledger.besu.consensus.common.PoAContext; -import org.hyperledger.besu.consensus.common.PoAMetricServiceImpl; import org.hyperledger.besu.controller.BesuController; import org.hyperledger.besu.controller.BesuControllerBuilder; import org.hyperledger.besu.controller.KeyPairUtil; @@ -104,7 +103,6 @@ import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; -import org.hyperledger.besu.plugin.services.metrics.PoAMetricsService; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBPlugin; import org.hyperledger.besu.services.BesuConfigurationImpl; import org.hyperledger.besu.services.BesuEventsImpl; @@ -209,6 +207,13 @@ protected KeyLoader getKeyLoader() { // CLI options defined by user at runtime. // Options parsing is done with CLI library Picocli https://picocli.info/ + @Option( + names = "--identity", + paramLabel = "", + description = "Identification for this node in the Client ID", + arity = "1") + private final Optional identityString = Optional.empty(); + // Completely disables P2P within Besu. @Option( names = {"--p2p-enabled"}, @@ -548,8 +553,8 @@ void setBannedNodeIds(final List values) { names = {"--logging", "-l"}, paramLabel = "", description = - "Logging verbosity levels: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL (default: INFO)") - private final Level logLevel = null; + "Logging verbosity levels: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL (default: ${DEFAULT-VALUE})") + private final Level logLevel = LogManager.getRootLogger().getLevel(); @Option( names = {"--miner-enabled"}, @@ -582,10 +587,9 @@ void setBannedNodeIds(final List values) { @Option( names = {"--pruning-enabled"}, - hidden = true, description = - "Enable pruning of world state of blocks older than the retention period (default: ${DEFAULT-VALUE})") - private final Boolean isPruningEnabled = false; + "Enable pruning of world state of blocks older than the retention period (default: true if fast sync is enabled, false otherwise)") + private Boolean pruningOverride; @Option( names = {"--pruning-blocks-retained"}, @@ -773,7 +777,9 @@ public void parse( final BesuExceptionHandler exceptionHandler, final InputStream in, final String... args) { - commandLine = new CommandLine(this).setCaseInsensitiveEnumValuesAllowed(true); + commandLine = + new CommandLine(this, new BesuCommandCustomFactory(besuPluginContext)) + .setCaseInsensitiveEnumValuesAllowed(true); handleStandaloneCommand() .addSubCommands(resultHandler, in) .registerConverters() @@ -786,7 +792,7 @@ public void parse( public void run() { try { prepareLogging(); - logger.info("Starting Besu version: {}", BesuInfo.version()); + logger.info("Starting Besu version: {}", BesuInfo.nodeName(identityString)); validateOptions().configure().controller().startPlugins().startSynchronization(); } catch (final Exception e) { throw new ParameterException(this.commandLine, e.getMessage(), e); @@ -846,6 +852,7 @@ private BesuCommand registerConverters() { commandLine.registerConverter(Wei.class, (arg) -> Wei.of(Long.parseUnsignedLong(arg))); commandLine.registerConverter(PositiveNumber.class, PositiveNumber::fromString); commandLine.registerConverter(Hash.class, Hash::fromHexString); + commandLine.registerConverter(Optional.class, Optional::of); metricCategoryConverter.addCategories(BesuMetricCategory.class); metricCategoryConverter.addCategories(StandardMetricCategory.class); @@ -924,25 +931,12 @@ private BesuCommand startPlugins() { besuController.getProtocolManager().getBlockBroadcaster(), besuController.getTransactionPool(), besuController.getSyncState())); - addPluginMetrics(besuController); + besuPluginContext.addService(MetricsSystem.class, getMetricsSystem()); + besuController.getAdditionalPluginServices().appendPluginServices(besuPluginContext); besuPluginContext.startPlugins(); return this; } - private void addPluginMetrics(final BesuController besuController) { - besuPluginContext.addService(MetricsSystem.class, getMetricsSystem()); - - final Object consensusState = besuController.getProtocolContext().getConsensusState(); - - if (consensusState != null && PoAContext.class.isAssignableFrom(consensusState.getClass())) { - final PoAMetricServiceImpl service = - new PoAMetricServiceImpl( - ((PoAContext) consensusState).getBlockInterface(), - besuController.getProtocolContext().getBlockchain()); - besuPluginContext.addService(PoAMetricsService.class, service); - } - } - private void prepareLogging() { // set log level per CLI flags if (logLevel != null) { @@ -1017,7 +1011,7 @@ private void issueOptionWarnings() { logger, commandLine, "--pruning-enabled", - !isPruningEnabled, + !isPruningEnabled(), asList("--pruning-block-confirmations", "--pruning-blocks-retained")); } @@ -1093,7 +1087,7 @@ public BesuControllerBuilder getControllerBuilder() { .clock(Clock.systemUTC()) .isRevertReasonEnabled(isRevertReasonEnabled) .storageProvider(keyStorageProvider(keyValueStorageName)) - .isPruningEnabled(isPruningEnabled) + .isPruningEnabled(isPruningEnabled()) .pruningConfiguration(buildPruningConfiguration()) .genesisConfigOverrides(genesisConfigOverrides) .targetGasLimit(targetGasLimit == null ? Optional.empty() : Optional.of(targetGasLimit)) @@ -1380,6 +1374,10 @@ private PruningConfiguration buildPruningConfiguration() { return new PruningConfiguration(pruningBlockConfirmations, pruningBlocksRetained); } + private boolean isPruningEnabled() { + return Optional.ofNullable(pruningOverride).orElse(syncMode == SyncMode.FAST); + } + // Blockchain synchronisation from peers. private void synchronize( final BesuController controller, @@ -1426,6 +1424,7 @@ private void synchronize( .metricsSystem(metricsSystem) .metricsConfiguration(metricsConfiguration) .staticNodes(staticNodes) + .identityString(identityString) .build(); addShutdownHook(runner); diff --git a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java index 94fb80415c6..f7c8f73f901 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java @@ -62,8 +62,6 @@ public interface DefaultCommandValues { String PERMISSIONING_CONFIG_LOCATION = "permissions_config.toml"; String MANDATORY_HOST_FORMAT_HELP = ""; String MANDATORY_PORT_FORMAT_HELP = ""; - // Default should be FAST for the next release - // but we use FULL for the moment as Fast is still in progress SyncMode DEFAULT_SYNC_MODE = SyncMode.FULL; NatMethod DEFAULT_NAT_METHOD = NatMethod.NONE; int FAST_SYNC_MIN_PEER_COUNT = 5; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java b/besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java index 5c396ce70c9..03da7e590c5 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java @@ -17,6 +17,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration.CLASSIC_BOOTSTRAP_NODES; import static org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration.GOERLI_BOOTSTRAP_NODES; +import static org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration.KOTTI_BOOTSTRAP_NODES; import static org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration.MAINNET_BOOTSTRAP_NODES; import static org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration.RINKEBY_BOOTSTRAP_NODES; import static org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration.ROPSTEN_BOOTSTRAP_NODES; @@ -41,12 +42,14 @@ public class EthNetworkConfig { public static final BigInteger GOERLI_NETWORK_ID = BigInteger.valueOf(5); public static final BigInteger DEV_NETWORK_ID = BigInteger.valueOf(2018); public static final BigInteger CLASSIC_NETWORK_ID = BigInteger.valueOf(1); + public static final BigInteger KOTTI_NETWORK_ID = BigInteger.valueOf(6); private static final String MAINNET_GENESIS = "/mainnet.json"; private static final String ROPSTEN_GENESIS = "/ropsten.json"; private static final String RINKEBY_GENESIS = "/rinkeby.json"; private static final String GOERLI_GENESIS = "/goerli.json"; private static final String DEV_GENESIS = "/dev.json"; private static final String CLASSIC_GENESIS = "/classic.json"; + private static final String KOTTI_GENESIS = "/kotti.json"; private final String genesisConfig; private final BigInteger networkId; private final List bootNodes; @@ -119,6 +122,9 @@ public static EthNetworkConfig getNetworkConfig(final NetworkName networkName) { case CLASSIC: return new EthNetworkConfig( jsonConfig(CLASSIC_GENESIS), CLASSIC_NETWORK_ID, CLASSIC_BOOTSTRAP_NODES); + case KOTTI: + return new EthNetworkConfig( + jsonConfig(KOTTI_GENESIS), KOTTI_NETWORK_ID, KOTTI_BOOTSTRAP_NODES); case MAINNET: default: return new EthNetworkConfig( diff --git a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java index 21c263dc3f3..5e1173df5a6 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java @@ -20,5 +20,6 @@ public enum NetworkName { ROPSTEN, GOERLI, DEV, - CLASSIC + CLASSIC, + KOTTI } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/converter/MetricCategoryConverter.java b/besu/src/main/java/org/hyperledger/besu/cli/converter/MetricCategoryConverter.java index 0d1f0ad2236..9752c6df28d 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/converter/MetricCategoryConverter.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/converter/MetricCategoryConverter.java @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.Map; +import com.google.common.annotations.VisibleForTesting; import picocli.CommandLine; public class MetricCategoryConverter implements CommandLine.ITypeConverter { @@ -41,6 +42,11 @@ public & MetricCategory> void addCategories(final Class ca } public void addRegistryCategory(final MetricCategory metricCategory) { - metricCategories.put(metricCategory.getName(), metricCategory); + metricCategories.put(metricCategory.getName().toUpperCase(), metricCategory); + } + + @VisibleForTesting + Map getMetricCategories() { + return metricCategories; } } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/RetestethSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/RetestethSubCommand.java index d04b8d21cbf..f412da725fc 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/RetestethSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/RetestethSubCommand.java @@ -61,8 +61,8 @@ public class RetestethSubCommand implements Runnable { names = {"--logging", "-l"}, paramLabel = "", description = - "Logging verbosity levels: OFF, FATAL, WARN, INFO, DEBUG, TRACE, ALL (default: INFO)") - private final Level logLevel = null; + "Logging verbosity levels: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL (default: ${DEFAULT-VALUE})") + private final Level logLevel = LogManager.getRootLogger().getLevel(); @SuppressWarnings("FieldMayBeFinal") // Because PicoCLI requires Strings to not be final. @Option( diff --git a/besu/src/main/java/org/hyperledger/besu/cli/util/BesuCommandCustomFactory.java b/besu/src/main/java/org/hyperledger/besu/cli/util/BesuCommandCustomFactory.java new file mode 100644 index 00000000000..bb8a95d27cc --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/util/BesuCommandCustomFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.util; + +import org.hyperledger.besu.services.PluginVersionsProvider; + +import java.lang.reflect.Constructor; + +import picocli.CommandLine; + +/** + * Custom PicoCli IFactory to handle version provider construction with plugin versions. Based on + * same logic as PicoCLI DefaultFactory. + */ +public class BesuCommandCustomFactory implements CommandLine.IFactory { + private final PluginVersionsProvider pluginVersionsProvider; + + public BesuCommandCustomFactory(final PluginVersionsProvider pluginVersionsProvider) { + this.pluginVersionsProvider = pluginVersionsProvider; + } + + @SuppressWarnings("unchecked") + @Override + public T create(final Class cls) throws Exception { + if (CommandLine.IVersionProvider.class.isAssignableFrom(cls)) { + return (T) new VersionProvider(pluginVersionsProvider); + } + + final Constructor constructor = cls.getDeclaredConstructor(); + try { + return constructor.newInstance(); + } catch (Exception e) { + constructor.setAccessible(true); + return constructor.newInstance(); + } + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/util/VersionProvider.java b/besu/src/main/java/org/hyperledger/besu/cli/util/VersionProvider.java index 1fe287546c9..0f6dff3f809 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/util/VersionProvider.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/util/VersionProvider.java @@ -15,12 +15,24 @@ package org.hyperledger.besu.cli.util; import org.hyperledger.besu.BesuInfo; +import org.hyperledger.besu.services.PluginVersionsProvider; + +import java.util.stream.Stream; import picocli.CommandLine; public class VersionProvider implements CommandLine.IVersionProvider { + private final PluginVersionsProvider pluginVersionsProvider; + + public VersionProvider(final PluginVersionsProvider pluginVersionsProvider) { + this.pluginVersionsProvider = pluginVersionsProvider; + } + @Override public String[] getVersion() { - return new String[] {BesuInfo.version()}; + // the PluginVersionsProvider has registered plugins and their versions by this time. + return Stream.concat( + Stream.of(BesuInfo.version()), pluginVersionsProvider.getPluginVersions().stream()) + .toArray(String[]::new); } } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuController.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuController.java index d0520f2743b..452302ae48a 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuController.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuController.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethodFactory; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; @@ -31,11 +31,18 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration; +import java.io.Closeable; +import java.io.IOException; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public class BesuController implements java.io.Closeable { + private static final Logger LOG = LogManager.getLogger(); public static final String DATABASE_PATH = "database"; private final ProtocolSchedule protocolSchedule; @@ -45,12 +52,13 @@ public class BesuController implements java.io.Closeable { private final SubProtocolConfiguration subProtocolConfiguration; private final KeyPair keyPair; private final Synchronizer synchronizer; - private final JsonRpcMethodFactory additionalJsonRpcMethodsFactory; + private final JsonRpcMethods additionalJsonRpcMethodsFactory; private final TransactionPool transactionPool; private final MiningCoordinator miningCoordinator; private final PrivacyParameters privacyParameters; - private final Runnable close; + private final List closeables; + private final PluginServiceFactory additionalPluginServices; private final SyncState syncState; BesuController( @@ -64,9 +72,10 @@ public class BesuController implements java.io.Closeable { final TransactionPool transactionPool, final MiningCoordinator miningCoordinator, final PrivacyParameters privacyParameters, - final Runnable close, - final JsonRpcMethodFactory additionalJsonRpcMethodsFactory, - final KeyPair keyPair) { + final JsonRpcMethods additionalJsonRpcMethodsFactory, + final KeyPair keyPair, + final List closeables, + final PluginServiceFactory additionalPluginServices) { this.protocolSchedule = protocolSchedule; this.protocolContext = protocolContext; this.ethProtocolManager = ethProtocolManager; @@ -79,7 +88,8 @@ public class BesuController implements java.io.Closeable { this.transactionPool = transactionPool; this.miningCoordinator = miningCoordinator; this.privacyParameters = privacyParameters; - this.close = close; + this.closeables = closeables; + this.additionalPluginServices = additionalPluginServices; } public ProtocolContext getProtocolContext() { @@ -120,7 +130,15 @@ public MiningCoordinator getMiningCoordinator() { @Override public void close() { - close.run(); + closeables.forEach(this::tryClose); + } + + private void tryClose(final Closeable closeable) { + try { + closeable.close(); + } catch (IOException e) { + LOG.error("Unable to close resource.", e); + } } public PrivacyParameters getPrivacyParameters() { @@ -129,13 +147,17 @@ public PrivacyParameters getPrivacyParameters() { public Map getAdditionalJsonRpcMethods( final Collection enabledRpcApis) { - return additionalJsonRpcMethodsFactory.createJsonRpcMethods(enabledRpcApis); + return additionalJsonRpcMethodsFactory.create(enabledRpcApis); } public SyncState getSyncState() { return syncState; } + public PluginServiceFactory getAdditionalPluginServices() { + return additionalPluginServices; + } + public static class Builder { public BesuControllerBuilder fromEthNetworkConfig(final EthNetworkConfig ethNetworkConfig) { diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index b4baacbf6c9..c52bbadf5d9 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.crypto.SECP256K1.KeyPair; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethodFactory; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.GenesisState; @@ -52,6 +52,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import java.io.Closeable; import java.io.File; import java.io.IOException; import java.math.BigInteger; @@ -63,16 +64,8 @@ import java.util.Map; import java.util.Optional; import java.util.OptionalLong; -import java.util.concurrent.Executors; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; public abstract class BesuControllerBuilder { - - private static final Logger LOG = LogManager.getLogger(); - protected GenesisConfigFile genesisConfig; SynchronizerConfiguration syncConfig; EthProtocolConfiguration ethereumWireProtocolConfiguration; @@ -87,7 +80,6 @@ public abstract class BesuControllerBuilder { protected boolean isRevertReasonEnabled; GasLimitCalculator gasLimitCalculator; private StorageProvider storageProvider; - private final List shutdownActions = new ArrayList<>(); private boolean isPruningEnabled; private PruningConfiguration pruningConfiguration; Map genesisConfigOverrides; @@ -167,8 +159,8 @@ public BesuControllerBuilder isRevertReasonEnabled(final boolean isRevertReas return this; } - public BesuControllerBuilder isPruningEnabled(final boolean pruningEnabled) { - this.isPruningEnabled = pruningEnabled; + public BesuControllerBuilder isPruningEnabled(final boolean isPruningEnabled) { + this.isPruningEnabled = isPruningEnabled; return this; } @@ -238,27 +230,9 @@ public BesuController build() { storageProvider.createPruningStorage(), metricsSystem), blockchain, - Executors.newSingleThreadExecutor( - new ThreadFactoryBuilder() - .setDaemon(true) - .setPriority(Thread.MIN_PRIORITY) - .setNameFormat("StatePruning-%d") - .build()), pruningConfiguration)); } - final Optional finalMaybePruner = maybePruner; - addShutdownAction( - () -> - finalMaybePruner.ifPresent( - pruner -> { - try { - pruner.stop(); - } catch (final InterruptedException ie) { - throw new RuntimeException(ie); - } - })); - final boolean fastSyncEnabled = syncConfig.getSyncMode().equals(SyncMode.FAST); final EthProtocolManager ethProtocolManager = createEthProtocolManager( @@ -299,11 +273,21 @@ public BesuController build() { syncState, ethProtocolManager); + final PluginServiceFactory additionalPluginServices = + createAdditionalPluginServices(blockchain); + final SubProtocolConfiguration subProtocolConfiguration = createSubProtocolConfiguration(ethProtocolManager); - final JsonRpcMethodFactory additionalJsonRpcMethodFactory = + final JsonRpcMethods additionalJsonRpcMethodFactory = createAdditionalJsonRpcMethodFactory(protocolContext); + + List closeables = new ArrayList<>(); + closeables.add(storageProvider); + if (privacyParameters.getPrivateStorageProvider() != null) { + closeables.add(privacyParameters.getPrivateStorageProvider()); + } + return new BesuController<>( protocolSchedule, protocolContext, @@ -315,24 +299,15 @@ public BesuController build() { transactionPool, miningCoordinator, privacyParameters, - () -> { - shutdownActions.forEach(Runnable::run); - try { - storageProvider.close(); - if (privacyParameters.getPrivateStorageProvider() != null) { - privacyParameters.getPrivateStorageProvider().close(); - } - } catch (final IOException e) { - LOG.error("Failed to close storage provider", e); - } - }, additionalJsonRpcMethodFactory, - nodeKeys); + nodeKeys, + closeables, + additionalPluginServices); } protected void prepForBuild() {} - protected JsonRpcMethodFactory createAdditionalJsonRpcMethodFactory( + protected JsonRpcMethods createAdditionalJsonRpcMethodFactory( final ProtocolContext protocolContext) { return apis -> Collections.emptyMap(); } @@ -342,10 +317,6 @@ protected SubProtocolConfiguration createSubProtocolConfiguration( return new SubProtocolConfiguration().withSubProtocol(EthProtocol.get(), ethProtocolManager); } - final void addShutdownAction(final Runnable action) { - shutdownActions.add(action); - } - protected abstract MiningCoordinator createMiningCoordinator( ProtocolSchedule protocolSchedule, ProtocolContext protocolContext, @@ -398,4 +369,7 @@ private List createPeerValidators(final ProtocolSchedule proto return validators; } + + protected abstract PluginServiceFactory createAdditionalPluginServices( + final Blockchain blockchain); } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java index bc5ebd1bef9..ee70e2bc015 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java @@ -22,14 +22,14 @@ import org.hyperledger.besu.consensus.clique.blockcreation.CliqueBlockScheduler; import org.hyperledger.besu.consensus.clique.blockcreation.CliqueMinerExecutor; import org.hyperledger.besu.consensus.clique.blockcreation.CliqueMiningCoordinator; -import org.hyperledger.besu.consensus.clique.jsonrpc.CliqueJsonRpcMethodsFactory; +import org.hyperledger.besu.consensus.clique.jsonrpc.CliqueJsonRpcMethods; import org.hyperledger.besu.consensus.common.BlockInterface; import org.hyperledger.besu.consensus.common.EpochManager; import org.hyperledger.besu.consensus.common.VoteProposer; import org.hyperledger.besu.consensus.common.VoteTallyCache; import org.hyperledger.besu.consensus.common.VoteTallyUpdater; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethodFactory; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Address; @@ -42,10 +42,6 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -69,9 +65,9 @@ protected void prepForBuild() { } @Override - protected JsonRpcMethodFactory createAdditionalJsonRpcMethodFactory( + protected JsonRpcMethods createAdditionalJsonRpcMethodFactory( final ProtocolContext protocolContext) { - return new CliqueJsonRpcMethodsFactory(protocolContext); + return new CliqueJsonRpcMethods(protocolContext); } @Override @@ -82,11 +78,9 @@ protected MiningCoordinator createMiningCoordinator( final MiningParameters miningParameters, final SyncState syncState, final EthProtocolManager ethProtocolManager) { - final ExecutorService minerThreadPool = Executors.newCachedThreadPool(); final CliqueMinerExecutor miningExecutor = new CliqueMinerExecutor( protocolContext, - minerThreadPool, protocolSchedule, transactionPool.getPendingTransactions(), nodeKeys, @@ -108,16 +102,6 @@ protected MiningCoordinator createMiningCoordinator( // Clique mining is implicitly enabled. miningCoordinator.enable(); - addShutdownAction( - () -> { - miningCoordinator.disable(); - minerThreadPool.shutdownNow(); - try { - minerThreadPool.awaitTermination(5, TimeUnit.SECONDS); - } catch (final InterruptedException e) { - LOG.error("Failed to shutdown miner executor"); - } - }); return miningCoordinator; } @@ -139,6 +123,11 @@ protected void validateContext(final ProtocolContext context) { } } + @Override + protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) { + return new CliqueQueryPluginServiceFactory(blockchain); + } + @Override protected CliqueContext createConsensusContext( final Blockchain blockchain, final WorldStateArchive worldStateArchive) { diff --git a/besu/src/main/java/org/hyperledger/besu/controller/CliqueQueryPluginServiceFactory.java b/besu/src/main/java/org/hyperledger/besu/controller/CliqueQueryPluginServiceFactory.java new file mode 100644 index 00000000000..3099a24095e --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueQueryPluginServiceFactory.java @@ -0,0 +1,41 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import org.hyperledger.besu.consensus.clique.CliqueBlockInterface; +import org.hyperledger.besu.consensus.common.BlockInterface; +import org.hyperledger.besu.consensus.common.PoaQueryServiceImpl; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.plugin.services.metrics.PoAMetricsService; +import org.hyperledger.besu.plugin.services.query.PoaQueryService; +import org.hyperledger.besu.services.BesuPluginContextImpl; + +public class CliqueQueryPluginServiceFactory implements PluginServiceFactory { + + final Blockchain blockchain; + + public CliqueQueryPluginServiceFactory(final Blockchain blockchain) { + this.blockchain = blockchain; + } + + @Override + public void appendPluginServices(final BesuPluginContextImpl besuContext) { + final BlockInterface blockInterface = new CliqueBlockInterface(); + + final PoaQueryServiceImpl service = new PoaQueryServiceImpl(blockInterface, blockchain); + besuContext.addService(PoaQueryService.class, service); + besuContext.addService(PoAMetricsService.class, service); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index 993042caa2e..69a02796758 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -14,8 +14,6 @@ */ package org.hyperledger.besu.controller; -import static org.hyperledger.besu.ethereum.eth.manager.MonitoredExecutors.newScheduledThreadPool; - import org.hyperledger.besu.config.IbftConfigOptions; import org.hyperledger.besu.consensus.common.BlockInterface; import org.hyperledger.besu.consensus.common.EpochManager; @@ -28,6 +26,7 @@ import org.hyperledger.besu.consensus.ibft.IbftBlockInterface; import org.hyperledger.besu.consensus.ibft.IbftContext; import org.hyperledger.besu.consensus.ibft.IbftEventQueue; +import org.hyperledger.besu.consensus.ibft.IbftExecutors; import org.hyperledger.besu.consensus.ibft.IbftGossip; import org.hyperledger.besu.consensus.ibft.IbftProcessor; import org.hyperledger.besu.consensus.ibft.IbftProtocolSchedule; @@ -37,7 +36,7 @@ import org.hyperledger.besu.consensus.ibft.blockcreation.IbftBlockCreatorFactory; import org.hyperledger.besu.consensus.ibft.blockcreation.IbftMiningCoordinator; import org.hyperledger.besu.consensus.ibft.blockcreation.ProposerSelector; -import org.hyperledger.besu.consensus.ibft.jsonrpc.IbftJsonRpcMethodsFactory; +import org.hyperledger.besu.consensus.ibft.jsonrpc.IbftJsonRpcMethods; import org.hyperledger.besu.consensus.ibft.network.ValidatorPeers; import org.hyperledger.besu.consensus.ibft.payload.MessageFactory; import org.hyperledger.besu.consensus.ibft.protocol.IbftProtocolManager; @@ -49,7 +48,7 @@ import org.hyperledger.besu.consensus.ibft.statemachine.IbftRoundFactory; import org.hyperledger.besu.consensus.ibft.validation.MessageValidatorFactory; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethodFactory; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.MinedBlockObserver; @@ -66,11 +65,6 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.util.Subscribers; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -88,9 +82,9 @@ protected void prepForBuild() { } @Override - protected JsonRpcMethodFactory createAdditionalJsonRpcMethodFactory( + protected JsonRpcMethods createAdditionalJsonRpcMethodFactory( final ProtocolContext protocolContext) { - return new IbftJsonRpcMethodsFactory(protocolContext); + return new IbftJsonRpcMethods(protocolContext); } @Override @@ -110,6 +104,7 @@ protected MiningCoordinator createMiningCoordinator( final SyncState syncState, final EthProtocolManager ethProtocolManager) { final MutableBlockchain blockchain = protocolContext.getBlockchain(); + final IbftExecutors ibftExecutors = IbftExecutors.create(metricsSystem); final IbftBlockCreatorFactory blockCreatorFactory = new IbftBlockCreatorFactory( @@ -133,9 +128,6 @@ protected MiningCoordinator createMiningCoordinator( final IbftGossip gossiper = new IbftGossip(uniqueMessageMulticaster); - final ScheduledExecutorService timerExecutor = - newScheduledThreadPool("IbftTimerExecutor", 1, metricsSystem); - final IbftFinalState finalState = new IbftFinalState( voteTallyCache, @@ -143,9 +135,9 @@ protected MiningCoordinator createMiningCoordinator( Util.publicKeyToAddress(nodeKeys.getPublicKey()), proposerSelector, uniqueMessageMulticaster, - new RoundTimer(ibftEventQueue, ibftConfig.getRequestTimeoutSeconds(), timerExecutor), + new RoundTimer(ibftEventQueue, ibftConfig.getRequestTimeoutSeconds(), ibftExecutors), new BlockTimer( - ibftEventQueue, ibftConfig.getBlockPeriodSeconds(), timerExecutor, clock), + ibftEventQueue, ibftConfig.getBlockPeriodSeconds(), ibftExecutors, clock), blockCreatorFactory, new MessageFactory(nodeKeys), clock); @@ -184,32 +176,25 @@ protected MiningCoordinator createMiningCoordinator( final EventMultiplexer eventMultiplexer = new EventMultiplexer(ibftController); final IbftProcessor ibftProcessor = new IbftProcessor(ibftEventQueue, eventMultiplexer); - final ExecutorService processorExecutor = Executors.newSingleThreadExecutor(); - processorExecutor.execute(ibftProcessor); final MiningCoordinator ibftMiningCoordinator = - new IbftMiningCoordinator(ibftProcessor, blockCreatorFactory, blockchain, ibftEventQueue); + new IbftMiningCoordinator( + ibftExecutors, + ibftController, + ibftProcessor, + blockCreatorFactory, + blockchain, + ibftEventQueue); ibftMiningCoordinator.enable(); - addShutdownAction( - () -> { - ibftProcessor.stop(); - ibftMiningCoordinator.disable(); - processorExecutor.shutdownNow(); - try { - processorExecutor.awaitTermination(5, TimeUnit.SECONDS); - } catch (final InterruptedException e) { - LOG.error("Failed to shutdown ibft processor executor"); - } - timerExecutor.shutdownNow(); - try { - timerExecutor.awaitTermination(5, TimeUnit.SECONDS); - } catch (final InterruptedException e) { - LOG.error("Failed to shutdown timer executor"); - } - }); + return ibftMiningCoordinator; } + @Override + protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) { + return new IbftQueryPluginServiceFactory(blockchain); + } + @Override protected ProtocolSchedule createProtocolSchedule() { return IbftProtocolSchedule.create( diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java index 0450a97a65c..4fabc809689 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.consensus.ibftlegacy.protocol.Istanbul64ProtocolManager; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.blockcreation.NoopMiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; @@ -63,7 +64,7 @@ protected MiningCoordinator createMiningCoordinator( final MiningParameters miningParameters, final SyncState syncState, final EthProtocolManager ethProtocolManager) { - return null; + return new NoopMiningCoordinator(miningParameters); } @Override @@ -91,6 +92,11 @@ protected IbftContext createConsensusContext( return new IbftContext(voteTallyCache, voteProposer, blockInterface); } + @Override + protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) { + return new NoopPluginServiceFactory(); + } + @Override protected void validateContext(final ProtocolContext context) { final BlockHeader genesisBlockHeader = context.getBlockchain().getGenesisBlock().getHeader(); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftQueryPluginServiceFactory.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftQueryPluginServiceFactory.java new file mode 100644 index 00000000000..fc0451a5670 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftQueryPluginServiceFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import org.hyperledger.besu.consensus.common.BlockInterface; +import org.hyperledger.besu.consensus.ibft.IbftBlockInterface; +import org.hyperledger.besu.consensus.ibft.queries.IbftQueryServiceImpl; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.plugin.services.metrics.PoAMetricsService; +import org.hyperledger.besu.plugin.services.query.IbftQueryService; +import org.hyperledger.besu.plugin.services.query.PoaQueryService; +import org.hyperledger.besu.services.BesuPluginContextImpl; + +public class IbftQueryPluginServiceFactory implements PluginServiceFactory { + + final Blockchain blockchain; + + public IbftQueryPluginServiceFactory(final Blockchain blockchain) { + this.blockchain = blockchain; + } + + @Override + public void appendPluginServices(final BesuPluginContextImpl besuContext) { + final BlockInterface blockInterface = new IbftBlockInterface(); + + final IbftQueryServiceImpl service = new IbftQueryServiceImpl(blockInterface, blockchain); + besuContext.addService(IbftQueryService.class, service); + besuContext.addService(PoaQueryService.class, service); + besuContext.addService(PoAMetricsService.class, service); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java index 617c10c8aff..7e0ae138527 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java @@ -29,15 +29,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - public class MainnetBesuControllerBuilder extends BesuControllerBuilder { - private static final Logger LOG = LogManager.getLogger(); @Override protected MiningCoordinator createMiningCoordinator( @@ -47,11 +39,9 @@ protected MiningCoordinator createMiningCoordinator( final MiningParameters miningParameters, final SyncState syncState, final EthProtocolManager ethProtocolManager) { - final ExecutorService minerThreadPool = Executors.newCachedThreadPool(); final EthHashMinerExecutor executor = new EthHashMinerExecutor( protocolContext, - minerThreadPool, protocolSchedule, transactionPool.getPendingTransactions(), miningParameters, @@ -67,16 +57,7 @@ protected MiningCoordinator createMiningCoordinator( if (miningParameters.isMiningEnabled()) { miningCoordinator.enable(); } - addShutdownAction( - () -> { - miningCoordinator.disable(); - minerThreadPool.shutdownNow(); - try { - minerThreadPool.awaitTermination(5, TimeUnit.SECONDS); - } catch (final InterruptedException e) { - LOG.error("Failed to shutdown miner executor"); - } - }); + return miningCoordinator; } @@ -86,6 +67,11 @@ protected Void createConsensusContext( return null; } + @Override + protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) { + return new NoopPluginServiceFactory(); + } + @Override protected ProtocolSchedule createProtocolSchedule() { return MainnetProtocolSchedule.fromConfig( diff --git a/besu/src/main/java/org/hyperledger/besu/controller/NoopPluginServiceFactory.java b/besu/src/main/java/org/hyperledger/besu/controller/NoopPluginServiceFactory.java new file mode 100644 index 00000000000..7daba41e266 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/controller/NoopPluginServiceFactory.java @@ -0,0 +1,23 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import org.hyperledger.besu.services.BesuPluginContextImpl; + +public class NoopPluginServiceFactory implements PluginServiceFactory { + + @Override + public void appendPluginServices(final BesuPluginContextImpl besuContext) {} +} diff --git a/besu/src/main/java/org/hyperledger/besu/controller/PluginServiceFactory.java b/besu/src/main/java/org/hyperledger/besu/controller/PluginServiceFactory.java new file mode 100644 index 00000000000..b6dca4d1d37 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/controller/PluginServiceFactory.java @@ -0,0 +1,22 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import org.hyperledger.besu.services.BesuPluginContextImpl; + +public interface PluginServiceFactory { + + void appendPluginServices(BesuPluginContextImpl besuContext); +} diff --git a/besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java index 17a8d023898..aa6570d20cd 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java @@ -17,8 +17,13 @@ import org.hyperledger.besu.ethereum.eth.sync.BlockBroadcaster; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.PropagatedBlockContext; +import org.hyperledger.besu.plugin.data.Quantity; import org.hyperledger.besu.plugin.services.BesuEvents; +import java.util.function.Supplier; + public class BesuEventsImpl implements BesuEvents { private final BlockBroadcaster blockBroadcaster; private final TransactionPool transactionPool; @@ -36,7 +41,9 @@ public BesuEventsImpl( @Override public long addBlockPropagatedListener(final BlockPropagatedListener listener) { return blockBroadcaster.subscribePropagateNewBlocks( - block -> listener.onBlockPropagated(block.getHeader())); + (block, totalDifficulty) -> + listener.onBlockPropagated( + blockPropagatedContext(block::getHeader, () -> totalDifficulty))); } @Override @@ -68,11 +75,27 @@ public void removeTransactionDroppedListener(final long listenerIdentifier) { @Override public long addSyncStatusListener(final SyncStatusListener syncStatusListener) { - return syncState.addSyncStatusListener(syncStatusListener); + return syncState.subscribeSyncStatus(syncStatusListener); } @Override public void removeSyncStatusListener(final long listenerIdentifier) { - syncState.removeSyncStatusListener(listenerIdentifier); + syncState.unsubscribeSyncStatus(listenerIdentifier); + } + + private static PropagatedBlockContext blockPropagatedContext( + final Supplier blockHeaderSupplier, + final Supplier totalDifficultySupplier) { + return new PropagatedBlockContext() { + @Override + public BlockHeader getBlockHeader() { + return blockHeaderSupplier.get(); + } + + @Override + public Quantity getTotalDifficulty() { + return totalDifficultySupplier.get(); + } + }; } } diff --git a/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java index 73afdf2daa5..b6fb37525b8 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java @@ -27,6 +27,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -34,13 +35,14 @@ import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; +import java.util.function.Predicate; import java.util.stream.Stream; import com.google.common.annotations.VisibleForTesting; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class BesuPluginContextImpl implements BesuContext { +public class BesuPluginContextImpl implements BesuContext, PluginVersionsProvider { private static final Logger LOG = LogManager.getLogger(); @@ -57,6 +59,7 @@ private enum Lifecycle { private Lifecycle state = Lifecycle.UNINITIALIZED; private final Map, ? super Object> serviceRegistry = new HashMap<>(); private final List plugins = new ArrayList<>(); + private final List pluginVersions = new ArrayList<>(); public void addService(final Class serviceType, final T service) { checkArgument(serviceType.isInterface(), "Services must be Java interfaces."); @@ -89,6 +92,7 @@ public void registerPlugins(final Path pluginsDir) { try { plugin.register(this); LOG.debug("Registered plugin of type {}.", plugin.getClass().getName()); + addPluginVersion(plugin); } catch (final Exception e) { LOG.error( "Error registering plugin of type {}, start and stop will not be called. \n{}", @@ -104,6 +108,20 @@ public void registerPlugins(final Path pluginsDir) { state = Lifecycle.REGISTERED; } + private void addPluginVersion(final BesuPlugin plugin) { + final Package pluginPackage = plugin.getClass().getPackage(); + final String implTitle = + Optional.ofNullable(pluginPackage.getImplementationTitle()) + .filter(Predicate.not(String::isBlank)) + .orElse(plugin.getClass().getSimpleName()); + final String implVersion = + Optional.ofNullable(pluginPackage.getImplementationVersion()) + .filter(Predicate.not(String::isBlank)) + .orElse(""); + final String pluginVersion = implTitle + "/v" + implVersion; + pluginVersions.add(pluginVersion); + } + public void startPlugins() { checkState( state == Lifecycle.REGISTERED, @@ -153,6 +171,11 @@ public void stopPlugins() { state = Lifecycle.STOPPED; } + @Override + public Collection getPluginVersions() { + return Collections.unmodifiableList(pluginVersions); + } + private static URL pathToURIOrNull(final Path p) { try { return p.toUri().toURL(); diff --git a/besu/src/main/java/org/hyperledger/besu/services/PicoCLIOptionsImpl.java b/besu/src/main/java/org/hyperledger/besu/services/PicoCLIOptionsImpl.java index a77e3ca3c8d..5d4a0cb3cc4 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/PicoCLIOptionsImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/PicoCLIOptionsImpl.java @@ -16,10 +16,16 @@ import org.hyperledger.besu.plugin.services.PicoCLIOptions; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import picocli.CommandLine; +import picocli.CommandLine.Model.CommandSpec; +import picocli.CommandLine.Model.OptionSpec; public class PicoCLIOptionsImpl implements PicoCLIOptions { + private static final Logger LOG = LogManager.getLogger(); + private final CommandLine commandLine; public PicoCLIOptionsImpl(final CommandLine commandLine) { @@ -28,6 +34,24 @@ public PicoCLIOptionsImpl(final CommandLine commandLine) { @Override public void addPicoCLIOptions(final String namespace, final Object optionObject) { - commandLine.addMixin("Plugin " + namespace, optionObject); + final String pluginPrefix = "--plugin-" + namespace + "-"; + final String unstablePrefix = "--Xplugin-" + namespace + "-"; + final CommandSpec mixin = CommandSpec.forAnnotatedObject(optionObject); + boolean badOptionName = false; + + for (final OptionSpec optionSpec : mixin.options()) { + for (final String optionName : optionSpec.names()) { + if (!optionName.startsWith(pluginPrefix) && !optionName.startsWith(unstablePrefix)) { + badOptionName = true; + LOG.error( + "Plugin option {} did not have the expected prefix of {}", optionName, pluginPrefix); + } + } + } + if (badOptionName) { + throw new RuntimeException("Error loading CLI options"); + } else { + commandLine.getCommandSpec().addMixin("Plugin " + namespace, mixin); + } } } diff --git a/besu/src/main/java/org/hyperledger/besu/services/PluginVersionsProvider.java b/besu/src/main/java/org/hyperledger/besu/services/PluginVersionsProvider.java new file mode 100644 index 00000000000..a2a5fa75187 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/services/PluginVersionsProvider.java @@ -0,0 +1,21 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.services; + +import java.util.Collection; + +public interface PluginVersionsProvider { + Collection getPluginVersions(); +} diff --git a/besu/src/test/java/org/hyperledger/besu/BesuInfoTest.java b/besu/src/test/java/org/hyperledger/besu/BesuInfoTest.java index 0b6fcbf0479..8491702a644 100644 --- a/besu/src/test/java/org/hyperledger/besu/BesuInfoTest.java +++ b/besu/src/test/java/org/hyperledger/besu/BesuInfoTest.java @@ -16,6 +16,8 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.util.Optional; + import org.junit.Test; public final class BesuInfoTest { @@ -30,4 +32,29 @@ public final class BesuInfoTest { public void versionStringIsEthstatsFriendly() { assertThat(BesuInfo.version()).matches("[^/]+/v(\\d+\\.\\d+\\.\\d+[^/]*|null)/[^/]+/[^/]+"); } + + /** + * Ethstats wants a version string like <foo>/v<bar>/<baz>/<bif>. Foo is the + * client identity (besu, Geth, Parity, etc). Bar is the version, in semantic version form + * (1.2.3-whatever), baz is OS and chip architecture, and bif is "compiler" - which we use as JVM + * info. + */ + @Test + public void noIdentityNodeNameIsEthstatsFriendly() { + assertThat(BesuInfo.nodeName(Optional.empty())) + .matches("[^/]+/v(\\d+\\.\\d+\\.\\d+[^/]*|null)/[^/]+/[^/]+"); + } + + /** + * Ethstats also accepts a version string like + * <foo>/%lt;qux>/v<bar>/<baz>/<bif>. Foo is the client identity (besu, + * Geth, Parity, etc). Qux is user identity (PegaSysEng, Yes-EIP-1679, etc) Bar is the version, in + * semantic version form (1.2.3-whatever), baz is OS and chip architecture, and bif is "compiler" + * - which we use as JVM info. + */ + @Test + public void userIdentityNodeNameIsEthstatsFriendly() { + assertThat(BesuInfo.nodeName(Optional.of("TestUserIdentity"))) + .matches("[^/]+/[^/]+/v(\\d+\\.\\d+\\.\\d+[^/]*|null)/[^/]+/[^/]+"); + } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 55279d99736..8fa12d4a437 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -20,6 +20,7 @@ import static org.hyperledger.besu.cli.config.NetworkName.CLASSIC; import static org.hyperledger.besu.cli.config.NetworkName.DEV; import static org.hyperledger.besu.cli.config.NetworkName.GOERLI; +import static org.hyperledger.besu.cli.config.NetworkName.KOTTI; import static org.hyperledger.besu.cli.config.NetworkName.MAINNET; import static org.hyperledger.besu.cli.config.NetworkName.RINKEBY; import static org.hyperledger.besu.cli.config.NetworkName.ROPSTEN; @@ -996,6 +997,16 @@ public void genesisPathDisabledUnderDocker() { assertThat(commandOutput.toString()).isEmpty(); } + @Test + public void identityValueTrueMustBeUsed() { + parseCommand("--identity", "test"); + + verify(mockRunnerBuilder.identityString(eq(Optional.of("test")))).build(); + + assertThat(commandOutput.toString()).isEmpty(); + assertThat(commandErrorOutput.toString()).isEmpty(); + } + @Test public void p2pEnabledOptionValueTrueMustBeUsed() { parseCommand("--p2p-enabled", "true"); @@ -2318,7 +2329,29 @@ public void miningParametersAreCaptured() throws Exception { } @Test - public void pruningIsEnabledWhenSpecified() throws Exception { + public void pruningIsEnabledIfSyncModeIsFast() { + parseCommand("--sync-mode", "FAST"); + + verify(mockControllerBuilder).isPruningEnabled(true); + verify(mockControllerBuilder).build(); + + assertThat(commandOutput.toString()).isEmpty(); + assertThat(commandErrorOutput.toString()).isEmpty(); + } + + @Test + public void pruningIsDisabledIfSyncModeIsFull() { + parseCommand("--sync-mode", "FULL"); + + verify(mockControllerBuilder).isPruningEnabled(false); + verify(mockControllerBuilder).build(); + + assertThat(commandOutput.toString()).isEmpty(); + assertThat(commandErrorOutput.toString()).isEmpty(); + } + + @Test + public void pruningEnabledExplicitly() { parseCommand("--pruning-enabled"); verify(mockControllerBuilder).isPruningEnabled(true); @@ -2328,6 +2361,17 @@ public void pruningIsEnabledWhenSpecified() throws Exception { assertThat(commandErrorOutput.toString()).isEmpty(); } + @Test + public void pruningDisabledExplicitly() { + parseCommand("--pruning-enabled=false"); + + verify(mockControllerBuilder).isPruningEnabled(false); + verify(mockControllerBuilder).build(); + + assertThat(commandOutput.toString()).isEmpty(); + assertThat(commandErrorOutput.toString()).isEmpty(); + } + @Test public void pruningOptionsRequiresServiceToBeEnabled() { @@ -2437,6 +2481,22 @@ public void classicValuesAreUsed() throws Exception { assertThat(commandErrorOutput.toString()).isEmpty(); } + @Test + public void kottiValuesAreUsed() throws Exception { + parseCommand("--network", "kotti"); + + final ArgumentCaptor networkArg = + ArgumentCaptor.forClass(EthNetworkConfig.class); + + verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any()); + verify(mockControllerBuilder).build(); + + assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(KOTTI)); + + assertThat(commandOutput.toString()).isEmpty(); + assertThat(commandErrorOutput.toString()).isEmpty(); + } + @Test public void rinkebyValuesCanBeOverridden() throws Exception { networkValuesCanBeOverridden("rinkeby"); @@ -2462,6 +2522,11 @@ public void classicValuesCanBeOverridden() throws Exception { networkValuesCanBeOverridden("classic"); } + @Test + public void kottiValuesCanBeOverridden() throws Exception { + networkValuesCanBeOverridden("kotti"); + } + private void networkValuesCanBeOverridden(final String network) throws Exception { parseCommand( "--network", diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index 4de6e11bfd7..f28246fd427 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.cli.subcommands.blocks.BlocksSubCommand; import org.hyperledger.besu.controller.BesuController; import org.hyperledger.besu.controller.BesuControllerBuilder; +import org.hyperledger.besu.controller.NoopPluginServiceFactory; import org.hyperledger.besu.crypto.SECP256K1.KeyPair; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration; @@ -177,6 +178,9 @@ public void initMocks() throws Exception { lenient().when(mockController.getProtocolManager()).thenReturn(mockEthProtocolManager); lenient().when(mockController.getProtocolSchedule()).thenReturn(mockProtocolSchedule); lenient().when(mockController.getProtocolContext()).thenReturn(mockProtocolContext); + lenient() + .when(mockController.getAdditionalPluginServices()) + .thenReturn(new NoopPluginServiceFactory()); when(mockEthProtocolManager.getBlockBroadcaster()).thenReturn(mockBlockBroadcaster); @@ -203,6 +207,7 @@ public void initMocks() throws Exception { when(mockRunnerBuilder.metricsSystem(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.metricsConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.staticNodes(any())).thenReturn(mockRunnerBuilder); + when(mockRunnerBuilder.identityString(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.build()).thenReturn(mockRunner); when(storageService.getByName("rocksdb")).thenReturn(Optional.of(rocksDBStorageFactory)); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/PasswordSubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/PasswordSubCommandTest.java index 27c6abf10ff..db2630815cd 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/PasswordSubCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/PasswordSubCommandTest.java @@ -22,7 +22,7 @@ public class PasswordSubCommandTest extends CommandTestAbstract { @Test - public void passwordSubCommandExistAnbHaveSubCommands() { + public void passwordSubCommandExistsWithHashSubCommand() { final CommandSpec spec = parseCommand().getSpec(); assertThat(spec.subcommands()).containsKeys("password"); assertThat(spec.subcommands().get("password").getSubcommands()).containsKeys("hash"); @@ -39,7 +39,7 @@ public void passwordSubCommandExists() { } @Test - public void passwordHashSubCommandExist() { + public void passwordHashSubCommandExists() { parseCommand("password", "hash"); assertThat(commandOutput.toString()).isEmpty(); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/PublicKeySubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/PublicKeySubCommandTest.java index f5bb2e78f51..3b7f8fef4a1 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/PublicKeySubCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/PublicKeySubCommandTest.java @@ -79,7 +79,7 @@ public class PublicKeySubCommandTest extends CommandTestAbstract { // public-key sub-command @Test - public void publicKeySubCommandExistAnbHaveSubCommands() { + public void publicKeySubCommandExistsAndHasSubCommands() { CommandSpec spec = parseCommand().getSpec(); assertThat(spec.subcommands()).containsKeys(PUBLIC_KEY_SUBCOMMAND_NAME); assertThat(spec.subcommands().get(PUBLIC_KEY_SUBCOMMAND_NAME).getSubcommands()) diff --git a/besu/src/test/java/org/hyperledger/besu/cli/converter/MetricCategoryConverterTest.java b/besu/src/test/java/org/hyperledger/besu/cli/converter/MetricCategoryConverterTest.java new file mode 100644 index 00000000000..db34fb9d5e4 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/converter/MetricCategoryConverterTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.converter; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.plugin.services.metrics.MetricCategory; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class MetricCategoryConverterTest { + + private MetricCategoryConverter metricCategoryConverter; + + @Mock MetricCategory metricCategory; + + @Before + public void setUp() { + metricCategoryConverter = new MetricCategoryConverter(); + } + + @Test + public void convertShouldFailIfValueNotRegistered() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> metricCategoryConverter.convert("notRegistered")); + } + + @Test + public void addRegistryCategoryShouldUppercaseInputValues() { + when(metricCategory.getName()).thenReturn("testcat"); + metricCategoryConverter.addRegistryCategory(metricCategory); + when(metricCategory.getName()).thenReturn("tesTCat2"); + metricCategoryConverter.addRegistryCategory(metricCategory); + + final boolean containsLowercase = + metricCategoryConverter.getMetricCategories().keySet().stream() + .anyMatch(testString -> testString.chars().anyMatch(Character::isLowerCase)); + + assertThat(containsLowercase).isFalse(); + assertThat(metricCategoryConverter.getMetricCategories().size()).isEqualTo(2); + assertThat(metricCategoryConverter.getMetricCategories().keySet()) + .containsExactlyInAnyOrder("TESTCAT", "TESTCAT2"); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/cli/rlp/RLPSubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/rlp/RLPSubCommandTest.java index f40603cc3e9..27c3e62c030 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/rlp/RLPSubCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/rlp/RLPSubCommandTest.java @@ -66,7 +66,7 @@ public class RLPSubCommandTest extends CommandTestAbstract { // RLP sub-command @Test - public void rlpSubCommandExistAnbHaveSubCommands() { + public void rlpSubCommandExistsAndHasSubCommands() { final CommandSpec spec = parseCommand().getSpec(); assertThat(spec.subcommands()).containsKeys(RLP_SUBCOMMAND_NAME); assertThat(spec.subcommands().get(RLP_SUBCOMMAND_NAME).getSubcommands()) diff --git a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java index 1fda617e7bc..1fda465fc25 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java @@ -103,7 +103,7 @@ public class BlocksSubCommandTest extends CommandTestAbstract { // Block sub-command @Test - public void blockSubCommandExistAnbHaveSubCommands() { + public void blockSubCommandExistsAndHasSubCommands() { CommandSpec spec = parseCommand().getSpec(); assertThat(spec.subcommands()).containsKeys(BLOCK_SUBCOMMAND_NAME); assertThat(spec.subcommands().get(BLOCK_SUBCOMMAND_NAME).getSubcommands()) diff --git a/besu/src/test/java/org/hyperledger/besu/cli/util/BesuCommandCustomFactoryTest.java b/besu/src/test/java/org/hyperledger/besu/cli/util/BesuCommandCustomFactoryTest.java new file mode 100644 index 00000000000..9f8e46d8032 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/util/BesuCommandCustomFactoryTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.BesuInfo; +import org.hyperledger.besu.services.PluginVersionsProvider; + +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class BesuCommandCustomFactoryTest { + + @Mock private PluginVersionsProvider pluginVersionsProvider; + + @Before + public void initMocks() { + when(pluginVersionsProvider.getPluginVersions()).thenReturn(Arrays.asList("v1", "v2")); + } + + @Test + public void testCreateVersionProviderInstance() throws Exception { + final BesuCommandCustomFactory besuCommandCustomFactory = + new BesuCommandCustomFactory(pluginVersionsProvider); + final VersionProvider versionProvider = besuCommandCustomFactory.create(VersionProvider.class); + assertThat(versionProvider.getVersion()).containsExactly(BesuInfo.version(), "v1", "v2"); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/cli/util/VersionProviderTest.java b/besu/src/test/java/org/hyperledger/besu/cli/util/VersionProviderTest.java new file mode 100644 index 00000000000..8b4b8dece87 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/util/VersionProviderTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.util; + +import static java.util.Collections.emptyList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.BesuInfo; +import org.hyperledger.besu.services.PluginVersionsProvider; + +import java.util.Collections; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class VersionProviderTest { + + @Mock private PluginVersionsProvider pluginVersionsProvider; + + @Test + public void validateEmptyListGenerateBesuInfoVersionOnly() { + when(pluginVersionsProvider.getPluginVersions()).thenReturn(emptyList()); + final VersionProvider versionProvider = new VersionProvider(pluginVersionsProvider); + assertThat(versionProvider.getVersion()).containsOnly(BesuInfo.version()); + } + + @Test + public void validateVersionListGenerateValidValues() { + when(pluginVersionsProvider.getPluginVersions()).thenReturn(Collections.singletonList("test")); + final VersionProvider versionProvider = new VersionProvider(pluginVersionsProvider); + assertThat(versionProvider.getVersion()).containsExactly(BesuInfo.version(), "test"); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/plugins/BadCLIOptionsPlugin.java b/besu/src/test/java/org/hyperledger/besu/plugins/BadCLIOptionsPlugin.java new file mode 100644 index 00000000000..ae40a95b834 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/plugins/BadCLIOptionsPlugin.java @@ -0,0 +1,84 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.plugins; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import org.hyperledger.besu.plugin.BesuContext; +import org.hyperledger.besu.plugin.BesuPlugin; +import org.hyperledger.besu.plugin.services.PicoCLIOptions; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import com.google.auto.service.AutoService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import picocli.CommandLine.Option; + +@AutoService(BesuPlugin.class) +public class BadCLIOptionsPlugin implements BesuPlugin { + private static final Logger LOG = LogManager.getLogger(); + + @Option(names = "--poorly-named-option") + String poorlyNamedOption = "nothing"; + + private File callbackDir; + + @Override + public void register(final BesuContext context) { + LOG.info("Registering BadCliOptionsPlugin"); + callbackDir = new File(System.getProperty("besu.plugins.dir", "plugins")); + writeStatus("init"); + + context + .getService(PicoCLIOptions.class) + .ifPresent( + picoCLIOptions -> + picoCLIOptions.addPicoCLIOptions("bad-cli", BadCLIOptionsPlugin.this)); + + writeStatus("register"); + } + + @Override + public void start() { + LOG.info("Starting BadCliOptionsPlugin"); + writeStatus("start"); + } + + @Override + public void stop() { + LOG.info("Stopping BadCliOptionsPlugin"); + writeStatus("stop"); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + private void writeStatus(final String status) { + try { + final File callbackFile = new File(callbackDir, "badCLIOptions." + status); + if (!callbackFile.getParentFile().exists()) { + callbackFile.getParentFile().mkdirs(); + callbackFile.getParentFile().deleteOnExit(); + } + Files.write(callbackFile.toPath(), status.getBytes(UTF_8)); + callbackFile.deleteOnExit(); + LOG.info("Write status " + status); + } catch (final IOException ioe) { + throw new RuntimeException(ioe); + } + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/plugins/TestBesuEventsPlugin.java b/besu/src/test/java/org/hyperledger/besu/plugins/TestBesuEventsPlugin.java index 2eded498519..79cdd096016 100644 --- a/besu/src/test/java/org/hyperledger/besu/plugins/TestBesuEventsPlugin.java +++ b/besu/src/test/java/org/hyperledger/besu/plugins/TestBesuEventsPlugin.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.plugin.BesuContext; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.PropagatedBlockContext; import org.hyperledger.besu.plugin.services.BesuEvents; import java.io.File; @@ -66,7 +67,8 @@ public void stop() { LOG.info("No longer listening with ID#" + subscriptionId); } - private void onBlockAnnounce(final BlockHeader header) { + private void onBlockAnnounce(final PropagatedBlockContext propagatedBlockContext) { + final BlockHeader header = propagatedBlockContext.getBlockHeader(); final int blockCount = blockCounter.incrementAndGet(); LOG.info("I got a new block! (I've seen {}) - {}", blockCount, header); try { diff --git a/besu/src/test/java/org/hyperledger/besu/plugins/TestPicoCLIPlugin.java b/besu/src/test/java/org/hyperledger/besu/plugins/TestPicoCLIPlugin.java index 244f1fdbfc0..37192404dab 100644 --- a/besu/src/test/java/org/hyperledger/besu/plugins/TestPicoCLIPlugin.java +++ b/besu/src/test/java/org/hyperledger/besu/plugins/TestPicoCLIPlugin.java @@ -32,9 +32,18 @@ public class TestPicoCLIPlugin implements BesuPlugin { private static final Logger LOG = LogManager.getLogger(); - @Option(names = "--Xtest-option", hidden = true, defaultValue = "UNSET") + @Option( + names = {"--Xplugin-test-option"}, + hidden = true, + defaultValue = "UNSET") String testOption = System.getProperty("testPicoCLIPlugin.testOption"); + @Option( + names = {"--plugin-test-stable-option"}, + hidden = true, + defaultValue = "UNSET") + String stableOption = ""; + private String state = "uninited"; private File callbackDir; @@ -51,8 +60,7 @@ public void register(final BesuContext context) { context .getService(PicoCLIOptions.class) .ifPresent( - picoCLIOptions -> - picoCLIOptions.addPicoCLIOptions("Test PicoCLI Plugin", TestPicoCLIPlugin.this)); + picoCLIOptions -> picoCLIOptions.addPicoCLIOptions("test", TestPicoCLIPlugin.this)); callbackDir = new File(System.getProperty("besu.plugins.dir", "plugins")); writeSignal("registered"); @@ -93,6 +101,7 @@ public String getState() { } /** This is used to signal to the acceptance test that certain tasks were completed. */ + @SuppressWarnings("ResultOfMethodCallIgnored") private void writeSignal(final String signal) { try { final File callbackFile = new File(callbackDir, "pluginLifecycle." + signal); diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index ae10ca5ad6f..9eba7c60959 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.SECP256K1.KeyPair; @@ -30,6 +31,7 @@ import org.hyperledger.besu.ethereum.core.WorldState; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthMessages; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.sync.BlockBroadcaster; @@ -43,7 +45,7 @@ import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.PropagatedBlockContext; import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.plugin.data.Transaction; import org.hyperledger.besu.testutil.TestClock; @@ -122,46 +124,71 @@ public void setUp() { @Test public void syncStatusEventFiresAfterSubscribe() { - final AtomicReference result = new AtomicReference<>(); + final AtomicReference> result = new AtomicReference<>(); serviceImpl.addSyncStatusListener(result::set); assertThat(result.get()).isNull(); - syncState.publishSyncStatus(); + setSyncTarget(); + assertThat(result.get()).isNotNull(); + + // Reset result for next event + result.set(null); + + clearSyncTarget(); assertThat(result.get()).isNotNull(); } @Test public void syncStatusEventDoesNotFireAfterUnsubscribe() { - final AtomicReference result = new AtomicReference<>(); + final AtomicReference> result = new AtomicReference<>(); final long id = serviceImpl.addSyncStatusListener(result::set); - syncState.publishSyncStatus(); + + assertThat(result.get()).isNull(); + setSyncTarget(); assertThat(result.get()).isNotNull(); + + // Reset result for next event result.set(null); + // And remove listener serviceImpl.removeSyncStatusListener(id); - syncState.publishSyncStatus(); + + clearSyncTarget(); assertThat(result.get()).isNull(); } + private void setSyncTarget() { + syncState.setSyncTarget(mock(EthPeer.class), fakeBlockHeader); + } + + private void clearSyncTarget() { + syncState.clearSyncTarget(); + } + @Test public void newBlockEventFiresAfterSubscribe() { - final AtomicReference result = new AtomicReference<>(); + final AtomicReference result = new AtomicReference<>(); serviceImpl.addBlockPropagatedListener(result::set); - + final Block block = generateBlock(); assertThat(result.get()).isNull(); - blockBroadcaster.propagate(generateBlock(), UInt256.of(1)); + blockBroadcaster.propagate(block, UInt256.of(1)); assertThat(result.get()).isNotNull(); + assertThat(result.get().getBlockHeader()).isEqualTo(block.getHeader()); + assertThat(result.get().getTotalDifficulty()).isEqualTo(UInt256.of(1)); } @Test public void newBlockEventDoesNotFireAfterUnsubscribe() { - final AtomicReference result = new AtomicReference<>(); + final AtomicReference result = new AtomicReference<>(); final long id = serviceImpl.addBlockPropagatedListener(result::set); assertThat(result.get()).isNull(); - blockBroadcaster.propagate(generateBlock(), UInt256.of(1)); + final Block block = generateBlock(); + blockBroadcaster.propagate(block, UInt256.of(2)); assertThat(result.get()).isNotNull(); + assertThat(result.get().getBlockHeader()).isEqualTo(block.getHeader()); + assertThat(result.get().getTotalDifficulty()).isEqualTo(UInt256.of(2)); serviceImpl.removeBlockPropagatedListener(id); result.set(null); diff --git a/besu/src/test/java/org/hyperledger/besu/services/PicoCLIOptionsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/PicoCLIOptionsImplTest.java index f0daf2f5668..e19db8f2e13 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/PicoCLIOptionsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/PicoCLIOptionsImplTest.java @@ -34,7 +34,7 @@ static final class SimpleCommand { } static final class MixinOptions { - @Option(names = "--mixin") + @Option(names = "--plugin-Test1-mixin") String mixinOption = "defaultmixin"; } @@ -44,18 +44,18 @@ static final class MixinOptions { private PicoCLIOptionsImpl serviceImpl; @Before - public void setUp() throws Exception { + public void setUp() { command = new SimpleCommand(); mixin = new MixinOptions(); commandLine = new CommandLine(command); serviceImpl = new PicoCLIOptionsImpl(commandLine); - serviceImpl.addPicoCLIOptions("Test 1", mixin); + serviceImpl.addPicoCLIOptions("Test1", mixin); } @Test public void testSimpleOptionParse() { - commandLine.parseArgs("--existing", "1", "--mixin", "2"); + commandLine.parseArgs("--existing", "1", "--plugin-Test1-mixin", "2"); assertThat(command.existingOption).isEqualTo("1"); assertThat(mixin.mixinOption).isEqualTo("2"); } @@ -69,7 +69,7 @@ public void testUnsetOptionLeavesDefault() { @Test public void testMixinOptionOnly() { - commandLine.parseArgs("--mixin", "2"); + commandLine.parseArgs("--plugin-Test1-mixin", "2"); assertThat(command.existingOption).isEqualTo("defaultexisting"); assertThat(mixin.mixinOption).isEqualTo("2"); } diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index d77d6bb25bd..b480d4f1253 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -14,6 +14,7 @@ logging="INFO" node-private-key-file="./path/to/privateKey" # P2P network +identity="PegaSysEng" p2p-enabled=true nat-method="NONE" discovery-enabled=false @@ -82,6 +83,9 @@ miner-coinbase="0x0000000000000000000000000000000000000002" miner-extra-data="0x444F4E27542050414E4943202120484F444C2C20484F444C2C20484F444C2021" min-gas-price=1 +# Pruning +pruning-enabled=true + # Permissioning permissions-nodes-config-file-enabled=false permissions-nodes-config-file="./permissions_config.toml" diff --git a/build.gradle b/build.gradle index 0a9dff7ad2c..7d012631385 100644 --- a/build.gradle +++ b/build.gradle @@ -18,9 +18,9 @@ import net.ltgt.gradle.errorprone.CheckSeverity import java.text.SimpleDateFormat plugins { - id 'com.diffplug.gradle.spotless' version '3.23.1' + id 'com.diffplug.gradle.spotless' version '3.25.0' id 'com.jfrog.bintray' version '1.8.4' - id 'com.github.ben-manes.versions' version '0.21.0' + id 'com.github.ben-manes.versions' version '0.26.0' id 'com.github.hierynomus.license' version '0.15.0' id 'io.spring.dependency-management' version '1.0.8.RELEASE' id 'me.champeau.gradle.jmh' version '0.4.8' apply false @@ -236,7 +236,7 @@ allprojects { */ test { jvmArgs = [ - '-Xmx4g', + '-Xmx2g', '-XX:-UseGCOverheadLimit', // Mockito and jackson-databind do some strange reflection during tests. // This suppresses an illegal access warning. @@ -268,7 +268,7 @@ allprojects { task deploy() {} -task checkMavenCoordianteCollisions { +task checkMavenCoordinateCollisions { doLast { def coordinates = [:] getAllprojects().forEach { @@ -276,8 +276,8 @@ task checkMavenCoordianteCollisions { def coordinate = it.publishing?.publications[0].coordinates if (coordinates.containsKey(coordinate)) { throw new GradleException("Duplicate maven coordinates detected, ${coordinate} is used by " + - "both ${coordinates[coordinate]} and ${it.path}.\n" + - "Please add a `publishing` script block to one or both subprojects.") + "both ${coordinates[coordinate]} and ${it.path}.\n" + + "Please add a `publishing` script block to one or both subprojects.") } coordinates[coordinate] = it.path } @@ -287,7 +287,7 @@ task checkMavenCoordianteCollisions { tasks.register('checkPluginAPIChanges', DefaultTask) { } checkPluginAPIChanges.dependsOn(':plugin-api:checkAPIChanges') -check.dependsOn('checkPluginAPIChanges', 'checkMavenCoordianteCollisions') +check.dependsOn('checkPluginAPIChanges', 'checkMavenCoordinateCollisions') subprojects { @@ -548,6 +548,30 @@ task distDocker(type: Exec) { args "-c", "docker build --build-arg BUILD_DATE=${buildTime()} --build-arg VERSION=${dockerBuildVersion} --build-arg VCS_REF=${getCheckedOutGitCommitHash()} -t ${image} ." } +task dockerUpload(type: Exec) { + dependsOn distDocker + def dockerBuildVersion = project.hasProperty('release.releaseVersion') ? project.property('release.releaseVersion') : "${rootProject.version}" + def imageName = "hyperledger/besu" + def image = project.hasProperty('release.releaseVersion') ? "${imageName}:" + project.property('release.releaseVersion') : "${imageName}:${project.version}" + def cmd = "docker push '${image}'" + def additionalTags = [] + + if (project.hasProperty('branch') && project.property('branch') == 'master') { + additionalTags.add('develop') + } + + if (! version ==~ /.*-SNAPSHOT/) { + additionalTags.add('latest') + additionalTags.add(version.split(/\./)[0..1].join('.')) + } + + additionalTags.each { tag -> + cmd += " && docker tag '${image}' '${imageName}:${tag.trim()}' && docker push '${imageName}:${tag.trim()}'" + } + executable "sh" + args "-c", cmd +} + task checkSpdxHeader(type: CheckSpdxHeader) { apply plugin: 'groovy' diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java index 21e8609448e..a1c95b9d2fd 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java @@ -56,6 +56,67 @@ public interface GenesisConfigOptions { OptionalLong getIstanbulBlockNumber(); + /** + * Block number for ECIP-1015 fork on Classic network ECIP-1015: Long-term gas cost changes for + * IO-heavy operations to mitigate transaction spam attacks In reference to EIP-150 (ETH Tangerine + * Whistle) Note, this fork happens after Homestead (Mainnet definition) and before DieHard fork + * + * @see https://ecips.ethereumclassic.org/ECIPs/ecip-1015 + * @return block number to activate ECIP-1015 code + */ + OptionalLong getEcip1015BlockNumber(); + + /** + * Block number for DieHard fork on Classic network The DieHard fork includes changes to meet + * specification for ECIP-1010 and EIP-160 Note, this fork happens after ECIP-1015 (classic + * tangerine whistle) and before Gotham fork ECIP-1010: Delay Difficulty Bomb Explosion + * + * @see https://ecips.ethereumclassic.org/ECIPs/ecip-1010 + * EIP-160: EXP cost increase + * @see https://eips.ethereum.org/EIPS/eip-160 + * @return block number to activate Classic DieHard fork + */ + OptionalLong getDieHardBlockNumber(); + + // TODO edwardmack, Add gotham fork block number here + + /** + * Block number to remove difficulty bomb on Classic network The DefuseDifficultyBomb fork + * includes changes to meet specification for ECIP-1041 Note, this fork happen after Gotham fork + * and before Atlantis fork ECIP-1041: Remove Difficulty Bomb + * + * @see https://ecips.ethereumclassic.org/ECIPs/ecip-1041 + * @return block number to activate Defuse Difficulty Bomb fork on Classic + */ + OptionalLong getDefuseDifficultyBombBlockNumber(); + + /** + * Block number for Atlantis fork on Classic network Note, this fork happen after Defuse + * Difficulty Bomb fork and before Agharta fork ECIP-1054: Atlantis EVM and Protocol Upgrades + * Enable the outstanding Ethereum Foundation Spurious Dragon and Byzantium network protocol + * upgrades for the Ethereum Classic network. + * + * @see https://ecips.ethereumclassic.org/ECIPs/ecip-1054 + * @return block number for Atlantis fork on Classic network + */ + OptionalLong getAtlantisBlockNumber(); + + /** + * Block number for Agharta fork on Classic network Note, this fork happen after Atlantis fork + * ECIP-1056: Agharta EVM and Protocol Upgrades Enable the outstanding Ethereum Foundation + * Constaninople and Petersburg network protocol upgrades for the Ethereum Classic network. + * + * @see https://ecips.ethereumclassic.org/ECIPs/ecip-1056 + * @return block number for Agharta fork on Classic network + */ + OptionalLong getAghartaBlockNumber(); + Optional getChainId(); OptionalInt getContractSizeLimit(); @@ -63,8 +124,4 @@ public interface GenesisConfigOptions { OptionalInt getEvmStackSize(); Map asMap(); - - OptionalLong getAtlantisBlockNumber(); - - OptionalLong getAghartaBlockNumber(); } diff --git a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java index 481b9b5295f..10c413e8247 100644 --- a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java @@ -160,18 +160,18 @@ public OptionalLong getIstanbulBlockNumber() { } @Override - public Optional getChainId() { - return getOptionalBigInteger("chainid"); + public OptionalLong getEcip1015BlockNumber() { + return getOptionalLong("ecip1015block"); } @Override - public OptionalInt getContractSizeLimit() { - return getOptionalInt("contractsizelimit"); + public OptionalLong getDieHardBlockNumber() { + return getOptionalLong("diehardblock"); } @Override - public OptionalInt getEvmStackSize() { - return getOptionalInt("evmstacksize"); + public OptionalLong getDefuseDifficultyBombBlockNumber() { + return getOptionalLong("ecip1041block"); } @Override @@ -184,6 +184,21 @@ public OptionalLong getAghartaBlockNumber() { return getOptionalLong("aghartablock"); } + @Override + public Optional getChainId() { + return getOptionalBigInteger("chainid"); + } + + @Override + public OptionalInt getContractSizeLimit() { + return getOptionalInt("contractsizelimit"); + } + + @Override + public OptionalInt getEvmStackSize() { + return getOptionalInt("evmstacksize"); + } + @Override public Map asMap() { final ImmutableMap.Builder builder = ImmutableMap.builder(); diff --git a/config/src/main/resources/classic.json b/config/src/main/resources/classic.json index eb69076eade..124b24fe044 100644 --- a/config/src/main/resources/classic.json +++ b/config/src/main/resources/classic.json @@ -2,15 +2,10 @@ "config": { "chainId": 61, "homesteadBlock": 1150000, - "daoForkBlock": 1920000, - "daoForkSupport": true, - "eip150Block": 2463000, - "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", - "eip155Block": 2675000, - "eip158Block": 2675000, - "byzantiumBlock": 4370000, - "constantinopleBlock": 7280000, - "constantinopleFixBlock": 7280000, + "ecip1015Block": 2500000, + "eip150Hash": "0xca12c63534f565899681965528d536c52cb05b7c48e269c2a6cb77ad864d878a", + "diehardBlock": 3000000, + "ecip1041Block": 5900000, "atlantisBlock": 8772000, "aghartaBlock": 9200000, "ethash": { diff --git a/config/src/main/resources/kotti.json b/config/src/main/resources/kotti.json new file mode 100644 index 00000000000..249302b7c69 --- /dev/null +++ b/config/src/main/resources/kotti.json @@ -0,0 +1,801 @@ +{ + "config": { + "chainId": 6, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x14c2283285a88fe5fce9bf5c573ab03d6616695d717b12a127188bcacfc743c4", + "eip158Block": 0, + "eip160Block": 0, + "atlantisBlock": 716617, + "clique":{ + "blockperiodseconds":15, + "epochlength":30000 + } + }, + "nonce": "0x0", + "timestamp": "0x5c2d2287", + "extraData": "0x000000000000000000000000000000000000000000000000000000000000000025b7955e43adf9c2a01a9475908702cce67f302a6aaf8cba3c9255a2b863415d4db7bae4f4bbca020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0xa00000", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000000000": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000001": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000002": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000003": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000004": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000005": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000006": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000007": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000008": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000009": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000010": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000011": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000012": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000013": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000014": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000015": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000016": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000017": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000018": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000019": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000020": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000021": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000022": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000023": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000024": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000025": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000026": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000027": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000028": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000029": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000030": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000031": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000032": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000033": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000034": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000035": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000036": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000037": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000038": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000039": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000040": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000041": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000042": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000043": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000044": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000045": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000046": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000047": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000048": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000049": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000050": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000051": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000052": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000053": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000054": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000055": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000056": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000057": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000058": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000059": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000060": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000061": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000062": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000063": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000064": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000065": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000066": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000067": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000068": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000069": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000070": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000071": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000072": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000073": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000074": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000075": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000076": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000077": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000078": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000079": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000080": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000081": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000082": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000083": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000084": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000085": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000086": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000087": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000088": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000089": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000090": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000091": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000092": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000093": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000094": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000095": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000096": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000097": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000098": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000099": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009f": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000aa": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ab": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ac": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ad": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ae": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000af": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ba": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000be": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bf": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ca": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ce": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cf": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000da": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000db": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000dc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000dd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000de": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000df": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ea": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000eb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ec": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ed": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ee": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ef": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fa": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fe": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ff": { + "balance": "0x1" + }, + "25b7955e43adf9c2a01a9475908702cce67f302a": { + "balance": "0x84595161401484a000000" + }, + "6aaf8cba3c9255a2b863415d4db7bae4f4bbca02": { + "balance": "0x4a723dc6b40b8a9a000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/config/src/main/resources/mainnet.json b/config/src/main/resources/mainnet.json index 925b6e575cd..14095498c2d 100644 --- a/config/src/main/resources/mainnet.json +++ b/config/src/main/resources/mainnet.json @@ -11,6 +11,7 @@ "byzantiumBlock": 4370000, "constantinopleBlock": 7280000, "constantinopleFixBlock": 7280000, + "istanbulBlock": 9069000, "ethash": { } diff --git a/config/src/test-support/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java b/config/src/test-support/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java index c72002897c3..07cbc9ada79 100644 --- a/config/src/test-support/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java +++ b/config/src/test-support/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java @@ -32,11 +32,14 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions { private OptionalLong constantinopleBlockNumber = OptionalLong.empty(); private OptionalLong constantinopleFixBlockNumber = OptionalLong.empty(); private OptionalLong istanbulBlockNumber = OptionalLong.empty(); + private OptionalLong ecip1015BlockNumber = OptionalLong.empty(); + private OptionalLong diehardBlockNumber = OptionalLong.empty(); + private OptionalLong defuseDifficultyBombBlockNumber = OptionalLong.empty(); + private OptionalLong atlantisBlockNumber = OptionalLong.empty(); + private OptionalLong aghartaBlockNumber = OptionalLong.empty(); private Optional chainId = Optional.empty(); private OptionalInt contractSizeLimit = OptionalInt.empty(); private OptionalInt stackSizeLimit = OptionalInt.empty(); - private OptionalLong atlantisBlockNumber = OptionalLong.empty(); - private OptionalLong aghartaBlockNumber = OptionalLong.empty(); @Override public String getConsensusEngine() { @@ -124,18 +127,18 @@ public OptionalLong getIstanbulBlockNumber() { } @Override - public OptionalInt getContractSizeLimit() { - return contractSizeLimit; + public OptionalLong getEcip1015BlockNumber() { + return ecip1015BlockNumber; } @Override - public OptionalInt getEvmStackSize() { - return stackSizeLimit; + public OptionalLong getDieHardBlockNumber() { + return diehardBlockNumber; } @Override - public Optional getChainId() { - return chainId; + public OptionalLong getDefuseDifficultyBombBlockNumber() { + return defuseDifficultyBombBlockNumber; } @Override @@ -148,6 +151,21 @@ public OptionalLong getAghartaBlockNumber() { return aghartaBlockNumber; } + @Override + public OptionalInt getContractSizeLimit() { + return contractSizeLimit; + } + + @Override + public OptionalInt getEvmStackSize() { + return stackSizeLimit; + } + + @Override + public Optional getChainId() { + return chainId; + } + @Override public Map asMap() { final ImmutableMap.Builder builder = ImmutableMap.builder(); diff --git a/consensus/clique/build.gradle b/consensus/clique/build.gradle index b2ed7cbf04e..059a87f8fc8 100644 --- a/consensus/clique/build.gradle +++ b/consensus/clique/build.gradle @@ -40,7 +40,6 @@ dependencies { implementation project(':ethereum:rlp') implementation project(':ethereum:p2p') implementation project(':services:kvstore') - implementation project(':consensus:common') implementation project(':util') implementation 'io.vertx:vertx-core' diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueContext.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueContext.java index f54eaca00be..a849f0657ff 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueContext.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueContext.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.consensus.common.BlockInterface; import org.hyperledger.besu.consensus.common.EpochManager; -import org.hyperledger.besu.consensus.common.PoAContext; +import org.hyperledger.besu.consensus.common.PoaContext; import org.hyperledger.besu.consensus.common.VoteProposer; import org.hyperledger.besu.consensus.common.VoteTallyCache; @@ -24,7 +24,7 @@ * Holds the data which lives "in parallel" with the importation of blocks etc. when using the * Clique consensus mechanism. */ -public class CliqueContext implements PoAContext { +public class CliqueContext implements PoaContext { private final VoteTallyCache voteTallyCache; private final VoteProposer voteProposer; diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java index 0a449fdafb4..f1d97a634b9 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java @@ -35,7 +35,6 @@ import java.util.List; import java.util.Optional; -import java.util.concurrent.ExecutorService; import java.util.function.Function; import com.google.common.annotations.VisibleForTesting; @@ -49,7 +48,6 @@ public class CliqueMinerExecutor extends AbstractMinerExecutor protocolContext, - final ExecutorService executorService, final ProtocolSchedule protocolSchedule, final PendingTransactions pendingTransactions, final KeyPair nodeKeys, @@ -59,7 +57,6 @@ public CliqueMinerExecutor( final Function gasLimitCalculator) { super( protocolContext, - executorService, protocolSchedule, pendingTransactions, miningParams, @@ -71,19 +68,7 @@ public CliqueMinerExecutor( } @Override - public CliqueBlockMiner startAsyncMining( - final Subscribers observers, final BlockHeader parentHeader) { - final CliqueBlockMiner currentRunningMiner = createMiner(observers, parentHeader); - executorService.execute(currentRunningMiner); - return currentRunningMiner; - } - - @Override - public CliqueBlockMiner createMiner(final BlockHeader parentHeader) { - return createMiner(Subscribers.none(), parentHeader); - } - - private CliqueBlockMiner createMiner( + public CliqueBlockMiner createMiner( final Subscribers observers, final BlockHeader parentHeader) { final Function blockCreator = (header) -> diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/CliqueJsonRpcMethodsFactory.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/CliqueJsonRpcMethods.java similarity index 66% rename from consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/CliqueJsonRpcMethodsFactory.java rename to consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/CliqueJsonRpcMethods.java index 1ba554cb27d..860af0e9369 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/CliqueJsonRpcMethodsFactory.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/CliqueJsonRpcMethods.java @@ -29,56 +29,46 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethodFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.ApiGroupJsonRpcMethods; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import java.util.Collection; -import java.util.HashMap; import java.util.Map; -public class CliqueJsonRpcMethodsFactory implements JsonRpcMethodFactory { +public class CliqueJsonRpcMethods extends ApiGroupJsonRpcMethods { + private final JsonRpcParameter parameter = new JsonRpcParameter(); private final ProtocolContext context; - public CliqueJsonRpcMethodsFactory(final ProtocolContext context) { + public CliqueJsonRpcMethods(final ProtocolContext context) { this.context = context; } @Override - public Map createJsonRpcMethods(final Collection jsonRpcApis) { - final Map rpcMethods = new HashMap<>(); - if (!jsonRpcApis.contains(CliqueRpcApis.CLIQUE)) { - return rpcMethods; - } + protected RpcApi getApiGroup() { + return CliqueRpcApis.CLIQUE; + } + + @Override + protected Map create() { final MutableBlockchain blockchain = context.getBlockchain(); final WorldStateArchive worldStateArchive = context.getWorldStateArchive(); final BlockchainQueries blockchainQueries = new BlockchainQueries(blockchain, worldStateArchive); final VoteProposer voteProposer = context.getConsensusState().getVoteProposer(); - final JsonRpcParameter jsonRpcParameter = new JsonRpcParameter(); + // Must create our own voteTallyCache as using this would pollute the main voteTallyCache final VoteTallyCache voteTallyCache = createVoteTallyCache(context, blockchain); - final CliqueGetSigners cliqueGetSigners = - new CliqueGetSigners(blockchainQueries, voteTallyCache, jsonRpcParameter); - final CliqueGetSignersAtHash cliqueGetSignersAtHash = - new CliqueGetSignersAtHash(blockchainQueries, voteTallyCache, jsonRpcParameter); - final Propose proposeRpc = new Propose(voteProposer, jsonRpcParameter); - final Discard discardRpc = new Discard(voteProposer, jsonRpcParameter); - final CliqueProposals cliqueProposals = new CliqueProposals(voteProposer); - final CliqueGetSignerMetrics cliqueGetSignerMetrics = - new CliqueGetSignerMetrics(new CliqueBlockInterface(), blockchainQueries, jsonRpcParameter); - - rpcMethods.put(cliqueGetSigners.getName(), cliqueGetSigners); - rpcMethods.put(cliqueGetSignersAtHash.getName(), cliqueGetSignersAtHash); - rpcMethods.put(proposeRpc.getName(), proposeRpc); - rpcMethods.put(discardRpc.getName(), discardRpc); - rpcMethods.put(cliqueProposals.getName(), cliqueProposals); - rpcMethods.put(cliqueGetSignerMetrics.getName(), cliqueGetSignerMetrics); - return rpcMethods; + return mapOf( + new CliqueGetSigners(blockchainQueries, voteTallyCache, parameter), + new CliqueGetSignersAtHash(blockchainQueries, voteTallyCache, parameter), + new Propose(voteProposer, parameter), + new Discard(voteProposer, parameter), + new CliqueProposals(voteProposer), + new CliqueGetSignerMetrics(new CliqueBlockInterface(), blockchainQueries, parameter)); } private VoteTallyCache createVoteTallyCache( diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignerMetrics.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignerMetrics.java index 67cb70af91c..7090161c22b 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignerMetrics.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignerMetrics.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; public class CliqueGetSignerMetrics extends AbstractGetSignerMetricsMethod implements JsonRpcMethod { diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSigners.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSigners.java index 78d4cb812be..8d8b2b65e90 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSigners.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSigners.java @@ -15,17 +15,17 @@ package org.hyperledger.besu.consensus.clique.jsonrpc.methods; import org.hyperledger.besu.consensus.common.VoteTallyCache; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; import java.util.Objects; diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHash.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHash.java index 101f048d86c..f95c62a5241 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHash.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHash.java @@ -15,16 +15,16 @@ package org.hyperledger.besu.consensus.clique.jsonrpc.methods; import org.hyperledger.besu.consensus.common.VoteTallyCache; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java index 098359b4cdd..ac69c42d03e 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java @@ -48,7 +48,6 @@ import java.util.List; import java.util.Random; -import java.util.concurrent.Executors; import java.util.function.Function; import com.google.common.collect.Lists; @@ -94,7 +93,6 @@ public void extraDataCreatedOnEpochBlocksContainsValidators() { final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, - Executors.newSingleThreadExecutor(), CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair, false), new PendingTransactions( TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS, @@ -132,7 +130,6 @@ public void extraDataForNonEpochBlocksDoesNotContainValidaors() { final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, - Executors.newSingleThreadExecutor(), CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair, false), new PendingTransactions( TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS, @@ -170,7 +167,6 @@ public void shouldUseLatestVanityData() { final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, - Executors.newSingleThreadExecutor(), CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair, false), new PendingTransactions( TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS, diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMiningCoordinatorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMiningCoordinatorTest.java index 919d3602ded..bfaec897c0e 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMiningCoordinatorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMiningCoordinatorTest.java @@ -43,6 +43,7 @@ import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import java.util.List; +import java.util.Optional; import org.assertj.core.util.Lists; import org.junit.Before; @@ -89,7 +90,7 @@ public void setup() { when(protocolContext.getConsensusState()).thenReturn(cliqueContext); when(protocolContext.getBlockchain()).thenReturn(blockChain); - when(minerExecutor.startAsyncMining(any(), any())).thenReturn(blockMiner); + when(minerExecutor.startAsyncMining(any(), any())).thenReturn(Optional.of(blockMiner)); when(syncState.isInSync()).thenReturn(true); miningTracker = new CliqueMiningTracker(proposerAddress, protocolContext); @@ -108,6 +109,7 @@ public void outOfTurnBlockImportedDoesNotInterruptInTurnMiningOperation() { new CliqueMiningCoordinator(blockChain, minerExecutor, syncState, miningTracker); coordinator.enable(); + coordinator.start(); verify(minerExecutor, times(1)).startAsyncMining(any(), any()); @@ -134,11 +136,12 @@ public void outOfTurnBlockImportedAtHigherLevelInterruptsMiningOperation() { new CliqueMiningCoordinator(blockChain, minerExecutor, syncState, miningTracker); coordinator.enable(); + coordinator.start(); verify(minerExecutor, times(1)).startAsyncMining(any(), any()); reset(minerExecutor); - when(minerExecutor.startAsyncMining(any(), any())).thenReturn(blockMiner); + when(minerExecutor.startAsyncMining(any(), any())).thenReturn(Optional.of(blockMiner)); final Block importedBlock = createEmptyBlock(2, blockChain.getChainHeadHash(), validatorKeys); @@ -164,11 +167,12 @@ public void outOfTurnBlockImportedInterruptsOutOfTurnMiningOperation() { new CliqueMiningCoordinator(blockChain, minerExecutor, syncState, miningTracker); coordinator.enable(); + coordinator.start(); verify(minerExecutor, times(1)).startAsyncMining(any(), any()); reset(minerExecutor); - when(minerExecutor.startAsyncMining(any(), any())).thenReturn(blockMiner); + when(minerExecutor.startAsyncMining(any(), any())).thenReturn(Optional.of(blockMiner)); final Block importedBlock = createEmptyBlock(2, blockChain.getChainHeadHash(), validatorKeys); @@ -194,11 +198,12 @@ public void outOfTurnBlockImportedInterruptsNonRunningMiner() { new CliqueMiningCoordinator(blockChain, minerExecutor, syncState, miningTracker); coordinator.enable(); + coordinator.start(); verify(minerExecutor, times(1)).startAsyncMining(any(), any()); reset(minerExecutor); - when(minerExecutor.startAsyncMining(any(), any())).thenReturn(blockMiner); + when(minerExecutor.startAsyncMining(any(), any())).thenReturn(Optional.of(blockMiner)); final Block importedBlock = createEmptyBlock(2, blockChain.getChainHeadHash(), validatorKeys); @@ -219,11 +224,12 @@ public void locallyGeneratedBlockInvalidatesMiningEvenIfInTurn() { new CliqueMiningCoordinator(blockChain, minerExecutor, syncState, miningTracker); coordinator.enable(); + coordinator.start(); verify(minerExecutor, times(1)).startAsyncMining(any(), any()); reset(minerExecutor); - when(minerExecutor.startAsyncMining(any(), any())).thenReturn(blockMiner); + when(minerExecutor.startAsyncMining(any(), any())).thenReturn(Optional.of(blockMiner)); final Block importedBlock = createEmptyBlock(1, blockChain.getChainHeadHash(), proposerKeys); blockChain.appendBlock(importedBlock, Lists.emptyList()); diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignerMetricsTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignerMetricsTest.java index 67caed1bca2..d0735fbab23 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignerMetricsTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignerMetricsTest.java @@ -25,9 +25,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.SignerMetricResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java index 9602e778767..444bcc53cb1 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersAtHashTest.java @@ -23,15 +23,15 @@ import org.hyperledger.besu.consensus.clique.CliqueBlockHeaderFunctions; import org.hyperledger.besu.consensus.common.VoteTally; import org.hyperledger.besu.consensus.common.VoteTallyCache; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java index 2df38a41ae4..98b664650b3 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/jsonrpc/methods/CliqueGetSignersTest.java @@ -22,14 +22,14 @@ import org.hyperledger.besu.consensus.common.VoteTally; import org.hyperledger.besu.consensus.common.VoteTallyCache; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoAContext.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoaContext.java similarity index 95% rename from consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoAContext.java rename to consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoaContext.java index 5a70d3f2a76..b10bf63c357 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoAContext.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoaContext.java @@ -14,6 +14,6 @@ */ package org.hyperledger.besu.consensus.common; -public interface PoAContext { +public interface PoaContext { BlockInterface getBlockInterface(); } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoAMetricServiceImpl.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoaQueryServiceImpl.java similarity index 82% rename from consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoAMetricServiceImpl.java rename to consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoaQueryServiceImpl.java index bc5db073429..a7291728a2b 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoAMetricServiceImpl.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/PoaQueryServiceImpl.java @@ -18,16 +18,17 @@ import org.hyperledger.besu.plugin.data.Address; import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.services.metrics.PoAMetricsService; +import org.hyperledger.besu.plugin.services.query.PoaQueryService; import java.util.ArrayList; import java.util.Collection; -public class PoAMetricServiceImpl implements PoAMetricsService { +public class PoaQueryServiceImpl implements PoaQueryService, PoAMetricsService { private final BlockInterface blockInterface; private final Blockchain blockchain; - public PoAMetricServiceImpl(final BlockInterface blockInterface, final Blockchain blockchain) { + public PoaQueryServiceImpl(final BlockInterface blockInterface, final Blockchain blockchain) { this.blockInterface = blockInterface; this.blockchain = blockchain; } @@ -41,4 +42,8 @@ public Collection
getValidatorsForLatestBlock() { public Address getProposerOfBlock(final BlockHeader header) { return this.blockInterface.getProposerOfBlock(header); } + + protected Blockchain getBlockchain() { + return blockchain; + } } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractGetSignerMetricsMethod.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractGetSignerMetricsMethod.java index ec1a759506b..68064985427 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractGetSignerMetricsMethod.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/jsonrpc/AbstractGetSignerMetricsMethod.java @@ -18,12 +18,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.SignerMetricResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContext.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContext.java index 75365f666d9..7d4da38327c 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContext.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContext.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.consensus.ibft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.ibft.EventMultiplexer; +import org.hyperledger.besu.consensus.ibft.IbftExecutors; import org.hyperledger.besu.consensus.ibft.payload.MessageFactory; import org.hyperledger.besu.consensus.ibft.statemachine.IbftController; import org.hyperledger.besu.consensus.ibft.statemachine.IbftFinalState; @@ -40,6 +41,7 @@ public class TestContext { private final Map remotePeers; private final MutableBlockchain blockchain; + private final IbftExecutors ibftExecutors; private final IbftController controller; private final IbftFinalState finalState; private final EventMultiplexer eventMultiplexer; @@ -47,16 +49,23 @@ public class TestContext { public TestContext( final Map remotePeers, final MutableBlockchain blockchain, + final IbftExecutors ibftExecutors, final IbftController controller, final IbftFinalState finalState, final EventMultiplexer eventMultiplexer) { this.remotePeers = remotePeers; this.blockchain = blockchain; + this.ibftExecutors = ibftExecutors; this.controller = controller; this.finalState = finalState; this.eventMultiplexer = eventMultiplexer; } + public void start() { + ibftExecutors.start(); + controller.start(); + } + public MutableBlockchain getBlockchain() { return blockchain; } diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java index 38f46a8342b..228843776ea 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.consensus.ibft.IbftBlockInterface; import org.hyperledger.besu.consensus.ibft.IbftContext; import org.hyperledger.besu.consensus.ibft.IbftEventQueue; +import org.hyperledger.besu.consensus.ibft.IbftExecutors; import org.hyperledger.besu.consensus.ibft.IbftExtraData; import org.hyperledger.besu.consensus.ibft.IbftGossip; import org.hyperledger.besu.consensus.ibft.IbftHelpers; @@ -82,7 +83,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.Executors; import java.util.stream.Collectors; import com.google.common.collect.Iterables; @@ -93,19 +93,26 @@ public class TestContextBuilder { private static class ControllerAndState { + private final IbftExecutors ibftExecutors; private IbftController controller; private IbftFinalState finalState; private EventMultiplexer eventMultiplexer; public ControllerAndState( + final IbftExecutors ibftExecutors, final IbftController controller, final IbftFinalState finalState, final EventMultiplexer eventMultiplexer) { + this.ibftExecutors = ibftExecutors; this.controller = controller; this.finalState = finalState; this.eventMultiplexer = eventMultiplexer; } + public IbftExecutors getIbftExecutors() { + return ibftExecutors; + } + public IbftController getController() { return controller; } @@ -213,11 +220,18 @@ public TestContext build() { return new TestContext( remotePeers, blockChain, + controllerAndState.getIbftExecutors(), controllerAndState.getController(), controllerAndState.getFinalState(), controllerAndState.getEventMultiplexer()); } + public TestContext buildAndStart() { + TestContext testContext = build(); + testContext.start(); + return testContext; + } + private static Block createGenesisBlock(final Set
validators) { final Address coinbase = Iterables.get(validators, 0); final BlockHeaderTestFixture headerTestFixture = new BlockHeaderTestFixture(); @@ -304,6 +318,7 @@ private static ControllerAndState createControllerAndFinalState( final ProposerSelector proposerSelector = new ProposerSelector(blockChain, blockInterface, true); + final IbftExecutors ibftExecutors = IbftExecutors.create(new NoOpMetricsSystem()); final IbftFinalState finalState = new IbftFinalState( protocolContext.getConsensusState().getVoteTallyCache(), @@ -311,13 +326,9 @@ private static ControllerAndState createControllerAndFinalState( Util.publicKeyToAddress(nodeKeys.getPublicKey()), proposerSelector, multicaster, - new RoundTimer( - ibftEventQueue, ROUND_TIMER_SEC * 1000, Executors.newScheduledThreadPool(1)), + new RoundTimer(ibftEventQueue, ROUND_TIMER_SEC * 1000, ibftExecutors), new BlockTimer( - ibftEventQueue, - BLOCK_TIMER_SEC * 1000, - Executors.newScheduledThreadPool(1), - TestClock.fixed()), + ibftEventQueue, BLOCK_TIMER_SEC * 1000, ibftExecutors, TestClock.fixed()), blockCreatorFactory, new MessageFactory(nodeKeys), clock); @@ -355,6 +366,6 @@ private static ControllerAndState createControllerAndFinalState( final EventMultiplexer eventMultiplexer = new EventMultiplexer(ibftController); //////////////////////////// END IBFT BesuController //////////////////////////// - return new ControllerAndState(ibftController, finalState, eventMultiplexer); + return new ControllerAndState(ibftExecutors, ibftController, finalState, eventMultiplexer); } } diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/FutureHeightTest.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/FutureHeightTest.java index b70e3ae0f14..0fc042476d6 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/FutureHeightTest.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/FutureHeightTest.java @@ -49,7 +49,7 @@ public class FutureHeightTest { .validatorCount(NETWORK_SIZE) .indexOfFirstLocallyProposedBlock(0) .clock(fixedClock) - .build(); + .buildAndStart(); private final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(1, 0); private final RoundSpecificPeers peers = context.roundSpecificPeers(roundId); diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/FutureRoundTest.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/FutureRoundTest.java index 224764b4c40..ad5a685f477 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/FutureRoundTest.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/FutureRoundTest.java @@ -48,7 +48,7 @@ public class FutureRoundTest { .validatorCount(NETWORK_SIZE) .indexOfFirstLocallyProposedBlock(0) .clock(fixedClock) - .build(); + .buildAndStart(); private final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(1, 0); private final RoundSpecificPeers peers = context.roundSpecificPeers(roundId); diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/GossipTest.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/GossipTest.java index c3c2f0ae4b8..d4cc9a5d1f5 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/GossipTest.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/GossipTest.java @@ -56,7 +56,7 @@ public class GossipTest { .indexOfFirstLocallyProposedBlock(0) .clock(fixedClock) .useGossip(true) - .build(); + .buildAndStart(); private final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(1, 0); private final RoundSpecificPeers peers = context.roundSpecificPeers(roundId); diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/LocalNodeIsProposerTest.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/LocalNodeIsProposerTest.java index 57f4aedd2df..0c4c128fa33 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/LocalNodeIsProposerTest.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/LocalNodeIsProposerTest.java @@ -53,7 +53,7 @@ public class LocalNodeIsProposerTest { .validatorCount(NETWORK_SIZE) .indexOfFirstLocallyProposedBlock(1) .clock(fixedClock) - .build(); + .buildAndStart(); private final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(1, 0); private final RoundSpecificPeers peers = context.roundSpecificPeers(roundId); diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/LocalNodeNotProposerTest.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/LocalNodeNotProposerTest.java index 85cd689fe80..30ec97ee69d 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/LocalNodeNotProposerTest.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/LocalNodeNotProposerTest.java @@ -39,7 +39,7 @@ public class LocalNodeNotProposerTest { new TestContextBuilder() .validatorCount(NETWORK_SIZE) .indexOfFirstLocallyProposedBlock(0) - .build(); + .buildAndStart(); private final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(1, 0); private final RoundSpecificPeers peers = context.roundSpecificPeers(roundId); diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/ReceivedFutureProposalTest.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/ReceivedFutureProposalTest.java index 44cc813d7aa..f61b8e9c5c4 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/ReceivedFutureProposalTest.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/ReceivedFutureProposalTest.java @@ -48,7 +48,7 @@ public class ReceivedFutureProposalTest { new TestContextBuilder() .validatorCount(NETWORK_SIZE) .indexOfFirstLocallyProposedBlock(0) - .build(); + .buildAndStart(); private final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(1, 0); private final RoundSpecificPeers peers = context.roundSpecificPeers(roundId); diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/RoundChangeTest.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/RoundChangeTest.java index 5af4969befc..a0b0d63be29 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/RoundChangeTest.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/RoundChangeTest.java @@ -58,7 +58,7 @@ public class RoundChangeTest { .validatorCount(NETWORK_SIZE) .indexOfFirstLocallyProposedBlock(0) .clock(fixedClock) - .build(); + .buildAndStart(); private final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(1, 0); private final RoundSpecificPeers peers = context.roundSpecificPeers(roundId); diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/SpuriousBehaviourTest.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/SpuriousBehaviourTest.java index 3a70467283e..e81d917c61b 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/SpuriousBehaviourTest.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/tests/SpuriousBehaviourTest.java @@ -59,7 +59,7 @@ public class SpuriousBehaviourTest { .validatorCount(NETWORK_SIZE) .indexOfFirstLocallyProposedBlock(0) .clock(fixedClock) - .build(); + .buildAndStart(); private final ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(1, 0); private final RoundSpecificPeers peers = context.roundSpecificPeers(roundId); diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/BlockTimer.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/BlockTimer.java index 7cf7c95a43f..1af3d2f7b76 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/BlockTimer.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/BlockTimer.java @@ -19,13 +19,12 @@ import java.time.Clock; import java.util.Optional; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** Class for starting and keeping organised block timers */ public class BlockTimer { - private final ScheduledExecutorService timerExecutor; + private final IbftExecutors ibftExecutors; private Optional> currentTimerTask; private final IbftEventQueue queue; private final long minimumTimeBetweenBlocksMillis; @@ -36,16 +35,16 @@ public class BlockTimer { * * @param queue The queue in which to put block expiry events * @param minimumTimeBetweenBlocksSeconds Minimum timestamp difference between blocks - * @param timerExecutor Executor service that timers can be scheduled with + * @param ibftExecutors Executor services that timers can be scheduled with * @param clock System clock */ public BlockTimer( final IbftEventQueue queue, final long minimumTimeBetweenBlocksSeconds, - final ScheduledExecutorService timerExecutor, + final IbftExecutors ibftExecutors, final Clock clock) { this.queue = queue; - this.timerExecutor = timerExecutor; + this.ibftExecutors = ibftExecutors; this.currentTimerTask = Optional.empty(); this.minimumTimeBetweenBlocksMillis = minimumTimeBetweenBlocksSeconds * 1000; this.clock = clock; @@ -87,7 +86,7 @@ public synchronized void startTimer( final Runnable newTimerRunnable = () -> queue.add(new BlockTimerExpiry(round)); final ScheduledFuture newTimerTask = - timerExecutor.schedule(newTimerRunnable, delay, TimeUnit.MILLISECONDS); + ibftExecutors.scheduleTask(newTimerRunnable, delay, TimeUnit.MILLISECONDS); currentTimerTask = Optional.of(newTimerTask); } else { queue.add(new BlockTimerExpiry(round)); diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftContext.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftContext.java index 8127be3f80b..2a8247f4dd0 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftContext.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftContext.java @@ -15,12 +15,12 @@ package org.hyperledger.besu.consensus.ibft; import org.hyperledger.besu.consensus.common.BlockInterface; -import org.hyperledger.besu.consensus.common.PoAContext; +import org.hyperledger.besu.consensus.common.PoaContext; import org.hyperledger.besu.consensus.common.VoteProposer; import org.hyperledger.besu.consensus.common.VoteTallyCache; /** Holds the IBFT specific mutable state. */ -public class IbftContext implements PoAContext { +public class IbftContext implements PoaContext { private final VoteTallyCache voteTallyCache; private final VoteProposer voteProposer; diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftExecutors.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftExecutors.java new file mode 100644 index 00000000000..59ff8c3305e --- /dev/null +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftExecutors.java @@ -0,0 +1,109 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.consensus.ibft; + +import static org.hyperledger.besu.ethereum.eth.manager.MonitoredExecutors.newScheduledThreadPool; + +import org.hyperledger.besu.plugin.services.MetricsSystem; + +import java.time.Duration; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class IbftExecutors { + + private enum State { + IDLE, + RUNNING, + STOPPED + } + + private static final Logger LOG = LogManager.getLogger(); + + private final Duration shutdownTimeout = Duration.ofSeconds(30); + private final MetricsSystem metricsSystem; + + private volatile ScheduledExecutorService timerExecutor; + private volatile ExecutorService ibftProcessorExecutor; + private volatile State state = State.IDLE; + + private IbftExecutors(final MetricsSystem metricsSystem) { + this.metricsSystem = metricsSystem; + } + + public static IbftExecutors create(final MetricsSystem metricsSystem) { + return new IbftExecutors(metricsSystem); + } + + public synchronized void start() { + if (state != State.IDLE) { + // Nothing to do + return; + } + state = State.RUNNING; + ibftProcessorExecutor = Executors.newSingleThreadExecutor(); + timerExecutor = newScheduledThreadPool("IbftTimerExecutor", 1, metricsSystem); + } + + public void stop() { + synchronized (this) { + if (state != State.RUNNING) { + return; + } + state = State.STOPPED; + } + + timerExecutor.shutdownNow(); + ibftProcessorExecutor.shutdownNow(); + } + + public void awaitStop() throws InterruptedException { + if (!timerExecutor.awaitTermination(shutdownTimeout.getSeconds(), TimeUnit.SECONDS)) { + LOG.error("{} timer executor did not shutdown cleanly.", getClass().getSimpleName()); + } + if (!ibftProcessorExecutor.awaitTermination(shutdownTimeout.getSeconds(), TimeUnit.SECONDS)) { + LOG.error("{} ibftProcessor executor did not shutdown cleanly.", getClass().getSimpleName()); + } + } + + public synchronized void executeIbftProcessor(final IbftProcessor ibftProcessor) { + assertRunning(); + ibftProcessorExecutor.execute(ibftProcessor); + } + + public synchronized ScheduledFuture scheduleTask( + final Runnable command, final long delay, final TimeUnit unit) { + assertRunning(); + return timerExecutor.schedule(command, delay, unit); + } + + private void assertRunning() { + if (state != State.RUNNING) { + throw new IllegalStateException( + "Attempt to interact with " + + getClass().getSimpleName() + + " that is not running. Current State is " + + state.name() + + "."); + } + } +} diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftExtraData.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftExtraData.java index c854eb2cf11..f42ff3ffeaa 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftExtraData.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftExtraData.java @@ -84,6 +84,10 @@ public static IbftExtraData decode(final BlockHeader blockHeader) { } static IbftExtraData decodeRaw(final BytesValue input) { + if (input.isEmpty()) { + throw new IllegalArgumentException("Invalid BytesValue supplied - Ibft Extra Data required."); + } + final RLPInput rlpInput = new BytesValueRLPInput(input, false); rlpInput.enterList(); // This accounts for the "root node" which contains IBFT data items. diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProcessor.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProcessor.java index 2a7a7cb7e43..9f7fd892f6a 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProcessor.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProcessor.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.consensus.ibft.ibftevent.IbftEvent; import java.util.Optional; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.LogManager; @@ -30,6 +31,7 @@ public class IbftProcessor implements Runnable { private final IbftEventQueue incomingQueue; private volatile boolean shutdown = false; private final EventMultiplexer eventMultiplexer; + private CountDownLatch shutdownLatch = new CountDownLatch(1); /** * Construct a new IbftProcessor @@ -48,6 +50,10 @@ public void stop() { shutdown = true; } + public void awaitStop() throws InterruptedException { + shutdownLatch.await(); + } + @Override public void run() { try { @@ -59,6 +65,7 @@ public void run() { } // Clean up the executor service the round timer has been utilising LOG.info("Shutting down IBFT event processor"); + shutdownLatch.countDown(); } private Optional nextIbftEvent() { diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/RoundTimer.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/RoundTimer.java index c61a4c9d8bb..244c3881dbc 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/RoundTimer.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/RoundTimer.java @@ -17,13 +17,12 @@ import org.hyperledger.besu.consensus.ibft.ibftevent.RoundExpiry; import java.util.Optional; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** Class for starting and keeping organised round timers */ public class RoundTimer { - private final ScheduledExecutorService timerExecutor; + private final IbftExecutors ibftExecutors; private Optional> currentTimerTask; private final IbftEventQueue queue; private final long baseExpiryMillis; @@ -33,14 +32,12 @@ public class RoundTimer { * * @param queue The queue in which to put round expiry events * @param baseExpirySeconds The initial round length for round 0 - * @param timerExecutor executor service that timers can be scheduled with + * @param ibftExecutors executor service that timers can be scheduled with */ public RoundTimer( - final IbftEventQueue queue, - final long baseExpirySeconds, - final ScheduledExecutorService timerExecutor) { + final IbftEventQueue queue, final long baseExpirySeconds, final IbftExecutors ibftExecutors) { this.queue = queue; - this.timerExecutor = timerExecutor; + this.ibftExecutors = ibftExecutors; this.currentTimerTask = Optional.empty(); this.baseExpiryMillis = baseExpirySeconds * 1000; } @@ -73,7 +70,7 @@ public synchronized void startTimer(final ConsensusRoundIdentifier round) { final Runnable newTimerRunnable = () -> queue.add(new RoundExpiry(round)); final ScheduledFuture newTimerTask = - timerExecutor.schedule(newTimerRunnable, expiryTime, TimeUnit.MILLISECONDS); + ibftExecutors.scheduleTask(newTimerRunnable, expiryTime, TimeUnit.MILLISECONDS); currentTimerTask = Optional.of(newTimerTask); } } diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinator.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinator.java index 4d041f4c46b..acd713a78a2 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinator.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinator.java @@ -17,8 +17,10 @@ import static org.apache.logging.log4j.LogManager.getLogger; import org.hyperledger.besu.consensus.ibft.IbftEventQueue; +import org.hyperledger.besu.consensus.ibft.IbftExecutors; import org.hyperledger.besu.consensus.ibft.IbftProcessor; import org.hyperledger.besu.consensus.ibft.ibftevent.NewChainHead; +import org.hyperledger.besu.consensus.ibft.statemachine.IbftController; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; @@ -32,40 +34,89 @@ import java.util.List; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; import org.apache.logging.log4j.Logger; public class IbftMiningCoordinator implements MiningCoordinator, BlockAddedObserver { - private final IbftBlockCreatorFactory blockCreatorFactory; + private enum State { + IDLE, + RUNNING, + STOPPED + } + private static final Logger LOG = getLogger(); + + private final IbftController controller; + private final IbftProcessor ibftProcessor; + private final IbftBlockCreatorFactory blockCreatorFactory; protected final Blockchain blockchain; private final IbftEventQueue eventQueue; - private final IbftProcessor ibftProcessor; + private final IbftExecutors ibftExecutors; + + private long blockAddedObserverId; + private AtomicReference state = new AtomicReference<>(State.IDLE); public IbftMiningCoordinator( + final IbftExecutors ibftExecutors, + final IbftController controller, final IbftProcessor ibftProcessor, final IbftBlockCreatorFactory blockCreatorFactory, final Blockchain blockchain, final IbftEventQueue eventQueue) { + this.ibftExecutors = ibftExecutors; + this.controller = controller; this.ibftProcessor = ibftProcessor; this.blockCreatorFactory = blockCreatorFactory; this.eventQueue = eventQueue; this.blockchain = blockchain; - this.blockchain.observeBlockAdded(this); } @Override - public void enable() {} + public void start() { + if (state.compareAndSet(State.IDLE, State.RUNNING)) { + ibftExecutors.start(); + blockAddedObserverId = blockchain.observeBlockAdded(this); + controller.start(); + ibftExecutors.executeIbftProcessor(ibftProcessor); + } + } + + @Override + public void stop() { + if (state.compareAndSet(State.RUNNING, State.STOPPED)) { + blockchain.removeObserver(blockAddedObserverId); + ibftProcessor.stop(); + // Make sure the processor has stopped before shutting down the executors + try { + ibftProcessor.awaitStop(); + } catch (final InterruptedException e) { + LOG.debug("Interrupted while waiting for IbftProcessor to stop.", e); + Thread.currentThread().interrupt(); + } + ibftExecutors.stop(); + } + } + + @Override + public void awaitStop() throws InterruptedException { + ibftExecutors.awaitStop(); + } + + @Override + public boolean enable() { + return true; + } @Override - public void disable() { - ibftProcessor.stop(); + public boolean disable() { + return false; } @Override - public boolean isRunning() { + public boolean isMining() { return true; } diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/IbftJsonRpcMethodsFactory.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/IbftJsonRpcMethods.java similarity index 53% rename from consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/IbftJsonRpcMethodsFactory.java rename to consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/IbftJsonRpcMethods.java index 2542acab717..a0480f7b577 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/IbftJsonRpcMethodsFactory.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/IbftJsonRpcMethods.java @@ -27,51 +27,39 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethodFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.ApiGroupJsonRpcMethods; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import java.util.Collection; -import java.util.HashMap; import java.util.Map; -public class IbftJsonRpcMethodsFactory implements JsonRpcMethodFactory { +public class IbftJsonRpcMethods extends ApiGroupJsonRpcMethods { private final JsonRpcParameter jsonRpcParameter = new JsonRpcParameter(); private final ProtocolContext context; - public IbftJsonRpcMethodsFactory(final ProtocolContext context) { + public IbftJsonRpcMethods(final ProtocolContext context) { this.context = context; } @Override - public Map createJsonRpcMethods(final Collection jsonRpcApis) { - final Map rpcMethods = new HashMap<>(); - - if (jsonRpcApis.contains(IbftRpcApis.IBFT)) { - final BlockchainQueries blockchainQueries = - new BlockchainQueries(context.getBlockchain(), context.getWorldStateArchive()); - final VoteProposer voteProposer = context.getConsensusState().getVoteProposer(); - final BlockInterface blockInterface = new IbftBlockInterface(); - - addMethods( - rpcMethods, - new IbftProposeValidatorVote(voteProposer, jsonRpcParameter), - new IbftGetValidatorsByBlockNumber(blockchainQueries, blockInterface, jsonRpcParameter), - new IbftDiscardValidatorVote(voteProposer, jsonRpcParameter), - new IbftGetValidatorsByBlockHash( - context.getBlockchain(), blockInterface, jsonRpcParameter), - new IbftGetSignerMetrics(blockInterface, blockchainQueries, jsonRpcParameter), - new IbftGetPendingVotes(voteProposer)); - } - - return rpcMethods; + protected RpcApi getApiGroup() { + return IbftRpcApis.IBFT; } - private void addMethods( - final Map methods, final JsonRpcMethod... rpcMethods) { - for (final JsonRpcMethod rpcMethod : rpcMethods) { - methods.put(rpcMethod.getName(), rpcMethod); - } + @Override + protected Map create() { + final BlockchainQueries blockchainQueries = + new BlockchainQueries(context.getBlockchain(), context.getWorldStateArchive()); + final VoteProposer voteProposer = context.getConsensusState().getVoteProposer(); + final BlockInterface blockInterface = new IbftBlockInterface(); + + return mapOf( + new IbftProposeValidatorVote(voteProposer, jsonRpcParameter), + new IbftGetValidatorsByBlockNumber(blockchainQueries, blockInterface, jsonRpcParameter), + new IbftDiscardValidatorVote(voteProposer, jsonRpcParameter), + new IbftGetValidatorsByBlockHash(context.getBlockchain(), blockInterface, jsonRpcParameter), + new IbftGetSignerMetrics(blockInterface, blockchainQueries, jsonRpcParameter), + new IbftGetPendingVotes(voteProposer)); } } diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetSignerMetrics.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetSignerMetrics.java index b595e2a3cb2..d892d5bc074 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetSignerMetrics.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetSignerMetrics.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; public class IbftGetSignerMetrics extends AbstractGetSignerMetricsMethod implements JsonRpcMethod { diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumber.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumber.java index adf0b473ff3..d99acd5ae16 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumber.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumber.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; import java.util.Optional; diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/queries/IbftQueryServiceImpl.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/queries/IbftQueryServiceImpl.java new file mode 100644 index 00000000000..8e1bec5acea --- /dev/null +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/queries/IbftQueryServiceImpl.java @@ -0,0 +1,63 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.consensus.ibft.queries; + +import org.hyperledger.besu.consensus.common.BlockInterface; +import org.hyperledger.besu.consensus.common.PoaQueryServiceImpl; +import org.hyperledger.besu.consensus.ibft.IbftBlockHashing; +import org.hyperledger.besu.consensus.ibft.IbftExtraData; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.plugin.data.Address; +import org.hyperledger.besu.plugin.services.query.IbftQueryService; +import org.hyperledger.besu.util.bytes.Bytes32; + +import java.util.Collection; +import java.util.Collections; + +public class IbftQueryServiceImpl extends PoaQueryServiceImpl implements IbftQueryService { + + public IbftQueryServiceImpl(final BlockInterface blockInterface, final Blockchain blockchain) { + super(blockInterface, blockchain); + } + + @Override + public int getRoundNumberFrom(final org.hyperledger.besu.plugin.data.BlockHeader header) { + final BlockHeader headerFromChain = getHeaderFromChain(header); + final IbftExtraData extraData = IbftExtraData.decode(headerFromChain); + return extraData.getRound(); + } + + @Override + public Collection
getSignersFrom( + final org.hyperledger.besu.plugin.data.BlockHeader header) { + final BlockHeader headerFromChain = getHeaderFromChain(header); + final IbftExtraData extraData = IbftExtraData.decode(headerFromChain); + + return Collections.unmodifiableList( + IbftBlockHashing.recoverCommitterAddresses(headerFromChain, extraData)); + } + + private BlockHeader getHeaderFromChain( + final org.hyperledger.besu.plugin.data.BlockHeader header) { + if (header instanceof BlockHeader) { + return (BlockHeader) header; + } + + final Hash blockHash = Hash.wrap(Bytes32.wrap(header.getBlockHash().getByteArray())); + return getBlockchain().getBlockHeader(blockHash).orElseThrow(); + } +} diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftController.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftController.java index 312734763a3..7a4aa2b3c99 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftController.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftController.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Message; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import org.apache.logging.log4j.LogManager; @@ -42,6 +43,7 @@ public class IbftController { private static final Logger LOG = LogManager.getLogger(); + private final Blockchain blockchain; private final IbftFinalState ibftFinalState; private final IbftBlockHeightManagerFactory ibftBlockHeightManagerFactory; private final FutureMessageBuffer futureMessageBuffer; @@ -50,6 +52,8 @@ public class IbftController { private final MessageTracker duplicateMessageTracker; private final SynchronizerUpdater sychronizerUpdater; + private final AtomicBoolean started = new AtomicBoolean(false); + public IbftController( final Blockchain blockchain, final IbftFinalState ibftFinalState, @@ -58,14 +62,19 @@ public IbftController( final MessageTracker duplicateMessageTracker, final FutureMessageBuffer futureMessageBuffer, final SynchronizerUpdater sychronizerUpdater) { + this.blockchain = blockchain; this.ibftFinalState = ibftFinalState; this.ibftBlockHeightManagerFactory = ibftBlockHeightManagerFactory; this.futureMessageBuffer = futureMessageBuffer; this.gossiper = gossiper; this.duplicateMessageTracker = duplicateMessageTracker; this.sychronizerUpdater = sychronizerUpdater; + } - startNewHeightManager(blockchain.getChainHeadHeader()); + public void start() { + if (started.compareAndSet(false, true)) { + startNewHeightManager(blockchain.getChainHeadHeader()); + } } public void handleMessageEvent(final IbftReceivedMessageEvent msg) { diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/BlockTimerTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/BlockTimerTest.java index 8dc8280556a..36551adff6c 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/BlockTimerTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/BlockTimerTest.java @@ -30,7 +30,6 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import java.time.Clock; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -44,20 +43,20 @@ @RunWith(MockitoJUnitRunner.StrictStubs.class) public class BlockTimerTest { - private ScheduledExecutorService mockExecutorService; + private IbftExecutors ibftExecutors; private IbftEventQueue mockQueue; private Clock mockClock; @Before public void initialise() { - mockExecutorService = mock(ScheduledExecutorService.class); + ibftExecutors = mock(IbftExecutors.class); mockQueue = mock(IbftEventQueue.class); mockClock = mock(Clock.class); } @Test public void cancelTimerCancelsWhenNoTimer() { - final BlockTimer timer = new BlockTimer(mockQueue, 15, mockExecutorService, mockClock); + final BlockTimer timer = new BlockTimer(mockQueue, 15, ibftExecutors, mockClock); // Starts with nothing running assertThat(timer.isRunning()).isFalse(); // cancel shouldn't die if there's nothing running @@ -74,8 +73,7 @@ public void startTimerSchedulesCorrectlyWhenExpiryIsInTheFuture() { final long EXPECTED_DELAY = 10_000L; final BlockTimer timer = - new BlockTimer( - mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, mockExecutorService, mockClock); + new BlockTimer(mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, ibftExecutors, mockClock); when(mockClock.millis()).thenReturn(NOW_MILLIS); @@ -86,12 +84,12 @@ public void startTimerSchedulesCorrectlyWhenExpiryIsInTheFuture() { final ScheduledFuture mockedFuture = mock(ScheduledFuture.class); Mockito.>when( - mockExecutorService.schedule(any(Runnable.class), anyLong(), any())) + ibftExecutors.scheduleTask(any(Runnable.class), anyLong(), any())) .thenReturn(mockedFuture); timer.startTimer(round, header); - verify(mockExecutorService) - .schedule(any(Runnable.class), eq(EXPECTED_DELAY), eq(TimeUnit.MILLISECONDS)); + verify(ibftExecutors) + .scheduleTask(any(Runnable.class), eq(EXPECTED_DELAY), eq(TimeUnit.MILLISECONDS)); } @Test @@ -110,13 +108,12 @@ public void aBlockTimerExpiryEventIsAddedToTheQueueOnExpiry() throws Interrupted final ScheduledFuture mockedFuture = mock(ScheduledFuture.class); Mockito.>when( - mockExecutorService.schedule(any(Runnable.class), anyLong(), any())) + ibftExecutors.scheduleTask(any(Runnable.class), anyLong(), any())) .thenReturn(mockedFuture); final IbftEventQueue eventQueue = new IbftEventQueue(1000); final BlockTimer timer = - new BlockTimer( - eventQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, mockExecutorService, mockClock); + new BlockTimer(eventQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, ibftExecutors, mockClock); timer.startTimer(round, header); // Verify that the event will not be added to the queue immediately @@ -124,8 +121,8 @@ public void aBlockTimerExpiryEventIsAddedToTheQueueOnExpiry() throws Interrupted // Verify that a task is sceheduled for EXPECTED_DELAY milliseconds in the future ArgumentCaptor expiryTask = ArgumentCaptor.forClass(Runnable.class); - verify(mockExecutorService, times(1)) - .schedule(expiryTask.capture(), eq(EXPECTED_DELAY), eq(TimeUnit.MILLISECONDS)); + verify(ibftExecutors, times(1)) + .scheduleTask(expiryTask.capture(), eq(EXPECTED_DELAY), eq(TimeUnit.MILLISECONDS)); // assert that the task puts a BlockExpired event into the queue final Runnable scheduledTask = expiryTask.getValue(); @@ -145,8 +142,7 @@ public void eventIsImmediatelyAddedToTheQueueIfAbsoluteExpiryIsEqualToNow() { final long BLOCK_TIME_STAMP = 500; final BlockTimer timer = - new BlockTimer( - mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, mockExecutorService, mockClock); + new BlockTimer(mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, ibftExecutors, mockClock); when(mockClock.millis()).thenReturn(NOW_MILLIS); @@ -156,7 +152,7 @@ public void eventIsImmediatelyAddedToTheQueueIfAbsoluteExpiryIsEqualToNow() { new ConsensusRoundIdentifier(0xFEDBCA9876543210L, 0x12345678); timer.startTimer(round, header); - verify(mockExecutorService, never()).schedule(any(Runnable.class), anyLong(), any()); + verify(ibftExecutors, never()).scheduleTask(any(Runnable.class), anyLong(), any()); final ArgumentCaptor ibftEventCaptor = ArgumentCaptor.forClass(IbftEvent.class); verify(mockQueue).add(ibftEventCaptor.capture()); @@ -173,8 +169,7 @@ public void eventIsImmediatelyAddedToTheQueueIfAbsoluteExpiryIsInThePast() { final long BLOCK_TIME_STAMP = 500L; final BlockTimer timer = - new BlockTimer( - mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, mockExecutorService, mockClock); + new BlockTimer(mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, ibftExecutors, mockClock); when(mockClock.millis()).thenReturn(NOW_MILLIS); @@ -184,7 +179,7 @@ public void eventIsImmediatelyAddedToTheQueueIfAbsoluteExpiryIsInThePast() { new ConsensusRoundIdentifier(0xFEDBCA9876543210L, 0x12345678); timer.startTimer(round, header); - verify(mockExecutorService, never()).schedule(any(Runnable.class), anyLong(), any()); + verify(ibftExecutors, never()).scheduleTask(any(Runnable.class), anyLong(), any()); final ArgumentCaptor ibftEventCaptor = ArgumentCaptor.forClass(IbftEvent.class); verify(mockQueue).add(ibftEventCaptor.capture()); @@ -201,8 +196,7 @@ public void startTimerCancelsExistingTimer() { final long BLOCK_TIME_STAMP = 500L; final BlockTimer timer = - new BlockTimer( - mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, mockExecutorService, mockClock); + new BlockTimer(mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, ibftExecutors, mockClock); when(mockClock.millis()).thenReturn(NOW_MILLIS); @@ -213,7 +207,7 @@ public void startTimerCancelsExistingTimer() { final ScheduledFuture mockedFuture = mock(ScheduledFuture.class); Mockito.>when( - mockExecutorService.schedule(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) + ibftExecutors.scheduleTask(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) .thenReturn(mockedFuture); timer.startTimer(round, header); verify(mockedFuture, times(0)).cancel(false); @@ -228,8 +222,7 @@ public void runningFollowsTheStateOfTheTimer() { final long BLOCK_TIME_STAMP = 500L; final BlockTimer timer = - new BlockTimer( - mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, mockExecutorService, mockClock); + new BlockTimer(mockQueue, MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS, ibftExecutors, mockClock); when(mockClock.millis()).thenReturn(NOW_MILLIS); @@ -240,7 +233,7 @@ public void runningFollowsTheStateOfTheTimer() { final ScheduledFuture mockedFuture = mock(ScheduledFuture.class); Mockito.>when( - mockExecutorService.schedule(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) + ibftExecutors.scheduleTask(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) .thenReturn(mockedFuture); timer.startTimer(round, header); when(mockedFuture.isDone()).thenReturn(false); diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataTest.java index 80737678e7d..cc2fb3a617a 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftExtraDataTest.java @@ -464,6 +464,15 @@ public void incorrectVoteTypeThrowsException() { .isInstanceOf(RLPException.class); } + @Test + public void emptyExtraDataThrowsException() { + final BytesValue bufferToInject = BytesValue.EMPTY; + + assertThatThrownBy(() -> IbftExtraData.decodeRaw(bufferToInject)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid BytesValue supplied - Ibft Extra Data required."); + } + private static byte[] createNonEmptyVanityData() { final byte[] vanity_bytes = new byte[32]; for (int i = 0; i < vanity_bytes.length; i++) { diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/RoundTimerTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/RoundTimerTest.java index bbbe2c29f19..173dbd4869c 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/RoundTimerTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/RoundTimerTest.java @@ -25,7 +25,6 @@ import org.hyperledger.besu.consensus.ibft.ibftevent.RoundExpiry; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -38,15 +37,15 @@ @RunWith(MockitoJUnitRunner.StrictStubs.class) public class RoundTimerTest { - private ScheduledExecutorService mockExecutorService; + private IbftExecutors ibftExecutors; private IbftEventQueue queue; private RoundTimer timer; @Before public void initialise() { - mockExecutorService = mock(ScheduledExecutorService.class); + ibftExecutors = mock(IbftExecutors.class); queue = new IbftEventQueue(1000); - timer = new RoundTimer(queue, 1, mockExecutorService); + timer = new RoundTimer(queue, 1, ibftExecutors); } @Test @@ -84,12 +83,10 @@ private void checkTimerForRound(final int roundNumber, final long timeout) { final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(1, roundNumber); final ScheduledFuture mockedFuture = mock(ScheduledFuture.class); Mockito.>when( - mockExecutorService.schedule( - any(Runnable.class), eq(timeout), eq(TimeUnit.MILLISECONDS))) + ibftExecutors.scheduleTask(any(Runnable.class), eq(timeout), eq(TimeUnit.MILLISECONDS))) .thenReturn(mockedFuture); timer.startTimer(round); - verify(mockExecutorService) - .schedule(any(Runnable.class), eq(timeout), eq(TimeUnit.MILLISECONDS)); + verify(ibftExecutors).scheduleTask(any(Runnable.class), eq(timeout), eq(TimeUnit.MILLISECONDS)); } @Test @@ -98,11 +95,11 @@ public void checkRunnableSubmittedDistributesCorrectEvent() throws InterruptedEx final ScheduledFuture mockedFuture = mock(ScheduledFuture.class); final ArgumentCaptor expiryRunnable = ArgumentCaptor.forClass(Runnable.class); Mockito.>when( - mockExecutorService.schedule(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) + ibftExecutors.scheduleTask(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) .thenReturn(mockedFuture); timer.startTimer(round); - verify(mockExecutorService) - .schedule(expiryRunnable.capture(), anyLong(), eq(TimeUnit.MILLISECONDS)); + verify(ibftExecutors) + .scheduleTask(expiryRunnable.capture(), anyLong(), eq(TimeUnit.MILLISECONDS)); assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNull(); expiryRunnable.getValue().run(); assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isEqualTo(new RoundExpiry(round)); @@ -113,7 +110,7 @@ public void startTimerCancelsExistingTimer() { final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(1, 0); final ScheduledFuture mockedFuture = mock(ScheduledFuture.class); Mockito.>when( - mockExecutorService.schedule(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) + ibftExecutors.scheduleTask(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) .thenReturn(mockedFuture); timer.startTimer(round); verify(mockedFuture, times(0)).cancel(false); @@ -126,7 +123,7 @@ public void runningFollowsTheStateOfTheTimer() { final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(1, 0); final ScheduledFuture mockedFuture = mock(ScheduledFuture.class); Mockito.>when( - mockExecutorService.schedule(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) + ibftExecutors.scheduleTask(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS))) .thenReturn(mockedFuture); timer.startTimer(round); when(mockedFuture.isDone()).thenReturn(false); diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinatorTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinatorTest.java index 32f04c03c74..45fe3ca434d 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinatorTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinatorTest.java @@ -15,12 +15,15 @@ package org.hyperledger.besu.consensus.ibft.blockcreation; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.hyperledger.besu.consensus.ibft.IbftEventQueue; +import org.hyperledger.besu.consensus.ibft.IbftExecutors; import org.hyperledger.besu.consensus.ibft.IbftProcessor; import org.hyperledger.besu.consensus.ibft.ibftevent.NewChainHead; +import org.hyperledger.besu.consensus.ibft.statemachine.IbftController; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Block; @@ -29,6 +32,7 @@ import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.util.bytes.BytesValue; +import java.util.Collections; import java.util.concurrent.TimeUnit; import org.assertj.core.util.Lists; @@ -40,6 +44,8 @@ @RunWith(MockitoJUnitRunner.class) public class IbftMiningCoordinatorTest { + @Mock private IbftController controller; + @Mock private IbftExecutors ibftExecutors; @Mock private IbftProcessor ibftProcessor; @Mock private IbftBlockCreatorFactory ibftBlockCreatorFactory; @Mock private Blockchain blockChain; @@ -52,20 +58,31 @@ public class IbftMiningCoordinatorTest { @Before public void setup() { ibftMiningCoordinator = - new IbftMiningCoordinator(ibftProcessor, ibftBlockCreatorFactory, blockChain, eventQueue); + new IbftMiningCoordinator( + ibftExecutors, + controller, + ibftProcessor, + ibftBlockCreatorFactory, + blockChain, + eventQueue); when(block.getBody()).thenReturn(blockBody); when(block.getHeader()).thenReturn(blockHeader); when(blockBody.getTransactions()).thenReturn(Lists.emptyList()); } @Test - public void enablesMining() { - ibftMiningCoordinator.enable(); + public void startsMining() { + ibftMiningCoordinator.start(); } @Test - public void disablesMining() { - ibftMiningCoordinator.disable(); + public void stopsMining() { + // Shouldn't stop without first starting + ibftMiningCoordinator.stop(); + verify(ibftProcessor, never()).stop(); + + ibftMiningCoordinator.start(); + ibftMiningCoordinator.stop(); verify(ibftProcessor).stop(); } @@ -85,7 +102,8 @@ public void setsTheExtraData() { @Test public void addsNewChainHeadEventWhenNewCanonicalHeadBlockEventReceived() throws Exception { - BlockAddedEvent headAdvancement = BlockAddedEvent.createForHeadAdvancement(block); + BlockAddedEvent headAdvancement = + BlockAddedEvent.createForHeadAdvancement(block, Collections.emptyList()); ibftMiningCoordinator.onBlockAdded(headAdvancement, blockChain); assertThat(eventQueue.size()).isEqualTo(1); diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetSignerMetricsTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetSignerMetricsTest.java index b69e9dc3109..ffa29c218bf 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetSignerMetricsTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetSignerMetricsTest.java @@ -25,9 +25,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.SignerMetricResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumberTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumberTest.java index 0ebd5ef877d..bae2ea6a640 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumberTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumberTest.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/queries/IbftQueryServiceImplTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/queries/IbftQueryServiceImplTest.java new file mode 100644 index 00000000000..a288492226d --- /dev/null +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/queries/IbftQueryServiceImplTest.java @@ -0,0 +1,145 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.consensus.ibft.queries; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.consensus.ibft.IbftBlockHashing; +import org.hyperledger.besu.consensus.ibft.IbftBlockHeaderFunctions; +import org.hyperledger.besu.consensus.ibft.IbftBlockInterface; +import org.hyperledger.besu.consensus.ibft.IbftExtraData; +import org.hyperledger.besu.crypto.SECP256K1; +import org.hyperledger.besu.crypto.SECP256K1.KeyPair; +import org.hyperledger.besu.crypto.SECP256K1.Signature; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.NonBesuBlockHeader; +import org.hyperledger.besu.ethereum.core.Util; +import org.hyperledger.besu.plugin.services.query.IbftQueryService; +import org.hyperledger.besu.util.bytes.BytesValue; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.google.common.collect.Lists; +import org.junit.Before; +import org.junit.Test; + +public class IbftQueryServiceImplTest { + + private Blockchain blockchain = mock(Blockchain.class); + + private final List validatorKeys = + Lists.newArrayList(KeyPair.generate(), KeyPair.generate()); + + private final List signingKeys = Lists.newArrayList(validatorKeys.get(0)); + private final int ROUND_NUMBER_IN_BLOCK = 5; + + private IbftExtraData signedExtraData; + private BlockHeader blockHeader; + + @Before + public void setup() { + + final Collection
validators = + validatorKeys.stream() + .map(validatorKeys -> Util.publicKeyToAddress(validatorKeys.getPublicKey())) + .collect(Collectors.toList()); + + final IbftExtraData unsignedExtraData = + new IbftExtraData( + BytesValue.wrap(new byte[32]), + Collections.emptyList(), + Optional.empty(), + ROUND_NUMBER_IN_BLOCK, + validators); + + final BlockHeaderTestFixture blockHeaderTestFixture = new BlockHeaderTestFixture(); + blockHeaderTestFixture.number(1); // can't be genesis block (due to extradata serialisation) + blockHeaderTestFixture.blockHeaderFunctions(IbftBlockHeaderFunctions.forOnChainBlock()); + blockHeaderTestFixture.extraData(unsignedExtraData.encode()); + + final BlockHeader unsignedBlockHeader = blockHeaderTestFixture.buildHeader(); + + final Collection validatorSignatures = + signingKeys.stream() + .map( + keyPair -> + SECP256K1.sign( + IbftBlockHashing.calculateDataHashForCommittedSeal(unsignedBlockHeader), + keyPair)) + .collect(Collectors.toList()); + + signedExtraData = + new IbftExtraData( + BytesValue.wrap(new byte[32]), + validatorSignatures, + Optional.empty(), + ROUND_NUMBER_IN_BLOCK, + validators); + + blockHeaderTestFixture.extraData(signedExtraData.encode()); + blockHeader = blockHeaderTestFixture.buildHeader(); + } + + @Test + public void roundNumberFromBlockIsReturned() { + final IbftQueryService service = new IbftQueryServiceImpl(new IbftBlockInterface(), blockchain); + + assertThat(service.getRoundNumberFrom(blockHeader)).isEqualTo(ROUND_NUMBER_IN_BLOCK); + } + + @Test + public void getRoundNumberThrowsIfBlockIsNotOnTheChain() { + final NonBesuBlockHeader header = + new NonBesuBlockHeader(blockHeader.getHash(), blockHeader.getExtraData()); + when(blockchain.getBlockHeader(blockHeader.getHash())).thenReturn(Optional.empty()); + + final IbftQueryService service = new IbftQueryServiceImpl(new IbftBlockInterface(), blockchain); + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> service.getRoundNumberFrom(header)); + } + + @Test + public void getSignersReturnsAddressesOfSignersInBlock() { + final IbftQueryService service = new IbftQueryServiceImpl(new IbftBlockInterface(), blockchain); + + final List
signers = + signingKeys.stream() + .map(keyPair -> Util.publicKeyToAddress(keyPair.getPublicKey())) + .collect(Collectors.toList()); + + assertThat(service.getSignersFrom(blockHeader)).containsExactlyElementsOf(signers); + } + + @Test + public void getSignersTheowsIfBlockIsNotOnTheChain() { + final NonBesuBlockHeader header = + new NonBesuBlockHeader(blockHeader.getHash(), blockHeader.getExtraData()); + when(blockchain.getBlockHeader(blockHeader.getHash())).thenReturn(Optional.empty()); + + final IbftQueryService service = new IbftQueryServiceImpl(new IbftBlockInterface(), blockchain); + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> service.getSignersFrom(header)); + } +} diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftControllerTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftControllerTest.java index ddf734be18f..f719b4c460f 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftControllerTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftControllerTest.java @@ -125,6 +125,9 @@ private void constructIbftController() { @Test public void createsNewBlockHeightManagerWhenStarted() { constructIbftController(); + verify(blockHeightManagerFactory, never()).create(chainHeadBlockHeader); + ibftController.start(); + verify(futureMessageBuffer, never()).addMessage(anyLong(), any()); verify(blockHeightManagerFactory).create(chainHeadBlockHeader); } @@ -143,6 +146,7 @@ public void startsNewBlockHeightManagerAndReplaysFutureMessages() { when(futureMessageBuffer.retrieveMessagesForHeight(2L)).thenReturn(height2Msgs); constructIbftController(); + ibftController.start(); verify(futureMessageBuffer).retrieveMessagesForHeight(2L); verify(futureMessageBuffer, never()).retrieveMessagesForHeight(3L); @@ -171,6 +175,7 @@ public void createsNewBlockHeightManagerAndReplaysFutureMessagesOnNewChainHeadEv when(blockHeightManager.getChainHeight()).thenReturn(2L); constructIbftController(); + ibftController.start(); final NewChainHead newChainHead = new NewChainHead(nextBlock); ibftController.handleNewBlockEvent(newChainHead); @@ -190,6 +195,7 @@ public void createsNewBlockHeightManagerAndReplaysFutureMessagesOnNewChainHeadEv @Test public void newBlockForCurrentOrPreviousHeightTriggersNoChange() { constructIbftController(); + ibftController.start(); long chainHeadHeight = chainHeadBlockHeader.getNumber(); when(nextBlock.getNumber()).thenReturn(chainHeadHeight); when(nextBlock.getHash()).thenReturn(Hash.ZERO); @@ -208,6 +214,7 @@ public void handlesRoundExpiry() { final RoundExpiry roundExpiry = new RoundExpiry(roundIdentifier); constructIbftController(); + ibftController.start(); ibftController.handleRoundExpiry(roundExpiry); verify(blockHeightManager).roundExpired(roundExpiry); @@ -218,6 +225,7 @@ public void handlesBlockTimerExpiry() { final BlockTimerExpiry blockTimerExpiry = new BlockTimerExpiry(roundIdentifier); constructIbftController(); + ibftController.start(); ibftController.handleBlockTimerExpiry(blockTimerExpiry); verify(blockHeightManager).handleBlockTimerExpiry(roundIdentifier); @@ -227,6 +235,7 @@ public void handlesBlockTimerExpiry() { public void proposalForCurrentHeightIsPassedToBlockHeightManager() { setupProposal(roundIdentifier, validator); constructIbftController(); + ibftController.start(); ibftController.handleMessageEvent(new IbftReceivedMessageEvent(proposalMessage)); verify(futureMessageBuffer, never()).addMessage(anyLong(), any()); @@ -240,6 +249,7 @@ public void proposalForCurrentHeightIsPassedToBlockHeightManager() { public void prepareForCurrentHeightIsPassedToBlockHeightManager() { setupPrepare(roundIdentifier, validator); constructIbftController(); + ibftController.start(); ibftController.handleMessageEvent(new IbftReceivedMessageEvent(prepareMessage)); verify(futureMessageBuffer, never()).addMessage(anyLong(), any()); @@ -253,6 +263,7 @@ public void prepareForCurrentHeightIsPassedToBlockHeightManager() { public void commitForCurrentHeightIsPassedToBlockHeightManager() { setupCommit(roundIdentifier, validator); constructIbftController(); + ibftController.start(); ibftController.handleMessageEvent(new IbftReceivedMessageEvent(commitMessage)); verify(futureMessageBuffer, never()).addMessage(anyLong(), any()); @@ -267,6 +278,7 @@ public void roundChangeForCurrentHeightIsPassedToBlockHeightManager() { roundIdentifier = new ConsensusRoundIdentifier(0, 1); setupRoundChange(roundIdentifier, validator); constructIbftController(); + ibftController.start(); ibftController.handleMessageEvent(new IbftReceivedMessageEvent(roundChangeMessage)); verify(futureMessageBuffer, never()).addMessage(anyLong(), any()); @@ -309,6 +321,7 @@ public void roundExpiryForPastHeightIsDiscarded() { final RoundExpiry roundExpiry = new RoundExpiry(roundIdentifier); when(blockHeightManager.getChainHeight()).thenReturn(1L); constructIbftController(); + ibftController.start(); ibftController.handleRoundExpiry(roundExpiry); verify(futureMessageBuffer, never()).addMessage(anyLong(), any()); verify(blockHeightManager, never()).roundExpired(any()); @@ -319,6 +332,7 @@ public void blockTimerForPastHeightIsDiscarded() { final BlockTimerExpiry blockTimerExpiry = new BlockTimerExpiry(roundIdentifier); when(blockHeightManager.getChainHeight()).thenReturn(1L); constructIbftController(); + ibftController.start(); ibftController.handleBlockTimerExpiry(blockTimerExpiry); verify(futureMessageBuffer, never()).addMessage(anyLong(), any()); verify(blockHeightManager, never()).handleBlockTimerExpiry(any()); @@ -385,6 +399,7 @@ public void uniqueMessagesAreAddedAsSeen() { when(messageTracker.hasSeenMessage(proposalMessageData)).thenReturn(false); setupProposal(roundIdentifier, validator); constructIbftController(); + ibftController.start(); ibftController.handleMessageEvent(new IbftReceivedMessageEvent(proposalMessage)); verify(messageTracker).addSeenMessage(proposalMessageData); @@ -392,6 +407,7 @@ public void uniqueMessagesAreAddedAsSeen() { private void verifyNotHandledAndNoFutureMsgs(final IbftReceivedMessageEvent msg) { constructIbftController(); + ibftController.start(); ibftController.handleMessageEvent(msg); verify(futureMessageBuffer, never()).addMessage(anyLong(), any()); @@ -401,6 +417,7 @@ private void verifyNotHandledAndNoFutureMsgs(final IbftReceivedMessageEvent msg) private void verifyHasFutureMessages(final long msgHeight, final Message message) { constructIbftController(); + ibftController.start(); ibftController.handleMessageEvent(new IbftReceivedMessageEvent(message)); verify(futureMessageBuffer).addMessage(msgHeight, message); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java index f20084306f8..f7db26acd09 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java @@ -34,13 +34,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionCompleteResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionHashResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionResult; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; @@ -160,7 +160,7 @@ public TransactionResult transaction( when(transaction.getV()).thenReturn(bigInteger(v)); when(transaction.getR()).thenReturn(bigInteger(r)); when(transaction.getS()).thenReturn(bigInteger(s)); - when(transaction.hash()).thenReturn(hash(hash)); + when(transaction.getHash()).thenReturn(hash(hash)); when(transaction.getTo()).thenReturn(Optional.ofNullable(address(toAddress))); when(transaction.getSender()).thenReturn(address(fromAddress)); when(transaction.getPayload()).thenReturn(bytes(input)); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java index 27d9f8b407d..a9f8c40a6b0 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java @@ -24,8 +24,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterRepository; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java index 282454b646b..ee85ca3781b 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java @@ -29,11 +29,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterRepository; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetFilterChanges; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Block; @@ -216,7 +216,7 @@ public void shouldReturnHashesIfNewPendingTransactions() { // We've added one transaction, so there should be one new hash. expected = - new JsonRpcSuccessResponse(null, Lists.newArrayList(String.valueOf(transaction.hash()))); + new JsonRpcSuccessResponse(null, Lists.newArrayList(String.valueOf(transaction.getHash()))); actual = method.response(request); assertThat(actual).isEqualToComparingFieldByField(expected); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java index 34964e6594c..ad44bfbe5fc 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java @@ -25,13 +25,13 @@ import org.hyperledger.besu.enclave.types.SendRequest; import org.hyperledger.besu.enclave.types.SendRequestLegacy; import org.hyperledger.besu.enclave.types.SendResponse; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetPrivateTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionLegacyResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.PrivacyParameters; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/LogsQuery.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/LogsQuery.java deleted file mode 100644 index 49a181db291..00000000000 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/LogsQuery.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api; - -import org.hyperledger.besu.ethereum.core.Address; -import org.hyperledger.besu.ethereum.core.Log; -import org.hyperledger.besu.ethereum.core.LogTopic; - -import java.util.Arrays; -import java.util.List; - -import com.google.common.collect.Lists; - -public class LogsQuery { - - private final List
queryAddresses; - private final List> queryTopics; - - private LogsQuery(final List
addresses, final List> topics) { - this.queryAddresses = addresses; - this.queryTopics = topics; - } - - public boolean matches(final Log log) { - return matchesAddresses(log.getLogger()) && matchesTopics(log.getTopics()); - } - - private boolean matchesAddresses(final Address address) { - return queryAddresses.isEmpty() || queryAddresses.contains(address); - } - - private boolean matchesTopics(final List topics) { - if (queryTopics.isEmpty()) { - return true; - } - if (topics.size() < queryTopics.size()) { - return false; - } - for (int i = 0; i < queryTopics.size(); ++i) { - if (!matchesTopic(topics.get(i), queryTopics.get(i))) { - return false; - } - } - return true; - } - - private boolean matchesTopic(final LogTopic topic, final List matchCriteria) { - for (final LogTopic candidate : matchCriteria) { - if (candidate == null) { - return true; - } - if (candidate.equals(topic)) { - return true; - } - } - return false; - } - - public static class Builder { - private final List
queryAddresses = Lists.newArrayList(); - private final List> queryTopics = Lists.newArrayList(); - - public Builder address(final Address address) { - if (address != null) { - queryAddresses.add(address); - } - return this; - } - - public Builder addresses(final Address... addresses) { - if (addresses != null && addresses.length > 0) { - queryAddresses.addAll(Arrays.asList(addresses)); - } - return this; - } - - public Builder addresses(final List
addresses) { - if (addresses != null && !addresses.isEmpty()) { - queryAddresses.addAll(addresses); - } - return this; - } - - public Builder topics(final List> topics) { - if (topics != null && !topics.isEmpty()) { - queryTopics.addAll(topics); - } - return this; - } - - public Builder topics(final TopicsParameter topicsParameter) { - if (topicsParameter != null) { - topics(topicsParameter.getTopics()); - } - return this; - } - - public LogsQuery build() { - return new LogsQuery(queryAddresses, queryTopics); - } - } -} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/TopicsParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/TopicsParameter.java deleted file mode 100644 index 3071271941e..00000000000 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/TopicsParameter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api; - -import org.hyperledger.besu.ethereum.core.LogTopic; -import org.hyperledger.besu.util.bytes.BytesValue; - -import java.util.ArrayList; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonCreator; - -public class TopicsParameter { - - private final List> queryTopics = new ArrayList<>(); - - @JsonCreator - public TopicsParameter(final List> topics) { - if (topics != null) { - for (final List list : topics) { - final List inputTopics = new ArrayList<>(); - if (list != null) { - for (final String input : list) { - final LogTopic topic = - input != null ? LogTopic.create(BytesValue.fromHexString(input)) : null; - inputTopics.add(topic); - } - } - queryTopics.add(inputTopics); - } - } - } - - public List> getTopics() { - return queryTopics; - } - - @Override - public String toString() { - return "TopicsParameter{" + "queryTopics=" + queryTopics + '}'; - } -} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetcherContext.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetcherContext.java index 59dc3d2f2b8..c8c268bc1b4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetcherContext.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetcherContext.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.graphql; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Synchronizer; @@ -24,7 +24,7 @@ public class GraphQLDataFetcherContext { - private final BlockchainQuery blockchain; + private final BlockchainQueries blockchain; private final MiningCoordinator miningCoordinator; private final Synchronizer synchronizer; private final ProtocolSchedule protocolSchedule; @@ -37,7 +37,7 @@ public GraphQLDataFetcherContext( final TransactionPool transactionPool, final MiningCoordinator miningCoordinator, final Synchronizer synchronizer) { - this.blockchain = new BlockchainQuery(blockchain, worldStateArchive); + this.blockchain = new BlockchainQueries(blockchain, worldStateArchive); this.protocolSchedule = protocolSchedule; this.miningCoordinator = miningCoordinator; this.synchronizer = synchronizer; @@ -48,7 +48,7 @@ public TransactionPool getTransactionPool() { return transactionPool; } - public BlockchainQuery getBlockchainQuery() { + public BlockchainQueries getBlockchainQueries() { return blockchain; } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java index f1cc56df8fd..df1105274a8 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java @@ -16,22 +16,26 @@ import static com.google.common.base.Preconditions.checkArgument; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; import org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.AccountAdapter; +import org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.LogAdapter; import org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.NormalBlockAdapter; import org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.PendingStateAdapter; import org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.SyncStateAdapter; import org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.TransactionAdapter; import org.hyperledger.besu.ethereum.api.graphql.internal.response.GraphQLError; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; +import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.WorldState; import org.hyperledger.besu.ethereum.eth.EthProtocol; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason; @@ -46,9 +50,11 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.OptionalInt; import java.util.Set; +import java.util.stream.Collectors; import com.google.common.base.Preconditions; import graphql.schema.DataFetcher; @@ -80,7 +86,7 @@ DataFetcher> getSendRawTransactionDataFetcher() { final ValidationResult validationResult = transactionPool.addLocalTransaction(transaction); if (validationResult.isValid()) { - return Optional.of(transaction.hash()); + return Optional.of(transaction.getHash()); } else { throw new GraphQLException(GraphQLError.of(validationResult.getInvalidReason())); } @@ -119,8 +125,8 @@ DataFetcher> getGasPriceDataFetcher() { DataFetcher> getRangeBlockDataFetcher() { return dataFetchingEnvironment -> { - final BlockchainQuery blockchainQuery = - ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQuery(); + final BlockchainQueries blockchainQuery = + ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQueries(); final long from = dataFetchingEnvironment.getArgument("from"); final long to; @@ -146,8 +152,8 @@ DataFetcher> getRangeBlockDataFetcher() { public DataFetcher> getBlockDataFetcher() { return dataFetchingEnvironment -> { - final BlockchainQuery blockchain = - ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQuery(); + final BlockchainQueries blockchain = + ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQueries(); final Long number = dataFetchingEnvironment.getArgument("number"); final Bytes32 hash = dataFetchingEnvironment.getArgument("hash"); if ((number != null) && (hash != null)) { @@ -170,12 +176,12 @@ public DataFetcher> getBlockDataFetcher() { DataFetcher> getAccountDataFetcher() { return dataFetchingEnvironment -> { - final BlockchainQuery blockchainQuery = - ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQuery(); + final BlockchainQueries blockchainQuery = + ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQueries(); final Address addr = dataFetchingEnvironment.getArgument("address"); final Long bn = dataFetchingEnvironment.getArgument("blockNumber"); if (bn != null) { - final Optional ws = blockchainQuery.getWorldState(bn); + final Optional ws = blockchainQuery.getWorldState(bn); if (ws.isPresent()) { final Account account = ws.get().get(addr); Preconditions.checkArgument( @@ -191,7 +197,7 @@ DataFetcher> getAccountDataFetcher() { } else { // return account on latest block final long latestBn = blockchainQuery.latestBlock().get().getHeader().getNumber(); - final Optional ows = blockchainQuery.getWorldState(latestBn); + final Optional ows = blockchainQuery.getWorldState(latestBn); return ows.flatMap( ws -> { Account account = ws.get(addr); @@ -204,10 +210,47 @@ DataFetcher> getAccountDataFetcher() { }; } + DataFetcher>> getLogsDataFetcher() { + return dataFetchingEnvironment -> { + final BlockchainQueries blockchainQuery = + ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQueries(); + + final Map filter = dataFetchingEnvironment.getArgument("filter"); + + final long currentBlock = blockchainQuery.getBlockchain().getChainHeadBlockNumber(); + final long fromBlock = (Long) filter.getOrDefault("fromBlock", currentBlock); + final long toBlock = (Long) filter.getOrDefault("toBlock", currentBlock); + + if (fromBlock > toBlock) { + throw new GraphQLException(GraphQLError.INVALID_PARAMS); + } + + @SuppressWarnings("unchecked") + final List
addrs = (List
) filter.get("addresses"); + @SuppressWarnings("unchecked") + final List> topics = (List>) filter.get("topics"); + + final List> transformedTopics = new ArrayList<>(); + for (final List topic : topics) { + transformedTopics.add(topic.stream().map(LogTopic::of).collect(Collectors.toList())); + } + + final LogsQuery query = + new LogsQuery.Builder().addresses(addrs).topics(transformedTopics).build(); + + final List logs = blockchainQuery.matchingLogs(fromBlock, toBlock, query); + final List results = new ArrayList<>(); + for (final LogWithMetadata log : logs) { + results.add(new LogAdapter(log)); + } + return Optional.of(results); + }; + } + DataFetcher> getTransactionDataFetcher() { return dataFetchingEnvironment -> { - final BlockchainQuery blockchain = - ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQuery(); + final BlockchainQueries blockchain = + ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQueries(); final Bytes32 hash = dataFetchingEnvironment.getArgument("hash"); final Optional tran = blockchain.transactionByHash(Hash.wrap(hash)); return tran.map(TransactionAdapter::new); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLProvider.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLProvider.java index 456a2c376cd..4ef33996dc3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLProvider.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLProvider.java @@ -61,6 +61,7 @@ private static RuntimeWiring buildWiring(final GraphQLDataFetchers graphQLDataFe .dataFetcher("account", graphQLDataFetchers.getAccountDataFetcher()) .dataFetcher("block", graphQLDataFetchers.getBlockDataFetcher()) .dataFetcher("blocks", graphQLDataFetchers.getRangeBlockDataFetcher()) + .dataFetcher("logs", graphQLDataFetchers.getLogsDataFetcher()) .dataFetcher("transaction", graphQLDataFetchers.getTransactionDataFetcher()) .dataFetcher("gasPrice", graphQLDataFetchers.getGasPriceDataFetcher()) .dataFetcher("syncing", graphQLDataFetchers.getSyncingDataFetcher()) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/BlockchainQuery.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/BlockchainQuery.java deleted file mode 100644 index 803613c9408..00000000000 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/BlockchainQuery.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api.graphql.internal; - -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.LogsQuery; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; -import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.chain.TransactionLocation; -import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockBody; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.Hash; -import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.TransactionReceipt; -import org.hyperledger.besu.ethereum.core.WorldState; -import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import com.google.common.collect.Lists; - -public class BlockchainQuery { - - private final WorldStateArchive worldStateArchive; - private final Blockchain blockchain; - - public BlockchainQuery(final Blockchain blockchain, final WorldStateArchive worldStateArchive) { - this.blockchain = blockchain; - this.worldStateArchive = worldStateArchive; - } - - public Blockchain getBlockchain() { - return blockchain; - } - - public WorldStateArchive getWorldStateArchive() { - return worldStateArchive; - } - - /** - * Returns the ommer at the given index for the referenced block. - * - * @param blockHeaderHash The hash of the block to be queried. - * @param index The index of the ommer in the blocks ommers list. - * @return The ommer at the given index belonging to the referenced block. - */ - public Optional getOmmer(final Hash blockHeaderHash, final int index) { - return blockchain.getBlockBody(blockHeaderHash).map(blockBody -> getOmmer(blockBody, index)); - } - - private BlockHeader getOmmer(final BlockBody blockBody, final int index) { - final List ommers = blockBody.getOmmers(); - if (ommers.size() > index) { - return ommers.get(index); - } else { - return null; - } - } - - /** - * Given a block hash, returns the associated block augmented with metadata. - * - * @param blockHeaderHash The hash of the target block's header. - * @return The referenced block. - */ - public Optional> blockByHash( - final Hash blockHeaderHash) { - return blockchain - .getBlockHeader(blockHeaderHash) - .flatMap( - header -> - blockchain - .getBlockBody(blockHeaderHash) - .flatMap( - body -> - blockchain - .getTotalDifficultyByHash(blockHeaderHash) - .map( - (td) -> { - final List txs = body.getTransactions(); - final List formattedTxs = - formatTransactions( - txs, header.getNumber(), blockHeaderHash); - final List ommers = - body.getOmmers().stream() - .map(BlockHeader::getHash) - .collect(Collectors.toList()); - final int size = new Block(header, body).calculateSize(); - return new BlockWithMetadata<>( - header, formattedTxs, ommers, td, size); - }))); - } - - /** - * Given a block number, returns the associated block augmented with metadata. - * - * @param number The height of the target block. - * @return The referenced block. - */ - public Optional> blockByNumber( - final long number) { - return blockchain.getBlockHashByNumber(number).flatMap(this::blockByHash); - } - - /** - * Returns the latest block augmented with metadata. - * - * @return The latest block. - */ - public Optional> latestBlock() { - return this.blockByHash(blockchain.getChainHeadHash()); - } - - /** - * Given a transaction hash, returns the associated transaction. - * - * @param transactionHash The hash of the target transaction. - * @return The transaction associated with the given hash. - */ - public Optional transactionByHash(final Hash transactionHash) { - final Optional maybeLocation = - blockchain.getTransactionLocation(transactionHash); - if (!maybeLocation.isPresent()) { - return Optional.empty(); - } - final TransactionLocation loc = maybeLocation.get(); - final Hash blockHash = loc.getBlockHash(); - final BlockHeader header = blockchain.getBlockHeader(blockHash).get(); - final Transaction transaction = blockchain.getTransactionByHash(transactionHash).get(); - return Optional.of( - new TransactionWithMetadata( - transaction, header.getNumber(), blockHash, loc.getTransactionIndex())); - } - - /** - * Returns the transaction receipt associated with the given transaction hash. - * - * @param transactionHash The hash of the transaction that corresponds to the receipt to retrieve. - * @return The transaction receipt associated with the referenced transaction. - */ - public Optional transactionReceiptByTransactionHash( - final Hash transactionHash) { - final Optional maybeLocation = - blockchain.getTransactionLocation(transactionHash); - if (!maybeLocation.isPresent()) { - return Optional.empty(); - } - final TransactionLocation location = maybeLocation.get(); - final BlockBody blockBody = blockchain.getBlockBody(location.getBlockHash()).get(); - final Transaction transaction = blockBody.getTransactions().get(location.getTransactionIndex()); - - final Hash blockhash = location.getBlockHash(); - final BlockHeader header = blockchain.getBlockHeader(blockhash).get(); - final List transactionReceipts = blockchain.getTxReceipts(blockhash).get(); - final TransactionReceipt transactionReceipt = - transactionReceipts.get(location.getTransactionIndex()); - - long gasUsed = transactionReceipt.getCumulativeGasUsed(); - if (location.getTransactionIndex() > 0) { - gasUsed = - gasUsed - - transactionReceipts.get(location.getTransactionIndex() - 1).getCumulativeGasUsed(); - } - - return Optional.of( - new TransactionReceiptWithMetadata( - transactionReceipt, - transaction, - transactionHash, - location.getTransactionIndex(), - gasUsed, - blockhash, - header.getNumber())); - } - - /** - * Returns the world state for the corresponding block number - * - * @param blockNumber the block number - * @return the world state at the block number - */ - public Optional getWorldState(final long blockNumber) { - final Optional header = blockchain.getBlockHeader(blockNumber); - return header - .map(BlockHeader::getStateRoot) - .flatMap(worldStateArchive::getMutable) - .map(mws -> mws); // to satisfy typing - } - - private List formatTransactions( - final List txs, final long blockNumber, final Hash blockHash) { - final int count = txs.size(); - final List result = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - result.add(new TransactionWithMetadata(txs.get(i), blockNumber, blockHash, i)); - } - return result; - } - - public List matchingLogs(final Hash blockhash, final LogsQuery query) { - final List matchingLogs = Lists.newArrayList(); - final Optional blockHeader = blockchain.getBlockHeader(blockhash); - if (!blockHeader.isPresent()) { - return matchingLogs; - } - final List receipts = blockchain.getTxReceipts(blockhash).get(); - final List transaction = - blockchain.getBlockBody(blockhash).get().getTransactions(); - final long number = blockHeader.get().getNumber(); - final boolean logHasBeenRemoved = !blockchain.blockIsOnCanonicalChain(blockhash); - return generateLogWithMetadata( - receipts, number, query, blockhash, matchingLogs, transaction, logHasBeenRemoved); - } - - private List generateLogWithMetadata( - final List receipts, - final long number, - final LogsQuery query, - final Hash blockhash, - final List matchingLogs, - final List transaction, - final boolean removed) { - for (int transactionIndex = 0; transactionIndex < receipts.size(); ++transactionIndex) { - final TransactionReceipt receipt = receipts.get(transactionIndex); - for (int logIndex = 0; logIndex < receipt.getLogs().size(); ++logIndex) { - if (query.matches(receipt.getLogs().get(logIndex))) { - final LogWithMetadata logWithMetaData = - new LogWithMetadata( - logIndex, - number, - blockhash, - transaction.get(transactionIndex).hash(), - transactionIndex, - receipts.get(transactionIndex).getLogs().get(logIndex).getLogger(), - receipts.get(transactionIndex).getLogs().get(logIndex).getData(), - receipts.get(transactionIndex).getLogs().get(logIndex).getTopics(), - removed); - matchingLogs.add(logWithMetaData); - } - } - } - return matchingLogs; - } - - public static List generateLogWithMetadataForTransaction( - final TransactionReceipt receipt, - final long number, - final Hash blockhash, - final Hash transactionHash, - final int transactionIndex, - final boolean removed) { - - final List logs = new ArrayList<>(); - for (int logIndex = 0; logIndex < receipt.getLogs().size(); ++logIndex) { - - final LogWithMetadata logWithMetaData = - new LogWithMetadata( - logIndex, - number, - blockhash, - transactionHash, - transactionIndex, - receipt.getLogs().get(logIndex).getLogger(), - receipt.getLogs().get(logIndex).getData(), - receipt.getLogs().get(logIndex).getTopics(), - removed); - logs.add(logWithMetaData); - } - - return logs; - } -} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/TransactionReceiptWithMetadata.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/TransactionReceiptWithMetadata.java deleted file mode 100644 index ecf6f1ec7ba..00000000000 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/TransactionReceiptWithMetadata.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api.graphql.internal; - -import org.hyperledger.besu.ethereum.core.Hash; -import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.TransactionReceipt; - -public class TransactionReceiptWithMetadata { - private final TransactionReceipt receipt; - private final Hash transactionHash; - private final int transactionIndex; - private final long gasUsed; - private final long blockNumber; - private final Hash blockHash; - private final Transaction transaction; - - TransactionReceiptWithMetadata( - final TransactionReceipt receipt, - final Transaction transaction, - final Hash transactionHash, - final int transactionIndex, - final long gasUsed, - final Hash blockHash, - final long blockNumber) { - this.receipt = receipt; - this.transactionHash = transactionHash; - this.transactionIndex = transactionIndex; - this.gasUsed = gasUsed; - this.blockHash = blockHash; - this.blockNumber = blockNumber; - this.transaction = transaction; - } - - public TransactionReceipt getReceipt() { - return receipt; - } - - public Hash getTransactionHash() { - return transactionHash; - } - - public Transaction getTransaction() { - return transaction; - } - - public int getTransactionIndex() { - return transactionIndex; - } - - public Hash getBlockHash() { - return blockHash; - } - - public long getBlockNumber() { - return blockNumber; - } - - // The gas used for this particular transaction (as opposed to cumulativeGas which is included in - // the receipt itself) - public long getGasUsed() { - return gasUsed; - } -} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AdapterBase.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AdapterBase.java index ad5c4f7f246..6d256d62b37 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AdapterBase.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AdapterBase.java @@ -15,12 +15,12 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter; import org.hyperledger.besu.ethereum.api.graphql.GraphQLDataFetcherContext; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import graphql.schema.DataFetchingEnvironment; abstract class AdapterBase { - BlockchainQuery getBlockchainQuery(final DataFetchingEnvironment environment) { - return ((GraphQLDataFetcherContext) environment.getContext()).getBlockchainQuery(); + BlockchainQueries getBlockchainQueries(final DataFetchingEnvironment environment) { + return ((GraphQLDataFetcherContext) environment.getContext()).getBlockchainQueries(); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java index 5749385f374..00d4c21b779 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java @@ -14,16 +14,16 @@ */ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.LogsQuery; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.graphql.GraphQLDataFetcherContext; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.WorldState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; @@ -53,7 +53,7 @@ public class BlockAdapterBase extends AdapterBase { } public Optional getParent(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final Hash parentHash = header.getParentHash(); final Optional> block = query.blockByHash(parentHash); @@ -84,7 +84,7 @@ public Optional getReceiptsRoot() { public Optional getMiner(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); long blockNumber = header.getNumber(); final Long bn = environment.getArgument("block"); if (bn != null) { @@ -133,7 +133,7 @@ public Optional getNumber() { public Optional getAccount(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final long bn = header.getNumber(); final WorldState ws = query.getWorldState(bn).get(); @@ -161,7 +161,7 @@ public List getLogs(final DataFetchingEnvironment environment) { final LogsQuery query = new LogsQuery.Builder().addresses(addrs).topics(transformedTopics).build(); - final BlockchainQuery blockchain = getBlockchainQuery(environment); + final BlockchainQueries blockchain = getBlockchainQueries(environment); final Hash hash = header.getHash(); final List logs = blockchain.matchingLogs(hash, query); @@ -190,7 +190,7 @@ private Optional executeCall(final DataFetchingEnvironment environme final UInt256 value = (UInt256) callData.get("value"); final BytesValue data = (BytesValue) callData.get("data"); - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final ProtocolSchedule protocolSchedule = ((GraphQLDataFetcherContext) environment.getContext()).getProtocolSchedule(); final long bn = header.getNumber(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java index c19b10a0b0c..f160dc2f129 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java @@ -14,11 +14,11 @@ */ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.util.bytes.Bytes32; import org.hyperledger.besu.util.bytes.BytesValue; @@ -32,7 +32,7 @@ public class LogAdapter extends AdapterBase { private final LogWithMetadata logWithMetadata; - LogAdapter(final LogWithMetadata logWithMetadata) { + public LogAdapter(final LogWithMetadata logWithMetadata) { this.logWithMetadata = logWithMetadata; } @@ -54,14 +54,14 @@ public Optional getData() { } public Optional getTransaction(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final Hash hash = logWithMetadata.getTransactionHash(); final Optional tran = query.transactionByHash(hash); return tran.map(TransactionAdapter::new); } public Optional getAccount(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); long blockNumber = logWithMetadata.getBlockNumber(); final Long bn = environment.getArgument("block"); if (bn != null) { @@ -70,6 +70,6 @@ public Optional getAccount(final DataFetchingEnvironment environ return query .getWorldState(blockNumber) - .map(ws -> new AccountAdapter(ws.get(logWithMetadata.getAddress()))); + .map(ws -> new AccountAdapter(ws.get(logWithMetadata.getLogger()))); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java index 4851f8b4d44..4805c90738b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java @@ -14,9 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.util.uint.UInt256; @@ -51,7 +51,7 @@ public Optional getOmmerCount() { } public List getOmmers(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final List ommers = blockWithMetaData.getOmmers(); final List results = new ArrayList<>(); final Hash hash = blockWithMetaData.getHeader().getHash(); @@ -64,7 +64,7 @@ public List getOmmers(final DataFetchingEnvironment environme } public Optional getOmmerAt(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final int index = environment.getArgument("index"); final List ommers = blockWithMetaData.getOmmers(); if (ommers.size() > index) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java index d1f2eb6c46f..8452b228d3b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java @@ -14,12 +14,12 @@ */ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.graphql.GraphQLDataFetcherContext; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Wei; -import org.hyperledger.besu.ethereum.core.WorldState; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.transaction.CallParameter; @@ -60,12 +60,12 @@ public List getTransactions() { // speculative environment, so estimate against latest. public Optional getAccount( final DataFetchingEnvironment dataFetchingEnvironment) { - final BlockchainQuery blockchainQuery = - ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQuery(); + final BlockchainQueries blockchainQuery = + ((GraphQLDataFetcherContext) dataFetchingEnvironment.getContext()).getBlockchainQueries(); final Address addr = dataFetchingEnvironment.getArgument("address"); final Long blockNumber = dataFetchingEnvironment.getArgument("blockNumber"); final long latestBlockNumber = blockchainQuery.latestBlock().get().getHeader().getNumber(); - final Optional optionalWorldState = + final Optional optionalWorldState = blockchainQuery.getWorldState(latestBlockNumber); return optionalWorldState .flatMap(worldState -> Optional.ofNullable(worldState.get(addr))) @@ -90,7 +90,7 @@ public Optional getCall(final DataFetchingEnvironment environment) { final UInt256 value = (UInt256) callData.get("value"); final BytesValue data = (BytesValue) callData.get("data"); - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final ProtocolSchedule protocolSchedule = ((GraphQLDataFetcherContext) environment.getContext()).getProtocolSchedule(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java index 1e74f4795d3..0f36359fd75 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java @@ -14,15 +14,15 @@ */ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; -import org.hyperledger.besu.ethereum.api.graphql.internal.TransactionReceiptWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; +import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; -import org.hyperledger.besu.ethereum.core.WorldState; import org.hyperledger.besu.util.bytes.BytesValue; import org.hyperledger.besu.util.uint.UInt256; @@ -41,7 +41,7 @@ public TransactionAdapter(final TransactionWithMetadata transactionWithMetadata) } public Optional getHash() { - return Optional.of(transactionWithMetadata.getTransaction().hash()); + return Optional.of(transactionWithMetadata.getTransaction().getHash()); } public Optional getNonce() { @@ -54,7 +54,7 @@ public Optional getIndex() { } public Optional getFrom(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final Optional txBlockNumber = transactionWithMetadata.getBlockNumber(); final Optional bn = Optional.ofNullable(environment.getArgument("block")); if (!txBlockNumber.isPresent() && !bn.isPresent()) { @@ -69,7 +69,7 @@ public Optional getFrom(final DataFetchingEnvironment environmen } public Optional getTo(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final Optional txBlockNumber = transactionWithMetadata.getBlockNumber(); final Optional bn = Optional.ofNullable(environment.getArgument("block")); if (!txBlockNumber.isPresent() && !bn.isPresent()) { @@ -105,14 +105,14 @@ public Optional getInputData() { public Optional getBlock(final DataFetchingEnvironment environment) { return transactionWithMetadata .getBlockHash() - .flatMap(blockHash -> getBlockchainQuery(environment).blockByHash(blockHash)) + .flatMap(blockHash -> getBlockchainQueries(environment).blockByHash(blockHash)) .map(NormalBlockAdapter::new); } public Optional getStatus(final DataFetchingEnvironment environment) { return Optional.ofNullable(transactionWithMetadata.getTransaction()) - .map(Transaction::hash) - .flatMap(rpt -> getBlockchainQuery(environment).transactionReceiptByTransactionHash(rpt)) + .map(Transaction::getHash) + .flatMap(rpt -> getBlockchainQueries(environment).transactionReceiptByTransactionHash(rpt)) .map(TransactionReceiptWithMetadata::getReceipt) .flatMap( receipt -> @@ -122,16 +122,18 @@ public Optional getStatus(final DataFetchingEnvironment environment) { } public Optional getGasUsed(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final Optional rpt = - query.transactionReceiptByTransactionHash(transactionWithMetadata.getTransaction().hash()); + query.transactionReceiptByTransactionHash( + transactionWithMetadata.getTransaction().getHash()); return rpt.map(TransactionReceiptWithMetadata::getGasUsed); } public Optional getCumulativeGasUsed(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final Optional rpt = - query.transactionReceiptByTransactionHash(transactionWithMetadata.getTransaction().hash()); + query.transactionReceiptByTransactionHash( + transactionWithMetadata.getTransaction().getHash()); if (rpt.isPresent()) { final TransactionReceipt receipt = rpt.get().getReceipt(); return Optional.of(receipt.getCumulativeGasUsed()); @@ -145,7 +147,7 @@ public Optional getCreatedContract(final DataFetchingEnvironment final Optional
addr = transactionWithMetadata.getTransaction().getTo(); if (addr.isPresent()) { - final BlockchainQuery query = getBlockchainQuery(environment); + final BlockchainQueries query = getBlockchainQueries(environment); final Optional txBlockNumber = transactionWithMetadata.getBlockNumber(); final Optional bn = Optional.ofNullable(environment.getArgument("block")); if (!txBlockNumber.isPresent() && !bn.isPresent()) { @@ -153,7 +155,7 @@ public Optional getCreatedContract(final DataFetchingEnvironment } final long blockNumber = bn.orElseGet(txBlockNumber::get); - final Optional ws = query.getWorldState(blockNumber); + final Optional ws = query.getWorldState(blockNumber); if (ws.isPresent()) { return Optional.of(new AccountAdapter(ws.get().get(addr.get()))); } @@ -163,15 +165,15 @@ public Optional getCreatedContract(final DataFetchingEnvironment } public List getLogs(final DataFetchingEnvironment environment) { - final BlockchainQuery query = getBlockchainQuery(environment); - final Hash hash = transactionWithMetadata.getTransaction().hash(); - final Optional tranRpt = + final BlockchainQueries query = getBlockchainQueries(environment); + final Hash hash = transactionWithMetadata.getTransaction().getHash(); + final Optional maybeTransactionReceiptWithMetadata = query.transactionReceiptByTransactionHash(hash); final List results = new ArrayList<>(); - if (tranRpt.isPresent()) { + if (maybeTransactionReceiptWithMetadata.isPresent()) { final List logs = - BlockchainQuery.generateLogWithMetadataForTransaction( - tranRpt.get().getReceipt(), + LogWithMetadata.generate( + maybeTransactionReceiptWithMetadata.get().getReceipt(), transactionWithMetadata.getBlockNumber().get(), transactionWithMetadata.getBlockHash().get(), hash, diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcMethodsFactory.java deleted file mode 100644 index 7d52ac5c0e1..00000000000 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcMethodsFactory.java +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api.jsonrpc; - -import org.hyperledger.besu.config.GenesisConfigOptions; -import org.hyperledger.besu.enclave.Enclave; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminAddPeer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminChangeLogLevel; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminNodeInfo; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminPeers; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminRemovePeer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugAccountRange; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugMetrics; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugStorageRangeAt; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlock; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlockByHash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlockByNumber; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthAccounts; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthBlockNumber; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthCall; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthChainId; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthCoinbase; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthEstimateGas; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGasPrice; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBalance; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockByHash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockByNumber; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockTransactionCountByHash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockTransactionCountByNumber; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetCode; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetFilterChanges; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetFilterLogs; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetLogs; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetProof; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetStorageAt; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionByBlockHashAndIndex; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionByBlockNumberAndIndex; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionByHash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionCount; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionReceipt; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetUncleByBlockHashAndIndex; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetUncleByBlockNumberAndIndex; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetUncleCountByBlockHash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetUncleCountByBlockNumber; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetWork; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthHashrate; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthMining; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthNewBlockFilter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthNewFilter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthNewPendingTransactionFilter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthProtocolVersion; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSendRawTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSendTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSyncing; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthUninstallFilter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetEnode; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetListening; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetPeerCount; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetServices; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetVersion; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.RpcModules; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuStatistics; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuTransactions; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.Web3ClientVersion; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.Web3Sha3; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetCoinbase; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetEtherbase; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerStart; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerStop; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermAddAccountsToWhitelist; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermAddNodesToWhitelist; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermGetAccountsWhitelist; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermGetNodesWhitelist; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermReloadPermissionsFromFile; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermRemoveAccountsFromWhitelist; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermRemoveNodesFromWhitelist; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea.EeaGetTransactionCount; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea.EeaPrivateNonceProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea.EeaSendRawTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivCreatePrivacyGroup; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivDeletePrivacyGroup; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivDistributeRawTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivFindPrivacyGroup; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetPrivacyPrecompileAddress; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetPrivateTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetTransactionCount; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetTransactionReceipt; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; -import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; -import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; -import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.Address; -import org.hyperledger.besu.ethereum.core.PrivacyParameters; -import org.hyperledger.besu.ethereum.core.Synchronizer; -import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; -import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; -import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; -import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; -import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; -import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; -import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler; -import org.hyperledger.besu.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory; -import org.hyperledger.besu.ethereum.privacy.markertransaction.PrivateMarkerTransactionFactory; -import org.hyperledger.besu.ethereum.privacy.markertransaction.RandomSigningPrivateMarkerTransactionFactory; -import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; -import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.metrics.ObservableMetricsSystem; -import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; - -import java.math.BigInteger; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -public class JsonRpcMethodsFactory { - - private final BlockResultFactory blockResult = new BlockResultFactory(); - private final JsonRpcParameter parameter = new JsonRpcParameter(); - - public Map methods( - final String clientVersion, - final BigInteger networkId, - final GenesisConfigOptions genesisConfigOptions, - final P2PNetwork peerNetworkingService, - final Blockchain blockchain, - final WorldStateArchive worldStateArchive, - final Synchronizer synchronizer, - final TransactionPool transactionPool, - final ProtocolSchedule protocolSchedule, - final MiningCoordinator miningCoordinator, - final ObservableMetricsSystem metricsSystem, - final Set supportedCapabilities, - final Collection rpcApis, - final FilterManager filterManager, - final Optional accountsWhitelistController, - final Optional nodeWhitelistController, - final PrivacyParameters privacyParameters, - final JsonRpcConfiguration jsonRpcConfiguration, - final WebSocketConfiguration webSocketConfiguration, - final MetricsConfiguration metricsConfiguration) { - final BlockchainQueries blockchainQueries = - new BlockchainQueries(blockchain, worldStateArchive); - return methods( - clientVersion, - networkId, - genesisConfigOptions, - peerNetworkingService, - blockchainQueries, - synchronizer, - protocolSchedule, - filterManager, - transactionPool, - miningCoordinator, - metricsSystem, - supportedCapabilities, - accountsWhitelistController, - nodeWhitelistController, - rpcApis, - privacyParameters, - jsonRpcConfiguration, - webSocketConfiguration, - metricsConfiguration); - } - - public Map methods( - final String clientVersion, - final BigInteger networkId, - final GenesisConfigOptions genesisConfigOptions, - final P2PNetwork p2pNetwork, - final BlockchainQueries blockchainQueries, - final Synchronizer synchronizer, - final ProtocolSchedule protocolSchedule, - final FilterManager filterManager, - final TransactionPool transactionPool, - final MiningCoordinator miningCoordinator, - final ObservableMetricsSystem metricsSystem, - final Set supportedCapabilities, - final Optional accountsWhitelistController, - final Optional nodeWhitelistController, - final Collection rpcApis, - final PrivacyParameters privacyParameters, - final JsonRpcConfiguration jsonRpcConfiguration, - final WebSocketConfiguration webSocketConfiguration, - final MetricsConfiguration metricsConfiguration) { - final Map enabledMethods = new HashMap<>(); - if (!rpcApis.isEmpty()) { - addMethods(enabledMethods, new RpcModules(rpcApis)); - } - if (rpcApis.contains(RpcApis.ETH)) { - addMethods( - enabledMethods, - new EthAccounts(), - new EthBlockNumber(blockchainQueries), - new EthGetBalance(blockchainQueries, parameter), - new EthGetBlockByHash(blockchainQueries, blockResult, parameter), - new EthGetBlockByNumber(blockchainQueries, blockResult, parameter), - new EthGetBlockTransactionCountByNumber(blockchainQueries, parameter), - new EthGetBlockTransactionCountByHash(blockchainQueries, parameter), - new EthCall( - blockchainQueries, - new TransactionSimulator( - blockchainQueries.getBlockchain(), - blockchainQueries.getWorldStateArchive(), - protocolSchedule), - parameter), - new EthGetCode(blockchainQueries, parameter), - new EthGetLogs(blockchainQueries, parameter), - new EthGetProof(blockchainQueries, parameter), - new EthGetUncleCountByBlockHash(blockchainQueries, parameter), - new EthGetUncleCountByBlockNumber(blockchainQueries, parameter), - new EthGetUncleByBlockNumberAndIndex(blockchainQueries, parameter), - new EthGetUncleByBlockHashAndIndex(blockchainQueries, parameter), - new EthNewBlockFilter(filterManager), - new EthNewPendingTransactionFilter(filterManager), - new EthNewFilter(filterManager, parameter), - new EthGetTransactionByHash( - blockchainQueries, transactionPool.getPendingTransactions(), parameter), - new EthGetTransactionByBlockHashAndIndex(blockchainQueries, parameter), - new EthGetTransactionByBlockNumberAndIndex(blockchainQueries, parameter), - new EthGetTransactionCount( - blockchainQueries, transactionPool.getPendingTransactions(), parameter), - new EthGetTransactionReceipt(blockchainQueries, parameter), - new EthUninstallFilter(filterManager, parameter), - new EthGetFilterChanges(filterManager, parameter), - new EthGetFilterLogs(filterManager, parameter), - new EthSyncing(synchronizer), - new EthGetStorageAt(blockchainQueries, parameter), - new EthSendRawTransaction(transactionPool, parameter), - new EthSendTransaction(), - new EthEstimateGas( - blockchainQueries, - new TransactionSimulator( - blockchainQueries.getBlockchain(), - blockchainQueries.getWorldStateArchive(), - protocolSchedule), - parameter), - new EthMining(miningCoordinator), - new EthCoinbase(miningCoordinator), - new EthProtocolVersion(supportedCapabilities), - new EthGasPrice(miningCoordinator), - new EthGetWork(miningCoordinator), - new EthHashrate(miningCoordinator), - new EthChainId(protocolSchedule.getChainId())); - } - if (rpcApis.contains(RpcApis.DEBUG)) { - final BlockReplay blockReplay = - new BlockReplay( - protocolSchedule, - blockchainQueries.getBlockchain(), - blockchainQueries.getWorldStateArchive()); - addMethods( - enabledMethods, - new DebugTraceTransaction( - blockchainQueries, new TransactionTracer(blockReplay), parameter), - new DebugAccountRange(parameter, blockchainQueries), - new DebugStorageRangeAt(parameter, blockchainQueries, blockReplay), - new DebugMetrics(metricsSystem), - new DebugTraceBlock( - parameter, - new BlockTracer(blockReplay), - ScheduleBasedBlockHeaderFunctions.create(protocolSchedule), - blockchainQueries), - new DebugTraceBlockByNumber(parameter, new BlockTracer(blockReplay), blockchainQueries), - new DebugTraceBlockByHash(parameter, new BlockTracer(blockReplay))); - } - if (rpcApis.contains(RpcApis.NET)) { - addMethods( - enabledMethods, - new NetVersion(protocolSchedule.getChainId()), - new NetListening(p2pNetwork), - new NetPeerCount(p2pNetwork), - new NetEnode(p2pNetwork), - new NetServices( - jsonRpcConfiguration, webSocketConfiguration, p2pNetwork, metricsConfiguration)); - } - if (rpcApis.contains(RpcApis.WEB3)) { - addMethods(enabledMethods, new Web3ClientVersion(clientVersion), new Web3Sha3()); - } - if (rpcApis.contains(RpcApis.MINER)) { - final MinerSetCoinbase minerSetCoinbase = new MinerSetCoinbase(miningCoordinator, parameter); - addMethods( - enabledMethods, - new MinerStart(miningCoordinator), - new MinerStop(miningCoordinator), - minerSetCoinbase, - new MinerSetEtherbase(minerSetCoinbase)); - } - if (rpcApis.contains(RpcApis.TX_POOL)) { - addMethods( - enabledMethods, - new TxPoolBesuTransactions(transactionPool.getPendingTransactions()), - new TxPoolBesuStatistics(transactionPool.getPendingTransactions())); - } - if (rpcApis.contains(RpcApis.PERM)) { - addMethods( - enabledMethods, - new PermAddNodesToWhitelist(nodeWhitelistController, parameter), - new PermRemoveNodesFromWhitelist(nodeWhitelistController, parameter), - new PermGetNodesWhitelist(nodeWhitelistController), - new PermGetAccountsWhitelist(accountsWhitelistController), - new PermAddAccountsToWhitelist(accountsWhitelistController, parameter), - new PermRemoveAccountsFromWhitelist(accountsWhitelistController, parameter), - new PermReloadPermissionsFromFile(accountsWhitelistController, nodeWhitelistController)); - } - if (rpcApis.contains(RpcApis.ADMIN)) { - addMethods( - enabledMethods, - new AdminAddPeer(p2pNetwork, parameter), - new AdminRemovePeer(p2pNetwork, parameter), - new AdminNodeInfo( - clientVersion, networkId, genesisConfigOptions, p2pNetwork, blockchainQueries), - new AdminPeers(p2pNetwork), - new AdminChangeLogLevel(parameter)); - } - - // Disable TRACE functionality while under development - // if (rpcApis.contains(RpcApis.TRACE)) { - // addMethods( - // enabledMethods, - // new TraceReplayBlockTransactions( - // parameter, - // new BlockTracer( - // new BlockReplay( - // protocolSchedule, - // blockchainQueries.getBlockchain(), - // blockchainQueries.getWorldStateArchive())), - // blockchainQueries, - // protocolSchedule)); - // } - - final boolean eea = rpcApis.contains(RpcApis.EEA); - final boolean priv = rpcApis.contains(RpcApis.PRIV); - if (eea || priv) { - final PrivateMarkerTransactionFactory markerTransactionFactory = - createPrivateMarkerTransactionFactory( - privacyParameters, blockchainQueries, transactionPool.getPendingTransactions()); - - final PrivateTransactionHandler privateTransactionHandler = - new PrivateTransactionHandler( - privacyParameters, protocolSchedule.getChainId(), markerTransactionFactory); - final Enclave enclave = new Enclave(privacyParameters.getEnclaveUri()); - if (eea) { - addMethods( - enabledMethods, - new EeaSendRawTransaction(privateTransactionHandler, transactionPool, parameter), - new EeaGetTransactionCount( - parameter, new EeaPrivateNonceProvider(enclave, privateTransactionHandler))); - } - if (priv) { - addMethods( - enabledMethods, - new PrivGetTransactionReceipt(blockchainQueries, enclave, parameter, privacyParameters), - new PrivCreatePrivacyGroup( - new Enclave(privacyParameters.getEnclaveUri()), privacyParameters, parameter), - new PrivDeletePrivacyGroup( - new Enclave(privacyParameters.getEnclaveUri()), privacyParameters, parameter), - new PrivFindPrivacyGroup(new Enclave(privacyParameters.getEnclaveUri()), parameter), - new PrivGetPrivacyPrecompileAddress(privacyParameters), - new PrivGetTransactionCount(parameter, privateTransactionHandler), - new PrivGetPrivateTransaction(blockchainQueries, enclave, parameter, privacyParameters), - new PrivDistributeRawTransaction( - privateTransactionHandler, transactionPool, parameter)); - } - } - - return enabledMethods; - } - - public static void addMethods( - final Map methods, final JsonRpcMethod... rpcMethods) { - for (final JsonRpcMethod rpcMethod : rpcMethods) { - methods.put(rpcMethod.getName(), rpcMethod); - } - } - - private PrivateMarkerTransactionFactory createPrivateMarkerTransactionFactory( - final PrivacyParameters privacyParameters, - final BlockchainQueries blockchainQueries, - final PendingTransactions pendingTransactions) { - - final Address privateContractAddress = - Address.privacyPrecompiled(privacyParameters.getPrivacyAddress()); - - if (privacyParameters.getSigningKeyPair().isPresent()) { - return new FixedKeySigningPrivateMarkerTransactionFactory( - privateContractAddress, - new LatestNonceProvider(blockchainQueries, pendingTransactions), - privacyParameters.getSigningKeyPair().get()); - } - return new RandomSigningPrivateMarkerTransactionFactory(privateContractAddress); - } -} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProvider.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProvider.java index 005c1a842fd..90020802b67 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProvider.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProvider.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; import org.hyperledger.besu.ethereum.util.NonceProvider; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index 958bc2bbfdf..a09e056b932 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -43,8 +43,8 @@ public enum RpcMethod { PRIV_DELETE_PRIVACY_GROUP("priv_deletePrivacyGroup"), PRIV_FIND_PRIVACY_GROUP("priv_findPrivacyGroup"), PRIV_DISTRIBUTE_RAW_TRANSACTION("priv_distributeRawTransaction"), + PRIV_GET_EEA_TRANSACTION_COUNT("priv_getEeaTransactionCount"), EEA_SEND_RAW_TRANSACTION("eea_sendRawTransaction"), - EEA_GET_TRANSACTION_COUNT("eea_getTransactionCount"), ETH_ACCOUNTS("eth_accounts"), ETH_BLOCK_NUMBER("eth_blockNumber"), ETH_CALL("eth_call"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManager.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManager.java index 18c0e1cc60d..f51ac4b539c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManager.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManager.java @@ -16,13 +16,13 @@ import static com.google.common.base.Preconditions.checkNotNull; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.LogsQuery; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; @@ -163,7 +163,7 @@ void recordPendingTransactionEvent(final Transaction transaction) { pendingTransactionFilters.forEach( (filter) -> { synchronized (filter) { - filter.addTransactionHash(transaction.hash()); + filter.addTransactionHash(transaction.getHash()); } }); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogFilter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogFilter.java index 026cbb7d001..54b5c40daee 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogFilter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogFilter.java @@ -14,9 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.LogsQuery; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterMethod.java index 117778dbd4a..4dd76836aae 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractBlockParameterMethod.java @@ -17,9 +17,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import java.util.OptionalLong; import java.util.function.Supplier; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfo.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfo.java index 8cd2ca58598..1a7508ed6af 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfo.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfo.java @@ -17,11 +17,11 @@ import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.ChainHead; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountRange.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountRange.java index d2e997a3257..ac0dc95ab61 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountRange.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountRange.java @@ -14,14 +14,14 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugAccountRangeAtResult; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAt.java index 4004e7b85f5..662be769387 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAt.java @@ -14,17 +14,17 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugStorageRangeAtResult; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.AccountStorageEntry; import org.hyperledger.besu.ethereum.core.Address; @@ -105,7 +105,7 @@ public JsonRpcResponse response(final JsonRpcRequest request) { .get() .afterTransactionInBlock( blockHash, - transactionWithMetadata.getTransaction().hash(), + transactionWithMetadata.getTransaction().getHash(), (transaction, blockHeader, blockchain, worldState, transactionProcessor) -> extractStorageAt(request, accountAddress, startKey, limit, worldState)) .orElseGet(() -> emptyResponse(request)))) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlock.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlock.java index 84a1fd8f102..e2c88cbfec2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlock.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlock.java @@ -20,12 +20,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.debug.TraceOptions; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumber.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumber.java index 6fcc038b639..62999daee59 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumber.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumber.java @@ -21,8 +21,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.debug.TraceOptions; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransaction.java index bad26ee239e..236572bfb36 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransaction.java @@ -14,16 +14,16 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.debug.TraceOptions; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumber.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumber.java index d850e49e3a8..d5edc7a028f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumber.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumber.java @@ -16,10 +16,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import java.util.function.Supplier; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java index 0c3d3703955..babc51a02ff 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java @@ -21,10 +21,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.transaction.CallParameter; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java index fc4d625e143..69d80b32c40 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java @@ -18,12 +18,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.transaction.CallParameter; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBalance.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBalance.java index b48a5073459..6123c92fab7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBalance.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBalance.java @@ -18,8 +18,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import java.util.function.Supplier; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHash.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHash.java index fb78c17d177..2f5aa7f516f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHash.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHash.java @@ -17,11 +17,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Hash; public class EthGetBlockByHash implements JsonRpcMethod { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByNumber.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByNumber.java index 2eea4bceb85..7315ef4e9f9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByNumber.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByNumber.java @@ -18,9 +18,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import java.util.function.Supplier; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockTransactionCountByHash.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockTransactionCountByHash.java index 58168db2410..ed36f5b5ca0 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockTransactionCountByHash.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockTransactionCountByHash.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Hash; public class EthGetBlockTransactionCountByHash implements JsonRpcMethod { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockTransactionCountByNumber.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockTransactionCountByNumber.java index dcd9034d3f2..ef8d3cbb9fa 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockTransactionCountByNumber.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockTransactionCountByNumber.java @@ -18,8 +18,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; public class EthGetBlockTransactionCountByNumber extends AbstractBlockParameterMethod { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java index 2ca4b7ecfd8..c786b7b65c7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java @@ -18,7 +18,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.util.bytes.BytesValue; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java index 282d106f238..620335f0e72 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; @@ -25,6 +24,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.List; import java.util.stream.Collectors; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java index 96e2ec79f67..f251e7f9630 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; @@ -24,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.List; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogs.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogs.java index 4a1fba7f84f..ec68ced39ed 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogs.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogs.java @@ -14,17 +14,17 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.ethereum.api.LogsQuery; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; public class EthGetLogs implements JsonRpcMethod { @@ -46,10 +46,7 @@ public JsonRpcResponse response(final JsonRpcRequest request) { final FilterParameter filter = parameters.required(request.getParams(), 0, FilterParameter.class); final LogsQuery query = - new LogsQuery.Builder() - .addresses(filter.getAddresses()) - .topics(filter.getTopics().getTopics()) - .build(); + new LogsQuery.Builder().addresses(filter.getAddresses()).topics(filter.getTopics()).build(); if (isValid(filter)) { return new JsonRpcErrorResponse(request.getId(), JsonRpcError.INVALID_PARAMS); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProof.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProof.java index af8785f895c..b3864928b2e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProof.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProof.java @@ -18,12 +18,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.proof.GetProofResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.proof.WorldStateProof; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetStorageAt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetStorageAt.java index 91a94bf0ea0..a13e5954cc0 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetStorageAt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetStorageAt.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UInt256Parameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.util.uint.UInt256; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndex.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndex.java index ffaf5fb0f02..7225931f5b4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndex.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndex.java @@ -14,16 +14,16 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionCompleteResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; import java.util.Optional; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockNumberAndIndex.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockNumberAndIndex.java index ee37a4ff641..bc4c7de2087 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockNumberAndIndex.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockNumberAndIndex.java @@ -14,14 +14,14 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionCompleteResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import java.util.Optional; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHash.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHash.java index 496c74061d6..d3006f72342 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHash.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHash.java @@ -17,13 +17,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionCompleteResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPendingResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java index aecc6c3ee74..1e2225f65fe 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java @@ -18,8 +18,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java index 6326128597d..e265374c3ba 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java @@ -17,13 +17,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptRootResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptStatusResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.mainnet.TransactionReceiptType; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndex.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndex.java index 9884950f394..476209ead3c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndex.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndex.java @@ -18,11 +18,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.UncleBlockResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Hash; public class EthGetUncleByBlockHashAndIndex implements JsonRpcMethod { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndex.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndex.java index 777df066edd..3f8af573448 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndex.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndex.java @@ -19,9 +19,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.UncleBlockResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; public class EthGetUncleByBlockNumberAndIndex extends AbstractBlockParameterMethod { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleCountByBlockHash.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleCountByBlockHash.java index c75428c487d..325397771ca 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleCountByBlockHash.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleCountByBlockHash.java @@ -17,10 +17,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Hash; public class EthGetUncleCountByBlockHash implements JsonRpcMethod { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleCountByBlockNumber.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleCountByBlockNumber.java index 216995841f9..f69afe4a8a1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleCountByBlockNumber.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleCountByBlockNumber.java @@ -18,8 +18,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; public class EthGetUncleCountByBlockNumber extends AbstractBlockParameterMethod { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMining.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMining.java index 53629f3c92a..d182f456a19 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMining.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMining.java @@ -36,6 +36,6 @@ public String getName() { @Override public JsonRpcResponse response(final JsonRpcRequest req) { - return new JsonRpcSuccessResponse(req.getId(), miningCoordinator.isRunning()); + return new JsonRpcSuccessResponse(req.getId(), miningCoordinator.isMining()); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilter.java index 0565376396f..91682b0f027 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilter.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import org.hyperledger.besu.ethereum.api.LogsQuery; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; @@ -22,6 +21,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; public class EthNewFilter implements JsonRpcMethod { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransaction.java index 20f3032224b..d3d15a19bda 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransaction.java @@ -82,7 +82,7 @@ public JsonRpcResponse response(final JsonRpcRequest request) { final ValidationResult validationResult = transactionPool.get().addLocalTransaction(transaction); return validationResult.either( - () -> new JsonRpcSuccessResponse(request.getId(), transaction.hash().toString()), + () -> new JsonRpcSuccessResponse(request.getId(), transaction.getHash().toString()), errorReason -> sendEmptyHashOnInvalidBlock ? new JsonRpcSuccessResponse(request.getId(), Hash.EMPTY.toString()) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index a12da42d0cd..f487a4a9c37 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -23,10 +23,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.FlatTraceGenerator; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.TraceFormatter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.TraceWriter; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.debug.TraceOptions; @@ -123,7 +123,7 @@ private JsonNode formatTraces( .ifPresent( transactionTrace -> { resultNode.put( - "transactionHash", transactionTrace.getTransaction().hash().getHexString()); + "transactionHash", transactionTrace.getTransaction().getHash().getHexString()); resultNode.put("output", transactionTrace.getResult().getOutput().toString()); }); resultNode.put("stateDiff", (String) null); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStart.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStart.java index 61477804390..e89dc410f20 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStart.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStart.java @@ -39,12 +39,13 @@ public String getName() { @Override public JsonRpcResponse response(final JsonRpcRequest req) { + final boolean enabled; try { - miningCoordinator.enable(); + enabled = miningCoordinator.enable(); } catch (final CoinbaseNotSetException e) { return new JsonRpcErrorResponse(req.getId(), JsonRpcError.COINBASE_NOT_SET); } - return new JsonRpcSuccessResponse(req.getId(), true); + return new JsonRpcSuccessResponse(req.getId(), enabled); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStop.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStop.java index ea416bcdea4..88fe963d42b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStop.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStop.java @@ -36,10 +36,7 @@ public String getName() { @Override public JsonRpcResponse response(final JsonRpcRequest req) { - if (miningCoordinator != null) { - miningCoordinator.disable(); - } - - return new JsonRpcSuccessResponse(req.getId(), true); + final boolean disabled = miningCoordinator.disable(); + return new JsonRpcSuccessResponse(req.getId(), disabled); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameter.java index 19f474bb636..2275ef53534 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameter.java @@ -14,12 +14,12 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; -import org.hyperledger.besu.ethereum.api.TopicsParameter; +import static java.util.Collections.emptyList; + import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogTopic; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import com.fasterxml.jackson.annotation.JsonCreator; @@ -33,7 +33,7 @@ public class FilterParameter { private final BlockParameter fromBlock; private final BlockParameter toBlock; private final List
addresses; - private final TopicsParameter topics; + private final List> topics; private final Hash blockhash; @JsonCreator @@ -41,26 +41,18 @@ public FilterParameter( @JsonProperty("fromBlock") final String fromBlock, @JsonProperty("toBlock") final String toBlock, @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) @JsonProperty("address") - final List address, + final List
address, @JsonDeserialize(using = TopicsDeserializer.class) @JsonProperty("topics") - final TopicsParameter topics, + final List> topics, @JsonProperty("blockhash") final String blockhash) { this.fromBlock = fromBlock != null ? new BlockParameter(fromBlock) : new BlockParameter("latest"); this.toBlock = toBlock != null ? new BlockParameter(toBlock) : new BlockParameter("latest"); - this.addresses = address != null ? renderAddress(address) : Collections.emptyList(); - this.topics = topics != null ? topics : new TopicsParameter(Collections.emptyList()); + this.addresses = address != null ? address : emptyList(); + this.topics = topics != null ? topics : emptyList(); this.blockhash = blockhash != null ? Hash.fromHexString(blockhash) : null; } - private List
renderAddress(final List inputAddresses) { - final List
addresses = new ArrayList<>(); - for (final String value : inputAddresses) { - addresses.add(Address.fromHexString(value)); - } - return addresses; - } - public BlockParameter getFromBlock() { return fromBlock; } @@ -73,7 +65,7 @@ public List
getAddresses() { return addresses; } - public TopicsParameter getTopics() { + public List> getTopics() { return topics; } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonRpcParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonRpcParameter.java index 46e7d9fe8ec..d84ed0b9208 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonRpcParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonRpcParameter.java @@ -16,8 +16,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import java.io.IOException; -import java.io.UncheckedIOException; import java.util.Optional; import com.fasterxml.jackson.core.JsonProcessingException; @@ -74,8 +72,6 @@ public Optional optional( param = mapper.readValue(json, paramClass); } catch (final JsonProcessingException e) { throw new InvalidJsonRpcParameters("Invalid json rpc parameter at index " + index, e); - } catch (final IOException e) { - throw new UncheckedIOException(e); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/TopicsDeserializer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/TopicsDeserializer.java index 6d13777ac7b..11ab23f7244 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/TopicsDeserializer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/TopicsDeserializer.java @@ -14,19 +14,20 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; -import org.hyperledger.besu.ethereum.api.TopicsParameter; +import static java.util.Collections.singletonList; + +import org.hyperledger.besu.ethereum.core.LogTopic; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.google.common.collect.Lists; -public class TopicsDeserializer extends StdDeserializer { +public class TopicsDeserializer extends StdDeserializer>> { public TopicsDeserializer() { this(null); } @@ -36,23 +37,27 @@ public TopicsDeserializer(final Class vc) { } @Override - public TopicsParameter deserialize( + public List> deserialize( final JsonParser jsonparser, final DeserializationContext context) throws IOException { - List topicsList = new ArrayList<>(); - - try { - // parse as list of lists - return jsonparser.readValueAs(TopicsParameter.class); - } catch (MismatchedInputException mie) { - // single list case - String topics = jsonparser.getText(); - jsonparser.nextToken(); // consume end of array character - if (topics == null) { - return new TopicsParameter(Collections.singletonList(topicsList)); - } else { - // make it list of list - return new TopicsParameter(Collections.singletonList(Collections.singletonList(topics))); + final JsonNode topicsNode = jsonparser.getCodec().readTree(jsonparser); + final List> topics = Lists.newArrayList(); + + if (!topicsNode.isArray()) { + topics.add(singletonList(LogTopic.fromHexString(topicsNode.textValue()))); + } else { + for (JsonNode child : topicsNode) { + if (child.isArray()) { + final List childItems = Lists.newArrayList(); + for (JsonNode subChild : child) { + childItems.add(LogTopic.fromHexString(subChild.textValue())); + } + topics.add(childItems); + } else { + topics.add(singletonList(LogTopic.fromHexString(child.textValue()))); + } } } + + return topics; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java index b243a717202..2cf3ed07d02 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java @@ -83,7 +83,7 @@ public JsonRpcResponse response(final JsonRpcRequest request) { .either( () -> new JsonRpcSuccessResponse( - request.getId(), privacyMarkerTransaction.hash().toString()), + request.getId(), privacyMarkerTransaction.getHash().toString()), errorReason -> new JsonRpcErrorResponse( request.getId(), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaGetTransactionCount.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java similarity index 89% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaGetTransactionCount.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java index c714dc387d8..b29535edb95 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaGetTransactionCount.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java @@ -12,7 +12,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea; +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv; import static org.apache.logging.log4j.LogManager.getLogger; @@ -29,22 +29,22 @@ import org.apache.logging.log4j.Logger; -public class EeaGetTransactionCount implements JsonRpcMethod { +public class PrivGetEeaTransactionCount implements JsonRpcMethod { private static final Logger LOG = getLogger(); private final JsonRpcParameter parameters; - private final EeaPrivateNonceProvider nonceProvider; + private final PrivateEeaNonceProvider nonceProvider; - public EeaGetTransactionCount( - final JsonRpcParameter parameters, final EeaPrivateNonceProvider nonceProvider) { + public PrivGetEeaTransactionCount( + final JsonRpcParameter parameters, final PrivateEeaNonceProvider nonceProvider) { this.parameters = parameters; this.nonceProvider = nonceProvider; } @Override public String getName() { - return RpcMethod.EEA_GET_TRANSACTION_COUNT.getMethodName(); + return RpcMethod.PRIV_GET_EEA_TRANSACTION_COUNT.getMethodName(); } @Override diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransaction.java index c0e04419e55..2c245bda865 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransaction.java @@ -19,16 +19,16 @@ import org.hyperledger.besu.enclave.Enclave; import org.hyperledger.besu.enclave.types.ReceiveRequest; import org.hyperledger.besu.enclave.types.ReceiveResponse; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionGroupResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionLegacyResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java index b6fd802979c..d6286f5c809 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java @@ -25,11 +25,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionReceiptResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.TransactionLocation; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockBody; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaPrivateNonceProvider.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivateEeaNonceProvider.java similarity index 96% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaPrivateNonceProvider.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivateEeaNonceProvider.java index d05c9e4d6aa..cc458bb6922 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaPrivateNonceProvider.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivateEeaNonceProvider.java @@ -12,7 +12,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea; +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv; import org.hyperledger.besu.enclave.Enclave; import org.hyperledger.besu.enclave.types.FindPrivacyGroupRequest; @@ -27,12 +27,12 @@ import com.google.common.collect.Lists; import org.bouncycastle.util.Arrays; -public class EeaPrivateNonceProvider { +public class PrivateEeaNonceProvider { private final Enclave enclave; private final PrivateTransactionHandler privateTransactionHandler; - public EeaPrivateNonceProvider( + public PrivateEeaNonceProvider( final Enclave enclave, final PrivateTransactionHandler privateTransactionHandler) { this.enclave = enclave; this.privateTransactionHandler = privateTransactionHandler; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java index 7298620dd45..b207cdde750 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java @@ -80,7 +80,7 @@ public Optional beforeTransactionInBlock( (body, header, blockchain, mutableWorldState, transactionProcessor) -> { final BlockHashLookup blockHashLookup = new BlockHashLookup(header, blockchain); for (final Transaction transaction : body.getTransactions()) { - if (transaction.hash().equals(transactionHash)) { + if (transaction.getHash().equals(transactionHash)) { return Optional.of( action.performAction( transaction, header, blockchain, mutableWorldState, transactionProcessor)); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java index 0956644e2ba..d5dd00b9586 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; import java.util.List; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java index e2fef1aa6f8..e252211bd55 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.ArrayList; import java.util.List; @@ -53,7 +53,7 @@ public LogResult(final LogWithMetadata logWithMetadata) { this.blockHash = logWithMetadata.getBlockHash().toString(); this.transactionHash = logWithMetadata.getTransactionHash().toString(); this.transactionIndex = Quantity.create(logWithMetadata.getTransactionIndex()); - this.address = logWithMetadata.getAddress().toString(); + this.address = logWithMetadata.getLogger().toString(); this.data = logWithMetadata.getData().toString(); this.topics = new ArrayList<>(logWithMetadata.getTopics().size()); this.removed = logWithMetadata.isRemoved(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogsResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogsResult.java index b3592635ad2..c27722627aa 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogsResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogsResult.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java index 195f00186ef..7285d611983 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.util.bytes.BytesValue; @@ -61,7 +61,7 @@ public TransactionCompleteResult(final TransactionWithMetadata tx) { this.from = transaction.getSender().toString(); this.gas = Quantity.create(transaction.getGasLimit()); this.gasPrice = Quantity.create(transaction.getGasPrice()); - this.hash = transaction.hash().toString(); + this.hash = transaction.getHash().toString(); this.input = transaction.getPayload().toString(); this.nonce = Quantity.create(transaction.getNonce()); this.to = transaction.getTo().map(BytesValue::toString).orElse(null); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java index 005bf4a9800..fc2a8da9dce 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java @@ -54,7 +54,7 @@ public TransactionPendingResult(final Transaction transaction) { this.from = transaction.getSender().toString(); this.gas = Quantity.create(transaction.getGasLimit()); this.gasPrice = Quantity.create(transaction.getGasPrice()); - this.hash = transaction.hash().toString(); + this.hash = transaction.getHash().toString(); this.input = transaction.getPayload().toString(); this.nonce = Quantity.create(transaction.getNonce()); this.to = transaction.getTo().map(BytesValue::toString).orElse(null); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java index 50ec1c017be..120a4626c53 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.TransactionReceiptWithMetadata; +import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.Log; @@ -76,12 +76,12 @@ public TransactionReceiptResult(final TransactionReceiptWithMetadata receiptWith logReceipts( receipt.getLogs(), receiptWithMetadata.getBlockNumber(), - receiptWithMetadata.getTransaction().hash(), + receiptWithMetadata.getTransaction().getHash(), receiptWithMetadata.getBlockHash(), receiptWithMetadata.getTransactionIndex()); this.logsBloom = receipt.getBloomFilter().toString(); this.to = receiptWithMetadata.getTransaction().getTo().map(BytesValue::toString).orElse(null); - this.transactionHash = receiptWithMetadata.getTransaction().hash().toString(); + this.transactionHash = receiptWithMetadata.getTransaction().getHash().toString(); this.transactionIndex = Quantity.create(receiptWithMetadata.getTransactionIndex()); this.revertReason = receipt.getRevertReason().map(BytesValue::toString).orElse(null); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptRootResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptRootResult.java index 88254eecd92..26ac03b604a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptRootResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptRootResult.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.TransactionReceiptWithMetadata; +import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import com.fasterxml.jackson.annotation.JsonGetter; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptStatusResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptStatusResult.java index 78964ce0dbc..77fc416e9a4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptStatusResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptStatusResult.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.TransactionReceiptWithMetadata; +import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import com.fasterxml.jackson.annotation.JsonGetter; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/AdminJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/AdminJsonRpcMethods.java new file mode 100644 index 00000000000..1c5b588db45 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/AdminJsonRpcMethods.java @@ -0,0 +1,70 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminAddPeer; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminChangeLogLevel; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminNodeInfo; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminPeers; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AdminRemovePeer; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; + +import java.math.BigInteger; +import java.util.Map; + +public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final JsonRpcParameter parameter = new JsonRpcParameter(); + private final String clientVersion; + private final BigInteger networkId; + private final GenesisConfigOptions genesisConfigOptions; + private final P2PNetwork p2pNetwork; + private final BlockchainQueries blockchainQueries; + + public AdminJsonRpcMethods( + final String clientVersion, + final BigInteger networkId, + final GenesisConfigOptions genesisConfigOptions, + final P2PNetwork p2pNetwork, + final BlockchainQueries blockchainQueries) { + this.clientVersion = clientVersion; + this.networkId = networkId; + this.genesisConfigOptions = genesisConfigOptions; + this.p2pNetwork = p2pNetwork; + this.blockchainQueries = blockchainQueries; + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.ADMIN; + } + + @Override + protected Map create() { + return mapOf( + new AdminAddPeer(p2pNetwork, parameter), + new AdminRemovePeer(p2pNetwork, parameter), + new AdminNodeInfo( + clientVersion, networkId, genesisConfigOptions, p2pNetwork, blockchainQueries), + new AdminPeers(p2pNetwork), + new AdminChangeLogLevel(parameter)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ApiGroupJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ApiGroupJsonRpcMethods.java new file mode 100644 index 00000000000..eb1d04e17c3 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ApiGroupJsonRpcMethods.java @@ -0,0 +1,41 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; + +public abstract class ApiGroupJsonRpcMethods implements JsonRpcMethods { + + @Override + public Map create(final Collection apis) { + return apis.contains(getApiGroup()) ? create() : Collections.emptyMap(); + } + + protected abstract RpcApi getApiGroup(); + + protected abstract Map create(); + + protected Map mapOf(final JsonRpcMethod... methods) { + return Arrays.stream(methods) + .collect(Collectors.toMap(JsonRpcMethod::getName, method -> method)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/DebugJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/DebugJsonRpcMethods.java new file mode 100644 index 00000000000..e9acf87a4e6 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/DebugJsonRpcMethods.java @@ -0,0 +1,80 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugAccountRange; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugMetrics; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugStorageRangeAt; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlock; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlockByHash; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlockByNumber; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceTransaction; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTracer; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; +import org.hyperledger.besu.metrics.ObservableMetricsSystem; + +import java.util.Map; + +public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final JsonRpcParameter parameter = new JsonRpcParameter(); + private final BlockchainQueries blockchainQueries; + private final ProtocolSchedule protocolSchedule; + private final ObservableMetricsSystem metricsSystem; + + public DebugJsonRpcMethods( + final BlockchainQueries blockchainQueries, + final ProtocolSchedule protocolSchedule, + final ObservableMetricsSystem metricsSystem) { + this.blockchainQueries = blockchainQueries; + this.protocolSchedule = protocolSchedule; + this.metricsSystem = metricsSystem; + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.DEBUG; + } + + @Override + protected Map create() { + final BlockReplay blockReplay = + new BlockReplay( + protocolSchedule, + blockchainQueries.getBlockchain(), + blockchainQueries.getWorldStateArchive()); + + return mapOf( + new DebugTraceTransaction(blockchainQueries, new TransactionTracer(blockReplay), parameter), + new DebugAccountRange(parameter, blockchainQueries), + new DebugStorageRangeAt(parameter, blockchainQueries, blockReplay), + new DebugMetrics(metricsSystem), + new DebugTraceBlock( + parameter, + new BlockTracer(blockReplay), + ScheduleBasedBlockHeaderFunctions.create(protocolSchedule), + blockchainQueries), + new DebugTraceBlockByNumber(parameter, new BlockTracer(blockReplay), blockchainQueries), + new DebugTraceBlockByHash(parameter, new BlockTracer(blockReplay))); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java new file mode 100644 index 00000000000..d8020069c29 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java @@ -0,0 +1,58 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.enclave.Enclave; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea.EeaSendRawTransaction; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetEeaTransactionCount; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivateEeaNonceProvider; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler; + +import java.util.Map; + +public class EeaJsonRpcMethods extends PrivacyApiGroupJsonRpcMethods { + + private final JsonRpcParameter parameter = new JsonRpcParameter(); + + public EeaJsonRpcMethods( + final BlockchainQueries blockchainQueries, + final ProtocolSchedule protocolSchedule, + final TransactionPool transactionPool, + final PrivacyParameters privacyParameters) { + super(blockchainQueries, protocolSchedule, transactionPool, privacyParameters); + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.EEA; + } + + @Override + protected Map create( + final PrivateTransactionHandler privateTransactionHandler, final Enclave enclave) { + return mapOf( + new EeaSendRawTransaction(privateTransactionHandler, getTransactionPool(), parameter), + new PrivGetEeaTransactionCount( + parameter, new PrivateEeaNonceProvider(enclave, privateTransactionHandler))); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java new file mode 100644 index 00000000000..86197aa9f8d --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java @@ -0,0 +1,163 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthAccounts; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthBlockNumber; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthCall; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthChainId; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthCoinbase; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthEstimateGas; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGasPrice; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBalance; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockByHash; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockByNumber; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockTransactionCountByHash; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockTransactionCountByNumber; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetCode; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetFilterChanges; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetFilterLogs; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetLogs; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetProof; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetStorageAt; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionByBlockHashAndIndex; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionByBlockNumberAndIndex; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionByHash; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionCount; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionReceipt; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetUncleByBlockHashAndIndex; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetUncleByBlockNumberAndIndex; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetUncleCountByBlockHash; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetUncleCountByBlockNumber; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetWork; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthHashrate; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthMining; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthNewBlockFilter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthNewFilter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthNewPendingTransactionFilter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthProtocolVersion; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSendRawTransaction; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSendTransaction; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSyncing; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthUninstallFilter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.core.Synchronizer; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; +import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; + +import java.util.Map; +import java.util.Set; + +public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final BlockResultFactory blockResult = new BlockResultFactory(); + private final JsonRpcParameter parameter = new JsonRpcParameter(); + + private final BlockchainQueries blockchainQueries; + private final Synchronizer synchronizer; + private final ProtocolSchedule protocolSchedule; + private final FilterManager filterManager; + private final TransactionPool transactionPool; + private final MiningCoordinator miningCoordinator; + private final Set supportedCapabilities; + + public EthJsonRpcMethods( + final BlockchainQueries blockchainQueries, + final Synchronizer synchronizer, + final ProtocolSchedule protocolSchedule, + final FilterManager filterManager, + final TransactionPool transactionPool, + final MiningCoordinator miningCoordinator, + final Set supportedCapabilities) { + this.blockchainQueries = blockchainQueries; + this.synchronizer = synchronizer; + this.protocolSchedule = protocolSchedule; + this.filterManager = filterManager; + this.transactionPool = transactionPool; + this.miningCoordinator = miningCoordinator; + this.supportedCapabilities = supportedCapabilities; + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.ETH; + } + + @Override + protected Map create() { + return mapOf( + new EthAccounts(), + new EthBlockNumber(blockchainQueries), + new EthGetBalance(blockchainQueries, parameter), + new EthGetBlockByHash(blockchainQueries, blockResult, parameter), + new EthGetBlockByNumber(blockchainQueries, blockResult, parameter), + new EthGetBlockTransactionCountByNumber(blockchainQueries, parameter), + new EthGetBlockTransactionCountByHash(blockchainQueries, parameter), + new EthCall( + blockchainQueries, + new TransactionSimulator( + blockchainQueries.getBlockchain(), + blockchainQueries.getWorldStateArchive(), + protocolSchedule), + parameter), + new EthGetCode(blockchainQueries, parameter), + new EthGetLogs(blockchainQueries, parameter), + new EthGetProof(blockchainQueries, parameter), + new EthGetUncleCountByBlockHash(blockchainQueries, parameter), + new EthGetUncleCountByBlockNumber(blockchainQueries, parameter), + new EthGetUncleByBlockNumberAndIndex(blockchainQueries, parameter), + new EthGetUncleByBlockHashAndIndex(blockchainQueries, parameter), + new EthNewBlockFilter(filterManager), + new EthNewPendingTransactionFilter(filterManager), + new EthNewFilter(filterManager, parameter), + new EthGetTransactionByHash( + blockchainQueries, transactionPool.getPendingTransactions(), parameter), + new EthGetTransactionByBlockHashAndIndex(blockchainQueries, parameter), + new EthGetTransactionByBlockNumberAndIndex(blockchainQueries, parameter), + new EthGetTransactionCount( + blockchainQueries, transactionPool.getPendingTransactions(), parameter), + new EthGetTransactionReceipt(blockchainQueries, parameter), + new EthUninstallFilter(filterManager, parameter), + new EthGetFilterChanges(filterManager, parameter), + new EthGetFilterLogs(filterManager, parameter), + new EthSyncing(synchronizer), + new EthGetStorageAt(blockchainQueries, parameter), + new EthSendRawTransaction(transactionPool, parameter), + new EthSendTransaction(), + new EthEstimateGas( + blockchainQueries, + new TransactionSimulator( + blockchainQueries.getBlockchain(), + blockchainQueries.getWorldStateArchive(), + protocolSchedule), + parameter), + new EthMining(miningCoordinator), + new EthCoinbase(miningCoordinator), + new EthProtocolVersion(supportedCapabilities), + new EthGasPrice(miningCoordinator), + new EthGetWork(miningCoordinator), + new EthHashrate(miningCoordinator), + new EthChainId(protocolSchedule.getChainId())); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/JsonRpcMethodFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethods.java similarity index 74% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/JsonRpcMethodFactory.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethods.java index a6ad31bdc18..0b4ae464772 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/JsonRpcMethodFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethods.java @@ -12,13 +12,14 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import java.util.Collection; import java.util.Map; -public interface JsonRpcMethodFactory { - Map createJsonRpcMethods(Collection enabledRpcApis); +public interface JsonRpcMethods { + Map create(Collection enabledRpcApis); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java new file mode 100644 index 00000000000..5991ecc510d --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java @@ -0,0 +1,157 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.RpcModules; +import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.core.Synchronizer; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; +import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; +import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; + +import java.math.BigInteger; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +public class JsonRpcMethodsFactory { + + public Map methods( + final String clientVersion, + final BigInteger networkId, + final GenesisConfigOptions genesisConfigOptions, + final P2PNetwork peerNetworkingService, + final Blockchain blockchain, + final WorldStateArchive worldStateArchive, + final Synchronizer synchronizer, + final TransactionPool transactionPool, + final ProtocolSchedule protocolSchedule, + final MiningCoordinator miningCoordinator, + final ObservableMetricsSystem metricsSystem, + final Set supportedCapabilities, + final Collection rpcApis, + final FilterManager filterManager, + final Optional accountsWhitelistController, + final Optional nodeWhitelistController, + final PrivacyParameters privacyParameters, + final JsonRpcConfiguration jsonRpcConfiguration, + final WebSocketConfiguration webSocketConfiguration, + final MetricsConfiguration metricsConfiguration) { + final BlockchainQueries blockchainQueries = + new BlockchainQueries(blockchain, worldStateArchive); + return methods( + clientVersion, + networkId, + genesisConfigOptions, + peerNetworkingService, + blockchainQueries, + synchronizer, + protocolSchedule, + filterManager, + transactionPool, + miningCoordinator, + metricsSystem, + supportedCapabilities, + accountsWhitelistController, + nodeWhitelistController, + rpcApis, + privacyParameters, + jsonRpcConfiguration, + webSocketConfiguration, + metricsConfiguration); + } + + public Map methods( + final String clientVersion, + final BigInteger networkId, + final GenesisConfigOptions genesisConfigOptions, + final P2PNetwork p2pNetwork, + final BlockchainQueries blockchainQueries, + final Synchronizer synchronizer, + final ProtocolSchedule protocolSchedule, + final FilterManager filterManager, + final TransactionPool transactionPool, + final MiningCoordinator miningCoordinator, + final ObservableMetricsSystem metricsSystem, + final Set supportedCapabilities, + final Optional accountsWhitelistController, + final Optional nodeWhitelistController, + final Collection rpcApis, + final PrivacyParameters privacyParameters, + final JsonRpcConfiguration jsonRpcConfiguration, + final WebSocketConfiguration webSocketConfiguration, + final MetricsConfiguration metricsConfiguration) { + final Map enabled = new HashMap<>(); + + if (!rpcApis.isEmpty()) { + final JsonRpcMethod modules = new RpcModules(rpcApis); + enabled.put(modules.getName(), modules); + + final List availableApiGroups = + List.of( + new AdminJsonRpcMethods( + clientVersion, networkId, genesisConfigOptions, p2pNetwork, blockchainQueries), + new DebugJsonRpcMethods(blockchainQueries, protocolSchedule, metricsSystem), + new EeaJsonRpcMethods( + blockchainQueries, protocolSchedule, transactionPool, privacyParameters), + new EthJsonRpcMethods( + blockchainQueries, + synchronizer, + protocolSchedule, + filterManager, + transactionPool, + miningCoordinator, + supportedCapabilities), + new NetJsonRpcMethods( + p2pNetwork, + protocolSchedule, + jsonRpcConfiguration, + webSocketConfiguration, + metricsConfiguration), + new MinerJsonRpcMethods(miningCoordinator), + new PermJsonRpcMethods(accountsWhitelistController, nodeWhitelistController), + new PrivJsonRpcMethods( + blockchainQueries, protocolSchedule, transactionPool, privacyParameters), + new Web3JsonRpcMethods(clientVersion), + // TRACE Methods (Disabled while under development) + // new TraceJsonRpcMethods(blockchainQueries,protocolSchedule) + new TxPoolJsonRpcMethods(transactionPool)); + + for (final JsonRpcMethods apiGroup : availableApiGroups) { + enabled.putAll(apiGroup.create(rpcApis)); + } + } + + return enabled; + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/MinerJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/MinerJsonRpcMethods.java new file mode 100644 index 00000000000..bed18cbaaea --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/MinerJsonRpcMethods.java @@ -0,0 +1,52 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetCoinbase; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetEtherbase; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerStart; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerStop; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; +import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; + +import java.util.Map; + +public class MinerJsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final JsonRpcParameter parameter = new JsonRpcParameter(); + private final MiningCoordinator miningCoordinator; + + public MinerJsonRpcMethods(final MiningCoordinator miningCoordinator) { + this.miningCoordinator = miningCoordinator; + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.MINER; + } + + @Override + protected Map create() { + final MinerSetCoinbase minerSetCoinbase = new MinerSetCoinbase(miningCoordinator, parameter); + return mapOf( + new MinerStart(miningCoordinator), + new MinerStop(miningCoordinator), + minerSetCoinbase, + new MinerSetEtherbase(minerSetCoinbase)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/NetJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/NetJsonRpcMethods.java new file mode 100644 index 00000000000..49a81953d64 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/NetJsonRpcMethods.java @@ -0,0 +1,69 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetEnode; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetListening; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetPeerCount; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetServices; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetVersion; +import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; +import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; + +import java.util.Map; + +public class NetJsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final P2PNetwork p2pNetwork; + private final ProtocolSchedule protocolSchedule; + private final JsonRpcConfiguration jsonRpcConfiguration; + private final WebSocketConfiguration webSocketConfiguration; + private final MetricsConfiguration metricsConfiguration; + + public NetJsonRpcMethods( + final P2PNetwork p2pNetwork, + final ProtocolSchedule protocolSchedule, + final JsonRpcConfiguration jsonRpcConfiguration, + final WebSocketConfiguration webSocketConfiguration, + final MetricsConfiguration metricsConfiguration) { + this.p2pNetwork = p2pNetwork; + this.protocolSchedule = protocolSchedule; + this.jsonRpcConfiguration = jsonRpcConfiguration; + this.webSocketConfiguration = webSocketConfiguration; + this.metricsConfiguration = metricsConfiguration; + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.NET; + } + + @Override + protected Map create() { + return mapOf( + new NetVersion(protocolSchedule.getChainId()), + new NetListening(p2pNetwork), + new NetPeerCount(p2pNetwork), + new NetEnode(p2pNetwork), + new NetServices( + jsonRpcConfiguration, webSocketConfiguration, p2pNetwork, metricsConfiguration)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PermJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PermJsonRpcMethods.java new file mode 100644 index 00000000000..6f667c2743e --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PermJsonRpcMethods.java @@ -0,0 +1,63 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermAddAccountsToWhitelist; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermAddNodesToWhitelist; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermGetAccountsWhitelist; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermGetNodesWhitelist; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermReloadPermissionsFromFile; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermRemoveAccountsFromWhitelist; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.permissioning.PermRemoveNodesFromWhitelist; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; +import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; +import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; + +import java.util.Map; +import java.util.Optional; + +public class PermJsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final JsonRpcParameter parameter = new JsonRpcParameter(); + private final Optional accountsWhitelistController; + private final Optional nodeWhitelistController; + + public PermJsonRpcMethods( + final Optional accountsWhitelistController, + final Optional nodeWhitelistController) { + this.accountsWhitelistController = accountsWhitelistController; + this.nodeWhitelistController = nodeWhitelistController; + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.PERM; + } + + @Override + protected Map create() { + return mapOf( + new PermAddNodesToWhitelist(nodeWhitelistController, parameter), + new PermRemoveNodesFromWhitelist(nodeWhitelistController, parameter), + new PermGetNodesWhitelist(nodeWhitelistController), + new PermGetAccountsWhitelist(accountsWhitelistController), + new PermAddAccountsToWhitelist(accountsWhitelistController, parameter), + new PermRemoveAccountsFromWhitelist(accountsWhitelistController, parameter), + new PermReloadPermissionsFromFile(accountsWhitelistController, nodeWhitelistController)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethods.java new file mode 100644 index 00000000000..6b79f8f59d5 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethods.java @@ -0,0 +1,73 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.enclave.Enclave; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivCreatePrivacyGroup; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivDeletePrivacyGroup; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivDistributeRawTransaction; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivFindPrivacyGroup; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetPrivacyPrecompileAddress; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetPrivateTransaction; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetTransactionCount; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetTransactionReceipt; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler; + +import java.util.Map; + +public class PrivJsonRpcMethods extends PrivacyApiGroupJsonRpcMethods { + + private final JsonRpcParameter parameter = new JsonRpcParameter(); + + public PrivJsonRpcMethods( + final BlockchainQueries blockchainQueries, + final ProtocolSchedule protocolSchedule, + final TransactionPool transactionPool, + final PrivacyParameters privacyParameters) { + super(blockchainQueries, protocolSchedule, transactionPool, privacyParameters); + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.PRIV; + } + + @Override + protected Map create( + final PrivateTransactionHandler privateTransactionHandler, final Enclave enclave) { + return mapOf( + new PrivGetTransactionReceipt( + getBlockchainQueries(), enclave, parameter, getPrivacyParameters()), + new PrivCreatePrivacyGroup( + new Enclave(getPrivacyParameters().getEnclaveUri()), getPrivacyParameters(), parameter), + new PrivDeletePrivacyGroup( + new Enclave(getPrivacyParameters().getEnclaveUri()), getPrivacyParameters(), parameter), + new PrivFindPrivacyGroup(new Enclave(getPrivacyParameters().getEnclaveUri()), parameter), + new PrivGetPrivacyPrecompileAddress(getPrivacyParameters()), + new PrivGetTransactionCount(parameter, privateTransactionHandler), + new PrivGetPrivateTransaction( + getBlockchainQueries(), enclave, parameter, getPrivacyParameters()), + new PrivDistributeRawTransaction( + privateTransactionHandler, getTransactionPool(), parameter)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethods.java new file mode 100644 index 00000000000..53881a8c015 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethods.java @@ -0,0 +1,101 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.enclave.Enclave; +import org.hyperledger.besu.ethereum.api.jsonrpc.LatestNonceProvider; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler; +import org.hyperledger.besu.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory; +import org.hyperledger.besu.ethereum.privacy.markertransaction.PrivateMarkerTransactionFactory; +import org.hyperledger.besu.ethereum.privacy.markertransaction.RandomSigningPrivateMarkerTransactionFactory; + +import java.util.Map; + +public abstract class PrivacyApiGroupJsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final BlockchainQueries blockchainQueries; + private final ProtocolSchedule protocolSchedule; + private final TransactionPool transactionPool; + private final PrivacyParameters privacyParameters; + + public PrivacyApiGroupJsonRpcMethods( + final BlockchainQueries blockchainQueries, + final ProtocolSchedule protocolSchedule, + final TransactionPool transactionPool, + final PrivacyParameters privacyParameters) { + this.blockchainQueries = blockchainQueries; + this.protocolSchedule = protocolSchedule; + this.transactionPool = transactionPool; + this.privacyParameters = privacyParameters; + } + + public BlockchainQueries getBlockchainQueries() { + return blockchainQueries; + } + + public ProtocolSchedule getProtocolSchedule() { + return protocolSchedule; + } + + public TransactionPool getTransactionPool() { + return transactionPool; + } + + public PrivacyParameters getPrivacyParameters() { + return privacyParameters; + } + + @Override + protected Map create() { + final PrivateMarkerTransactionFactory markerTransactionFactory = + createPrivateMarkerTransactionFactory( + privacyParameters, blockchainQueries, transactionPool.getPendingTransactions()); + + final PrivateTransactionHandler privateTransactionHandler = + new PrivateTransactionHandler( + privacyParameters, protocolSchedule.getChainId(), markerTransactionFactory); + + final Enclave enclave = new Enclave(privacyParameters.getEnclaveUri()); + + return create(privateTransactionHandler, enclave); + } + + protected abstract Map create( + final PrivateTransactionHandler privateTransactionHandler, final Enclave enclave); + + private PrivateMarkerTransactionFactory createPrivateMarkerTransactionFactory( + final PrivacyParameters privacyParameters, + final BlockchainQueries blockchainQueries, + final PendingTransactions pendingTransactions) { + + final Address privateContractAddress = + Address.privacyPrecompiled(privacyParameters.getPrivacyAddress()); + + if (privacyParameters.getSigningKeyPair().isPresent()) { + return new FixedKeySigningPrivateMarkerTransactionFactory( + privateContractAddress, + new LatestNonceProvider(blockchainQueries, pendingTransactions), + privacyParameters.getSigningKeyPair().get()); + } + return new RandomSigningPrivateMarkerTransactionFactory(privateContractAddress); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TraceJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TraceJsonRpcMethods.java new file mode 100644 index 00000000000..eb0c8b46900 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TraceJsonRpcMethods.java @@ -0,0 +1,60 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TraceReplayBlockTransactions; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; + +import java.util.Map; + +public class TraceJsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final JsonRpcParameter parameter = new JsonRpcParameter(); + private final BlockchainQueries blockchainQueries; + private final ProtocolSchedule protocolSchedule; + + public TraceJsonRpcMethods( + final BlockchainQueries blockchainQueries, final ProtocolSchedule protocolSchedule) { + this.blockchainQueries = blockchainQueries; + this.protocolSchedule = protocolSchedule; + } + + @Override + protected RpcApi getApiGroup() { + // Disable TRACE functionality while under development + // return RpcApis.TRACE; + return null; + } + + @Override + protected Map create() { + return mapOf( + new TraceReplayBlockTransactions( + parameter, + new BlockTracer( + new BlockReplay( + protocolSchedule, + blockchainQueries.getBlockchain(), + blockchainQueries.getWorldStateArchive())), + blockchainQueries, + protocolSchedule)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TxPoolJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TxPoolJsonRpcMethods.java new file mode 100644 index 00000000000..f1e3197d52f --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TxPoolJsonRpcMethods.java @@ -0,0 +1,45 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuStatistics; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuTransactions; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; + +import java.util.Map; + +public class TxPoolJsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final TransactionPool transactionPool; + + public TxPoolJsonRpcMethods(final TransactionPool transactionPool) { + this.transactionPool = transactionPool; + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.TX_POOL; + } + + @Override + protected Map create() { + return mapOf( + new TxPoolBesuTransactions(transactionPool.getPendingTransactions()), + new TxPoolBesuStatistics(transactionPool.getPendingTransactions())); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/Web3JsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/Web3JsonRpcMethods.java new file mode 100644 index 00000000000..ca9176aec21 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/Web3JsonRpcMethods.java @@ -0,0 +1,42 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.methods; + +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.Web3ClientVersion; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.Web3Sha3; + +import java.util.Map; + +public class Web3JsonRpcMethods extends ApiGroupJsonRpcMethods { + + private final String clientVersion; + + public Web3JsonRpcMethods(final String clientVersion) { + this.clientVersion = clientVersion; + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.WEB3; + } + + @Override + protected Map create() { + return mapOf(new Web3ClientVersion(clientVersion), new Web3Sha3()); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilder.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilder.java index 31d0144c929..0402c1f46fc 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilder.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilder.java @@ -39,7 +39,7 @@ public Subscription build( return new LogsSubscription( subscriptionId, connectionId, - Optional.ofNullable(request.getFilterParameter()) + Optional.ofNullable(request.getLogsQuery()) .orElseThrow(IllegalArgumentException::new)); } case SYNCING: diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionService.java index 3dc81e1696e..bfb53f0f9f9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionService.java @@ -14,11 +14,11 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.blockheaders; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.Blockchain; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscription.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscription.java index 81816a01725..d9e125f2f98 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscription.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscription.java @@ -14,25 +14,21 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.logs; -import org.hyperledger.besu.ethereum.api.LogsQuery; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.Subscription; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; public class LogsSubscription extends Subscription { - private final FilterParameter filterParameter; + private final LogsQuery logsQuery; public LogsSubscription( - final Long subscriptionId, final String connectionId, final FilterParameter filterParameter) { + final Long subscriptionId, final String connectionId, final LogsQuery logsQuery) { super(subscriptionId, connectionId, SubscriptionType.LOGS, Boolean.FALSE); - this.filterParameter = filterParameter; + this.logsQuery = logsQuery; } public LogsQuery getLogsQuery() { - return new LogsQuery.Builder() - .addresses(filterParameter.getAddresses()) - .topics(filterParameter.getTopics()) - .build(); + return logsQuery; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java index f858cafaaad..b4f49d323f7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java @@ -14,100 +14,40 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.logs; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogResult; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.Log; import java.util.List; -import java.util.Optional; public class LogsSubscriptionService implements BlockAddedObserver { private final SubscriptionManager subscriptionManager; - private final BlockchainQueries blockchainQueries; - public LogsSubscriptionService( - final SubscriptionManager subscriptionManager, final BlockchainQueries blockchainQueries) { + public LogsSubscriptionService(final SubscriptionManager subscriptionManager) { this.subscriptionManager = subscriptionManager; - this.blockchainQueries = blockchainQueries; } @Override - public void onBlockAdded(final BlockAddedEvent event, final Blockchain blockchain) { + public void onBlockAdded(final BlockAddedEvent event, final Blockchain __) { final List logsSubscriptions = subscriptionManager.subscriptionsOfType(SubscriptionType.LOGS, LogsSubscription.class); - if (logsSubscriptions.isEmpty()) { - return; - } - - event.getAddedTransactions().stream() - .map(tx -> blockchainQueries.transactionReceiptByTransactionHash(tx.hash())) - .filter(Optional::isPresent) - .map(Optional::get) - .forEachOrdered( - receiptWithMetadata -> { - final List logs = receiptWithMetadata.getReceipt().getLogs(); - sendLogsToMatchingSubscriptions(logs, logsSubscriptions, receiptWithMetadata, false); - }); - - event.getRemovedTransactions().stream() - .map(tx -> blockchainQueries.transactionReceiptByTransactionHash(tx.hash())) - .filter(Optional::isPresent) - .map(Optional::get) - .forEachOrdered( - receiptWithMetadata -> { - final List logs = receiptWithMetadata.getReceipt().getLogs(); - sendLogsToMatchingSubscriptions(logs, logsSubscriptions, receiptWithMetadata, true); - }); - } - - private void sendLogsToMatchingSubscriptions( - final List logs, - final List logsSubscriptions, - final TransactionReceiptWithMetadata receiptWithMetadata, - final boolean removed) { - for (int logIndex = 0; logIndex < logs.size(); logIndex++) { - for (final LogsSubscription subscription : logsSubscriptions) { - if (subscription.getLogsQuery().matches(logs.get(logIndex))) { - sendLogToSubscription(receiptWithMetadata, removed, logIndex, subscription); - } - } - } - } - - private void sendLogToSubscription( - final TransactionReceiptWithMetadata receiptWithMetadata, - final boolean removed, - final int logIndex, - final LogsSubscription subscription) { - final LogWithMetadata logWithMetaData = logWithMetadata(logIndex, receiptWithMetadata, removed); - subscriptionManager.sendMessage( - subscription.getSubscriptionId(), new LogResult(logWithMetaData)); - } - - // @formatter:off - private LogWithMetadata logWithMetadata( - final int logIndex, - final TransactionReceiptWithMetadata transactionReceiptWithMetadata, - final boolean removed) { - return new LogWithMetadata( - logIndex, - transactionReceiptWithMetadata.getBlockNumber(), - transactionReceiptWithMetadata.getBlockHash(), - transactionReceiptWithMetadata.getTransactionHash(), - transactionReceiptWithMetadata.getTransactionIndex(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(logIndex).getLogger(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(logIndex).getData(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(logIndex).getTopics(), - removed); + event + .getLogsWithMetadata() + .forEach( + logWithMetadata -> + logsSubscriptions.stream() + .filter( + logsSubscription -> + logsSubscription.getLogsQuery().matches(logWithMetadata)) + .forEach( + logsSubscription -> + subscriptionManager.sendMessage( + logsSubscription.getSubscriptionId(), + new LogResult(logWithMetadata)))); } - // @formatter:on } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java index e8a5e12166e..fec1e7974c3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java @@ -52,7 +52,7 @@ public PendingTransactionDetailResult(final Transaction tx) { this.from = tx.getSender().toString(); this.gas = Quantity.create(tx.getGasLimit()); this.gasPrice = Quantity.create(tx.getGasPrice()); - this.hash = tx.hash().toString(); + this.hash = tx.getHash().toString(); this.input = tx.getPayload().toString(); this.nonce = Quantity.create(tx.getNonce()); this.to = tx.getTo().map(BytesValue::toString).orElse(null); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionService.java index 3cf15f4cb5f..7b97b9b1a07 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionService.java @@ -35,7 +35,7 @@ public PendingTransactionDroppedSubscriptionService( @Override public void onTransactionDropped(final Transaction transaction) { - notifySubscribers(transaction.hash()); + notifySubscribers(transaction.getHash()); } private void notifySubscribers(final Hash pendingTransaction) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionSubscriptionService.java index 961fa066e64..26ce0ad10ab 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionSubscriptionService.java @@ -39,7 +39,7 @@ private void notifySubscribers(final Transaction pendingTransaction) { final List subscriptions = pendingTransactionSubscriptions(); final PendingTransactionResult hashResult = - new PendingTransactionResult(pendingTransaction.hash()); + new PendingTransactionResult(pendingTransaction.getHash()); final PendingTransactionDetailResult detailResult = new PendingTransactionDetailResult(pendingTransaction); for (final Subscription subscription : subscriptions) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/LogsSubscriptionParam.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/LogsSubscriptionParam.java deleted file mode 100644 index fbe495b23a5..00000000000 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/LogsSubscriptionParam.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonProperty; - -class LogsSubscriptionParam { - - private final List address; - private final List topics; - - @JsonCreator - LogsSubscriptionParam( - @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) @JsonProperty("address") - final List address, - @JsonProperty("topics") final List topics) { - this.address = address; - this.topics = topics; - } - - List address() { - return address; - } - - List topics() { - return topics; - } -} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscribeRequest.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscribeRequest.java index 22ea539ee64..0775d9f3b53 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscribeRequest.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscribeRequest.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; import java.util.Objects; @@ -22,17 +22,17 @@ public class SubscribeRequest { private final SubscriptionType subscriptionType; private final Boolean includeTransaction; - private final FilterParameter filterParameter; + private final LogsQuery logsQuery; private final String connectionId; public SubscribeRequest( final SubscriptionType subscriptionType, - final FilterParameter filterParameter, + final LogsQuery logsQuery, final Boolean includeTransaction, final String connectionId) { this.subscriptionType = subscriptionType; this.includeTransaction = includeTransaction; - this.filterParameter = filterParameter; + this.logsQuery = logsQuery; this.connectionId = connectionId; } @@ -40,8 +40,8 @@ public SubscriptionType getSubscriptionType() { return subscriptionType; } - public FilterParameter getFilterParameter() { - return filterParameter; + public LogsQuery getLogsQuery() { + return logsQuery; } public Boolean getIncludeTransaction() { @@ -54,16 +54,9 @@ public String getConnectionId() { @Override public String toString() { - return "SubscribeRequest{" - + "subscriptionType=" - + subscriptionType - + ", includeTransaction=" - + includeTransaction - + ", filterParameter=" - + filterParameter - + ", connectionId=" - + connectionId - + '}'; + return String.format( + "SubscribeRequest{subscriptionType=%s, includeTransaction=%s, logsQuery=%s, connectionId=%s}", + subscriptionType, includeTransaction, logsQuery, connectionId); } @Override @@ -77,12 +70,12 @@ public boolean equals(final Object o) { final SubscribeRequest that = (SubscribeRequest) o; return subscriptionType == that.subscriptionType && Objects.equals(includeTransaction, that.includeTransaction) - && Objects.equals(filterParameter, that.filterParameter) + && Objects.equals(logsQuery, that.logsQuery) && Objects.equals(connectionId, that.connectionId); } @Override public int hashCode() { - return Objects.hash(subscriptionType, includeTransaction, filterParameter, connectionId); + return Objects.hash(subscriptionType, includeTransaction, logsQuery, connectionId); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapper.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapper.java index ac0e042dcee..2b8ff7301e4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapper.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapper.java @@ -14,16 +14,12 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request; -import org.hyperledger.besu.ethereum.api.TopicsParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.methods.WebSocketRpcRequest; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; import java.util.Optional; public class SubscriptionRequestMapper { @@ -77,31 +73,8 @@ private SubscribeRequest parseNewBlockHeadersRequest( private SubscribeRequest parseLogsRequest( final WebSocketRpcRequest request, final JsonRpcParameter parameter) { - final LogsSubscriptionParam logFilterParams = - parameter.required(request.getParams(), 1, LogsSubscriptionParam.class); - return new SubscribeRequest( - SubscriptionType.LOGS, - createFilterParameter(logFilterParams), - null, - request.getConnectionId()); - } - - private FilterParameter createFilterParameter(final LogsSubscriptionParam logFilterParams) { - final List addresses = hasAddresses(logFilterParams); - final List> topics = hasTopics(logFilterParams); - return new FilterParameter(null, null, addresses, new TopicsParameter(topics), null); - } - - private List hasAddresses(final LogsSubscriptionParam logFilterParams) { - return logFilterParams.address() != null && !logFilterParams.address().isEmpty() - ? logFilterParams.address() - : Collections.emptyList(); - } - - private List> hasTopics(final LogsSubscriptionParam logFilterParams) { - return logFilterParams.topics() != null && !logFilterParams.topics().isEmpty() - ? Arrays.asList(logFilterParams.topics()) - : Collections.emptyList(); + final LogsQuery logsQuery = parameter.required(request.getParams(), 1, LogsQuery.class); + return new SubscribeRequest(SubscriptionType.LOGS, logsQuery, null, request.getConnectionId()); } public UnsubscribeRequest mapUnsubscribeRequest(final JsonRpcRequest jsonRpcRequest) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionService.java index 3f5d108c27a..9649bf0c73a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionService.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.syncing; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.JsonRpcResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.SyncingResult; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.Subscription; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; @@ -26,36 +27,24 @@ public class SyncingSubscriptionService { private final SubscriptionManager subscriptionManager; - private Optional lastMessageWasInSync = Optional.empty(); public SyncingSubscriptionService( final SubscriptionManager subscriptionManager, final Synchronizer synchronizer) { this.subscriptionManager = subscriptionManager; - synchronizer.observeSyncStatus(this::sendSyncingToMatchingSubscriptions); + synchronizer.subscribeSyncStatus(this::sendSyncingToMatchingSubscriptions); } - private void sendSyncingToMatchingSubscriptions(final SyncStatus syncStatus) { + private void sendSyncingToMatchingSubscriptions(final Optional syncStatus) { subscriptionManager.notifySubscribersOnWorkerThread( SubscriptionType.SYNCING, Subscription.class, syncingSubscriptions -> { - if (syncStatus.inSync()) { - if (!lastMessageWasInSync.orElse(Boolean.FALSE)) { - syncingSubscriptions.forEach( - s -> - subscriptionManager.sendMessage( - s.getSubscriptionId(), new NotSynchronisingResult())); - lastMessageWasInSync = Optional.of(Boolean.TRUE); - } - } else { - if (lastMessageWasInSync.orElse(Boolean.TRUE)) { - syncingSubscriptions.forEach( - s -> - subscriptionManager.sendMessage( - s.getSubscriptionId(), new SyncingResult(syncStatus))); - lastMessageWasInSync = Optional.of(Boolean.FALSE); - } - } + final JsonRpcResult result = + syncStatus.isPresent() + ? new SyncingResult(syncStatus.get()) + : new NotSynchronisingResult(); + syncingSubscriptions.forEach( + s -> subscriptionManager.sendMessage(s.getSubscriptionId(), result)); }); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/BlockWithMetadata.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockWithMetadata.java similarity index 97% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/BlockWithMetadata.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockWithMetadata.java index 53513635b71..0483d52151d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/BlockWithMetadata.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockWithMetadata.java @@ -12,7 +12,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.api; +package org.hyperledger.besu.ethereum.api.query; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.util.uint.UInt256; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/queries/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java similarity index 86% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/queries/BlockchainQueries.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index bf51d5c652c..eb6b7e3bdd2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/queries/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -12,14 +12,10 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries; +package org.hyperledger.besu.ethereum.api.query; import static com.google.common.base.Preconditions.checkArgument; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.LogsQuery; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.TransactionLocation; import org.hyperledger.besu.ethereum.core.Account; @@ -28,6 +24,7 @@ import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; @@ -38,12 +35,14 @@ import org.hyperledger.besu.util.uint.UInt256; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; - -import com.google.common.collect.Lists; +import java.util.stream.IntStream; +import java.util.stream.LongStream; public class BlockchainQueries { @@ -324,7 +323,7 @@ public Optional> blockByHashWithTxHashes( (td) -> { final List txs = body.getTransactions().stream() - .map(Transaction::hash) + .map(Transaction::getHash) .collect(Collectors.toList()); final List ommers = body.getOmmers().stream() @@ -487,72 +486,37 @@ public Optional transactionReceiptByTransactionH */ public List matchingLogs( final long fromBlockNumber, final long toBlockNumber, final LogsQuery query) { - if (fromBlockNumber > toBlockNumber || toBlockNumber > headBlockNumber()) { - return Lists.newArrayList(); - } - List matchingLogs = Lists.newArrayList(); - for (long blockNumber = fromBlockNumber; blockNumber <= toBlockNumber; blockNumber++) { - final Hash blockhash = blockchain.getBlockHashByNumber(blockNumber).get(); - final boolean logHasBeenRemoved = !blockchain.blockIsOnCanonicalChain(blockhash); - final List receipts = blockchain.getTxReceipts(blockhash).get(); - final List transaction = - blockchain.getBlockBody(blockhash).get().getTransactions(); - matchingLogs = - generateLogWithMetadata( - receipts, - blockNumber, - query, - blockhash, - matchingLogs, - transaction, - logHasBeenRemoved); - } - return matchingLogs; - } - - public List matchingLogs(final Hash blockhash, final LogsQuery query) { - final List matchingLogs = Lists.newArrayList(); - Optional blockHeader = blockchain.getBlockHeader(blockhash); - if (!blockHeader.isPresent()) { - return matchingLogs; + // rangeClosed handles the inverted from/to situations automatically with zero results. + return LongStream.rangeClosed(fromBlockNumber, toBlockNumber) + .mapToObj(blockchain::getBlockHeader) + // Use takeWhile instead of clamping on toBlockNumber/headBlockNumber because it may get an + // extra block or two for a query that has a toBlockNumber past chain head. Similarly this + // handles the case when fromBlockNumber is past chain head. + .takeWhile(Optional::isPresent) + .map(Optional::get) + .filter(header -> query.couldMatch(header.getLogsBloom())) + .flatMap(header -> matchingLogs(header.getHash(), query).stream()) + .collect(Collectors.toList()); + } + + public List matchingLogs(final Hash blockHash, final LogsQuery query) { + final Optional blockHeader = blockchain.getBlockHeader(blockHash); + if (blockHeader.isEmpty()) { + return Collections.emptyList(); } - final List receipts = blockchain.getTxReceipts(blockhash).get(); - final List transaction = - blockchain.getBlockBody(blockhash).get().getTransactions(); + final List receipts = blockchain.getTxReceipts(blockHash).get(); + final List transactions = + blockchain.getBlockBody(blockHash).get().getTransactions(); final long number = blockHeader.get().getNumber(); - final boolean logHasBeenRemoved = !blockchain.blockIsOnCanonicalChain(blockhash); - return generateLogWithMetadata( - receipts, number, query, blockhash, matchingLogs, transaction, logHasBeenRemoved); - } - - private List generateLogWithMetadata( - final List receipts, - final long number, - final LogsQuery query, - final Hash blockhash, - final List matchingLogs, - final List transaction, - final boolean removed) { - for (int transactionIndex = 0; transactionIndex < receipts.size(); ++transactionIndex) { - final TransactionReceipt receipt = receipts.get(transactionIndex); - for (int logIndex = 0; logIndex < receipt.getLogs().size(); ++logIndex) { - if (query.matches(receipt.getLogs().get(logIndex))) { - final LogWithMetadata logWithMetaData = - new LogWithMetadata( - logIndex, - number, - blockhash, - transaction.get(transactionIndex).hash(), - transactionIndex, - receipts.get(transactionIndex).getLogs().get(logIndex).getLogger(), - receipts.get(transactionIndex).getLogs().get(logIndex).getData(), - receipts.get(transactionIndex).getLogs().get(logIndex).getTopics(), - removed); - matchingLogs.add(logWithMetaData); - } - } - } - return matchingLogs; + final boolean removed = !blockchain.blockIsOnCanonicalChain(blockHash); + return IntStream.range(0, receipts.size()) + .mapToObj( + i -> + LogWithMetadata.generate( + receipts.get(i), number, blockHash, transactions.get(i).getHash(), i, removed)) + .flatMap(Collection::stream) + .filter(query::matches) + .collect(Collectors.toList()); } /** diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/LogsQuery.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/LogsQuery.java new file mode 100644 index 00000000000..2cc76a8858c --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/LogsQuery.java @@ -0,0 +1,151 @@ +/* + * + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.hyperledger.besu.ethereum.api.query; + +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.toUnmodifiableList; + +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TopicsDeserializer; +import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.Log; +import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogsBloomFilter; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.google.common.collect.Lists; + +public class LogsQuery { + + private final List
addresses; + private final List> topics; + private final List addressBlooms; + private final List> topicsBlooms; + + @JsonCreator + public LogsQuery( + @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) @JsonProperty("address") + final List
addresses, + @JsonDeserialize(using = TopicsDeserializer.class) @JsonProperty("topics") + final List> topics) { + this.addresses = addresses != null ? addresses : emptyList(); + this.topics = topics != null ? topics : emptyList(); + this.addressBlooms = + this.addresses.stream().map(LogsBloomFilter::computeBytes).collect(toUnmodifiableList()); + this.topicsBlooms = + this.topics.stream() + .map( + subTopics -> + subTopics.stream() + .filter(Objects::nonNull) + .map(LogsBloomFilter::computeBytes) + .collect(Collectors.toList())) + .collect(toUnmodifiableList()); + } + + public boolean couldMatch(final LogsBloomFilter bloom) { + return (addressBlooms.isEmpty() || addressBlooms.stream().anyMatch(bloom::couldContain)) + && (topicsBlooms.isEmpty() + || topicsBlooms.stream() + .allMatch( + topics -> topics.isEmpty() || topics.stream().anyMatch(bloom::couldContain))); + } + + public boolean matches(final Log log) { + return matchesAddresses(log.getLogger()) && matchesTopics(log.getTopics()); + } + + private boolean matchesAddresses(final Address address) { + return addresses.isEmpty() || addresses.contains(address); + } + + private boolean matchesTopics(final List topics) { + return this.topics.isEmpty() + || (topics.size() >= this.topics.size() + && IntStream.range(0, this.topics.size()) + .allMatch(i -> matchesTopic(topics.get(i), this.topics.get(i)))); + } + + private boolean matchesTopic(final LogTopic topic, final List matchCriteria) { + return matchCriteria.contains(null) || matchCriteria.contains(topic); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final LogsQuery logsQuery = (LogsQuery) o; + return Objects.equals(addresses, logsQuery.addresses) + && Objects.equals(topics, logsQuery.topics); + } + + @Override + public String toString() { + return String.format( + "%s{addresses=%s, topics=%s", getClass().getSimpleName(), addresses, topics); + } + + @Override + public int hashCode() { + return Objects.hash(addresses, topics); + } + + public static class Builder { + private final List
queryAddresses = Lists.newArrayList(); + private final List> queryTopics = Lists.newArrayList(); + + public Builder address(final Address address) { + if (address != null) { + queryAddresses.add(address); + } + return this; + } + + public Builder addresses(final Address... addresses) { + if (addresses != null && addresses.length > 0) { + queryAddresses.addAll(Arrays.asList(addresses)); + } + return this; + } + + public Builder addresses(final List
addresses) { + if (addresses != null && !addresses.isEmpty()) { + queryAddresses.addAll(addresses); + } + return this; + } + + public Builder topics(final List> topics) { + if (topics != null && !topics.isEmpty()) { + queryTopics.addAll(topics); + } + return this; + } + + public LogsQuery build() { + return new LogsQuery(queryAddresses, queryTopics); + } + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/queries/TransactionReceiptWithMetadata.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java similarity index 97% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/queries/TransactionReceiptWithMetadata.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java index ce427ac437d..4541b5ea59c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/queries/TransactionReceiptWithMetadata.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java @@ -12,7 +12,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries; +package org.hyperledger.besu.ethereum.api.query; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.Transaction; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/TransactionWithMetadata.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionWithMetadata.java similarity index 97% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/TransactionWithMetadata.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionWithMetadata.java index 26763b312c1..5b519b1dc41 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/TransactionWithMetadata.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionWithMetadata.java @@ -1,4 +1,5 @@ /* + * * Copyright ConsenSys AG. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with @@ -11,8 +12,9 @@ * specific language governing permissions and limitations under the License. * * SPDX-License-Identifier: Apache-2.0 + * */ -package org.hyperledger.besu.ethereum.api; +package org.hyperledger.besu.ethereum.api.query; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.Transaction; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractDataFetcherTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractDataFetcherTest.java index a5a44631ebd..1022c1ea889 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractDataFetcherTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractDataFetcherTest.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.graphql; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; import org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.NormalBlockAdapter; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; import java.util.Optional; @@ -40,7 +40,7 @@ public abstract class AbstractDataFetcherTest { @Mock protected GraphQLDataFetcherContext context; - @Mock protected BlockchainQuery query; + @Mock protected BlockchainQueries query; @Rule public ExpectedException thrown = ExpectedException.none(); @@ -49,6 +49,6 @@ public void before() { fetchers = new GraphQLDataFetchers(supportedCapabilities); fetcher = fetchers.getBlockDataFetcher(); Mockito.when(environment.getContext()).thenReturn(context); - Mockito.when(context.getBlockchainQuery()).thenReturn(query); + Mockito.when(context.getBlockchainQueries()).thenReturn(query); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java index e6acc8604d0..ffb8aa3f789 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java @@ -21,8 +21,8 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.core.DefaultSyncStatus; import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider; -import org.hyperledger.besu.ethereum.core.SyncStatus; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Wei; @@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; import org.hyperledger.besu.ethereum.util.RawBlockIterator; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.testutil.BlockTestUtil; import java.net.URL; @@ -120,7 +121,7 @@ public static void setupConstants() throws Exception { @Before public void setupTest() throws Exception { final Synchronizer synchronizerMock = Mockito.mock(Synchronizer.class); - final SyncStatus status = new SyncStatus(1, 2, 3); + final SyncStatus status = new DefaultSyncStatus(1, 2, 3); Mockito.when(synchronizerMock.getSyncStatus()).thenReturn(Optional.of(status)); final EthHashMiningCoordinator miningCoordinatorMock = diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java index 2f9f4f5dc24..77558301d6b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/BlockDataFetcherTest.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.graphql; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.util.bytes.BytesValue; @@ -46,7 +46,7 @@ public void onlyNumber() throws Exception { Mockito.when(environment.getArgument(ArgumentMatchers.eq("hash"))).thenReturn(null); Mockito.when(environment.getContext()).thenReturn(context); - Mockito.when(context.getBlockchainQuery()).thenReturn(query); + Mockito.when(context.getBlockchainQueries()).thenReturn(query); Mockito.when(query.blockByNumber(ArgumentMatchers.anyLong())) .thenReturn(Optional.of(new BlockWithMetadata<>(null, null, null, null, 0))); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java index 25d1d987f0a..94f7f1871fe 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/EthGraphQLHttpBySpecTest.java @@ -75,6 +75,7 @@ public static Collection specs() { specs.add("eth_getCode_noCode"); specs.add("eth_getLogs_matchTopic"); + specs.add("eth_getLogs_range"); specs.add("eth_getStorageAt"); specs.add("eth_getStorageAt_illegalRangeGreaterThan"); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceCorsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceCorsTest.java index 1031f8771f4..7fca5735f5d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceCorsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceCorsTest.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.graphql; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -203,7 +203,7 @@ private GraphQLHttpService createGraphQLHttpServiceWithAllowedDomains( config.setCorsAllowedDomains(Lists.newArrayList(corsAllowedDomains)); } - final BlockchainQuery blockchainQueries = Mockito.mock(BlockchainQuery.class); + final BlockchainQueries blockchainQueries = Mockito.mock(BlockchainQueries.class); final Synchronizer synchronizer = Mockito.mock(Synchronizer.class); final EthHashMiningCoordinator miningCoordinatorMock = @@ -211,7 +211,7 @@ private GraphQLHttpService createGraphQLHttpServiceWithAllowedDomains( final GraphQLDataFetcherContext dataFetcherContext = Mockito.mock(GraphQLDataFetcherContext.class); - Mockito.when(dataFetcherContext.getBlockchainQuery()).thenReturn(blockchainQueries); + Mockito.when(dataFetcherContext.getBlockchainQueries()).thenReturn(blockchainQueries); Mockito.when(dataFetcherContext.getMiningCoordinator()).thenReturn(miningCoordinatorMock); Mockito.when(dataFetcherContext.getTransactionPool()) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java index bf9207c78de..2f934ebde02 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.graphql; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -67,7 +67,7 @@ public void initServerAndClient() throws Exception { } private GraphQLHttpService createGraphQLHttpService() throws Exception { - final BlockchainQuery blockchainQueries = Mockito.mock(BlockchainQuery.class); + final BlockchainQueries blockchainQueries = Mockito.mock(BlockchainQueries.class); final Synchronizer synchronizer = Mockito.mock(Synchronizer.class); final EthHashMiningCoordinator miningCoordinatorMock = @@ -75,7 +75,7 @@ private GraphQLHttpService createGraphQLHttpService() throws Exception { final GraphQLDataFetcherContext dataFetcherContext = Mockito.mock(GraphQLDataFetcherContext.class); - Mockito.when(dataFetcherContext.getBlockchainQuery()).thenReturn(blockchainQueries); + Mockito.when(dataFetcherContext.getBlockchainQueries()).thenReturn(blockchainQueries); Mockito.when(dataFetcherContext.getMiningCoordinator()).thenReturn(miningCoordinatorMock); Mockito.when(dataFetcherContext.getTransactionPool()) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceTest.java index e6d3849118e..064c7df1cdd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceTest.java @@ -16,9 +16,9 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; -import org.hyperledger.besu.ethereum.api.graphql.internal.BlockchainQuery; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.Synchronizer; @@ -64,7 +64,7 @@ public class GraphQLHttpServiceTest { private static String baseUrl; protected static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); protected static final MediaType GRAPHQL = MediaType.parse("application/graphql; charset=utf-8"); - private static BlockchainQuery blockchainQueries; + private static BlockchainQueries blockchainQueries; private static Synchronizer synchronizer; private static GraphQL graphQL; private static GraphQLDataFetchers dataFetchers; @@ -75,14 +75,14 @@ public class GraphQLHttpServiceTest { @BeforeClass public static void initServerAndClient() throws Exception { - blockchainQueries = Mockito.mock(BlockchainQuery.class); + blockchainQueries = Mockito.mock(BlockchainQueries.class); synchronizer = Mockito.mock(Synchronizer.class); graphQL = Mockito.mock(GraphQL.class); miningCoordinatorMock = Mockito.mock(EthHashMiningCoordinator.class); dataFetcherContext = Mockito.mock(GraphQLDataFetcherContext.class); - Mockito.when(dataFetcherContext.getBlockchainQuery()).thenReturn(blockchainQueries); + Mockito.when(dataFetcherContext.getBlockchainQueries()).thenReturn(blockchainQueries); Mockito.when(dataFetcherContext.getMiningCoordinator()).thenReturn(miningCoordinatorMock); Mockito.when(dataFetcherContext.getTransactionPool()) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java index 7424ee81a97..1af7864a72a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java @@ -26,8 +26,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterRepository; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.PrivacyParameters; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java index 418a782b7aa..40b4d1b10eb 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java @@ -22,8 +22,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.health.HealthService; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java index d9c8ff73a7c..ca423147645 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java @@ -28,8 +28,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.NetVersion; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.Web3ClientVersion; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.Web3Sha3; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java index c6fe45f92c2..881325c480b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java @@ -24,9 +24,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.health.HealthService; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java index 4c5bac65130..d9b9b527395 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java @@ -25,23 +25,24 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.config.StubGenesisConfigOptions; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.health.HealthService; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.DefaultSyncStatus; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.LogsBloomFilter; import org.hyperledger.besu.ethereum.core.PrivacyParameters; -import org.hyperledger.besu.ethereum.core.SyncStatus; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Wei; @@ -54,6 +55,7 @@ import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; +import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.util.bytes.BytesValue; import org.hyperledger.besu.util.bytes.BytesValues; import org.hyperledger.besu.util.uint.UInt256; @@ -1749,7 +1751,7 @@ private void verifyBlockResult( final Transaction transaction = block.getBody().getTransactions().get(i); if (shouldTransactionsBeHashed) { assertThat(Hash.fromHexString(transactionsResult.getString(i))) - .isEqualTo(transaction.hash()); + .isEqualTo(transaction.getHash()); } else { final JsonObject transactionResult = transactionsResult.getJsonObject(i); final Integer expectedIndex = i; @@ -1767,7 +1769,7 @@ private void assertTransactionResultMatchesTransaction( final Integer index, final Hash blockHash, final Long blockNumber) { - assertThat(Hash.fromHexString(result.getString("hash"))).isEqualTo(transaction.hash()); + assertThat(Hash.fromHexString(result.getString("hash"))).isEqualTo(transaction.getHash()); assertThat(Long.decode(result.getString("nonce"))).isEqualByComparingTo(transaction.getNonce()); if (blockHash != null) { assertThat(Hash.fromHexString(result.getString("blockHash"))).isEqualTo(blockHash); @@ -1855,7 +1857,7 @@ public void ethSyncingFalse() throws Exception { @Test public void ethSyncingResultIsPresent() throws Exception { - final SyncStatus testResult = new SyncStatus(1L, 8L, 7L); + final SyncStatus testResult = new DefaultSyncStatus(1L, 8L, 7L); when(synchronizer.getSyncStatus()).thenReturn(Optional.of(testResult)); final String id = "999"; final RequestBody body = @@ -1898,7 +1900,7 @@ public BlockWithMetadata blockWithMetadataAndTxHashes(final Block bl final List txs = block.getBody().getTransactions().stream() - .map(Transaction::hash) + .map(Transaction::getHash) .collect(Collectors.toList()); final List ommers = block.getBody().getOmmers().stream().map(BlockHeader::getHash).collect(Collectors.toList()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProviderTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProviderTest.java index 7ab16c5d03d..43c1d71f273 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProviderTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/LatestNonceProviderTest.java @@ -18,7 +18,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/SimpleTestTransactionBuilder.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/SimpleTestTransactionBuilder.java index 23070bc6437..35c2f2faa88 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/SimpleTestTransactionBuilder.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/SimpleTestTransactionBuilder.java @@ -59,7 +59,7 @@ public static Transaction transaction( final String s) { final Transaction transaction = mock(Transaction.class); - when(transaction.hash()).thenReturn(blockHash); + when(transaction.getHash()).thenReturn(blockHash); when(transaction.getGasPrice()).thenReturn(Wei.fromHexString(gasPrice)); when(transaction.getNonce()).thenReturn(unsignedLong(nonce)); when(transaction.getV()).thenReturn(bigInteger(v)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/TraceJsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/TraceJsonRpcHttpBySpecTest.java index 6b6afa74317..a8bd6dbff16 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/TraceJsonRpcHttpBySpecTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/TraceJsonRpcHttpBySpecTest.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import java.net.URL; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/health/ReadinessCheckTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/health/ReadinessCheckTest.java index 4fda451d979..733aeda241f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/health/ReadinessCheckTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/health/ReadinessCheckTest.java @@ -18,6 +18,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import org.hyperledger.besu.ethereum.core.DefaultSyncStatus; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.plugin.data.SyncStatus; @@ -142,7 +143,6 @@ public void shouldNotBeReadyWhenCustomMaxBlocksBehindIsInvalid() { } private Optional createSyncStatus(final int currentBlock, final int highestBlock) { - return Optional.of( - new org.hyperledger.besu.ethereum.core.SyncStatus(0, currentBlock, highestBlock)); + return Optional.of(new DefaultSyncStatus(0, currentBlock, highestBlock)); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java index 9c5f25a150c..252c0abac87 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java @@ -38,7 +38,7 @@ private Hash recordPendingTransaction(final int blockNumber, final int transacti final Block block = blockchainSetupUtil.getBlock(blockNumber); final Transaction transaction = block.getBody().getTransactions().get(transactionIndex); filterManager.recordPendingTransactionEvent(transaction); - return transaction.hash(); + return transaction.getHash(); } @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java index 392879af7b2..3355b10806b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java @@ -18,23 +18,23 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.refEq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.LogsQuery; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.util.bytes.BytesValue; @@ -85,7 +85,7 @@ public void shouldCheckMatchingLogsWhenRecordedNewBlockEvent() { filterManager.installLogFilter(latest(), latest(), logsQuery()); recordNewBlockEvent(); - verify(blockchainQueries).matchingLogs(eq(100L), eq(100L), refEq(logsQuery())); + verify(blockchainQueries).matchingLogs(eq(100L), eq(100L), eq(logsQuery())); } @Test @@ -95,14 +95,14 @@ public void shouldUseHeadBlockAsFromBlockNumberWhenCheckingLogsForChanges() { filterManager.installLogFilter(blockNum(1L), blockNum(10L), logsQuery()); recordNewBlockEvent(); - verify(blockchainQueries).matchingLogs(eq(3L), eq(10L), refEq(logsQuery())); + verify(blockchainQueries).matchingLogs(eq(3L), eq(10L), eq(logsQuery())); } @Test public void shouldReturnLogWhenLogFilterMatches() { final LogWithMetadata log = logWithMetadata(); when(blockchainQueries.headBlockNumber()).thenReturn(100L); - when(blockchainQueries.matchingLogs(eq(100L), eq(100L), refEq(logsQuery()))) + when(blockchainQueries.matchingLogs(eq(100L), eq(100L), eq(logsQuery()))) .thenReturn(Lists.newArrayList(log)); final String filterId = filterManager.installLogFilter(latest(), latest(), logsQuery()); @@ -145,8 +145,11 @@ public void shouldClearLogsAfterGettingLogChanges() { } private void recordNewBlockEvent() { + final BlockDataGenerator gen = new BlockDataGenerator(); + final Block block = gen.block(); filterManager.recordBlockEvent( - BlockAddedEvent.createForHeadAdvancement(new BlockDataGenerator().block()), + BlockAddedEvent.createForHeadAdvancement( + block, LogWithMetadata.generate(block, gen.receipts(block), false)), blockchainQueries.getBlockchain()); } @@ -159,13 +162,13 @@ public void getLogsForAbsentFilterReturnsNull() { public void getLogsForExistingFilterReturnsResults() { final LogWithMetadata log = logWithMetadata(); when(blockchainQueries.headBlockNumber()).thenReturn(100L); - when(blockchainQueries.matchingLogs(eq(100L), eq(100L), refEq(logsQuery()))) + when(blockchainQueries.matchingLogs(eq(100L), eq(100L), eq(logsQuery()))) .thenReturn(Lists.newArrayList(log)); final String filterId = filterManager.installLogFilter(latest(), latest(), logsQuery()); final List retrievedLogs = filterManager.logs(filterId); - assertThat(retrievedLogs).isEqualToComparingFieldByFieldRecursively(Lists.newArrayList(log)); + assertThat(retrievedLogs).usingRecursiveComparison().isEqualTo(Lists.newArrayList(log)); } @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java index 1c6d8aee994..31e12ee6fda 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java @@ -22,7 +22,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Block; @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -232,13 +233,14 @@ private Hash appendBlockToBlockchain() { new BlockDataGenerator.BlockOptions().setBlockNumber(blockNumber).setParentHash(parentHash); currentBlock = blockGenerator.block(options); filterManager.recordBlockEvent( - BlockAddedEvent.createForHeadAdvancement(currentBlock), blockchainQueries.getBlockchain()); + BlockAddedEvent.createForHeadAdvancement(currentBlock, Collections.emptyList()), + blockchainQueries.getBlockchain()); return currentBlock.getHash(); } private Hash receivePendingTransaction() { final Transaction transaction = blockGenerator.transaction(); filterManager.recordPendingTransactionEvent(transaction); - return transaction.hash(); + return transaction.getHash(); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogsQueryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogsQueryTest.java index e735154237d..b35c11d8190 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogsQueryTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogsQueryTest.java @@ -14,12 +14,15 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; -import org.hyperledger.besu.ethereum.api.LogsQuery; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Log; import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogsBloomFilter; import org.hyperledger.besu.util.bytes.BytesValue; import java.util.ArrayList; @@ -39,6 +42,7 @@ public void wildcardQueryAddressTopicReturnTrue() { final List topics = new ArrayList<>(); final Log log = new Log(address, data, topics); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } @@ -50,6 +54,7 @@ public void univariateAddressMatchReturnsTrue() { final List topics = new ArrayList<>(); final Log log = new Log(address, BytesValue.fromHexString("0x0102"), topics); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } @@ -75,6 +80,7 @@ public void multivariateAddressQueryMatchReturnsTrue() { final List topics = new ArrayList<>(); final Log log = new Log(address1, BytesValue.fromHexString("0x0102"), topics); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } @@ -127,6 +133,7 @@ public void univariateTopicQueryMatchReturnTrue() { final LogsQuery query = new LogsQuery.Builder().address(address).topics(topicsQuery).build(); final Log log = new Log(address, BytesValue.fromHexString("0x0102"), Lists.newArrayList(topic)); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } @@ -212,6 +219,7 @@ public void multivariateSurplusTopicMatchMultivariateNullQueryReturnTrue() { new LogsQuery.Builder().address(address1).topics(queryParameter).build(); final Log log = new Log(address1, BytesValue.fromHexString("0x0102"), logTopics); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } @@ -241,6 +249,7 @@ public void multivariateSurplusTopicMatchMultivariateQueryReturnTrue_00() { final LogsQuery query = new LogsQuery.Builder().address(address).topics(queryParameter).build(); final Log log = new Log(address, BytesValue.fromHexString("0x0102"), logTopics); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } @@ -273,6 +282,7 @@ public void multivariateSurplusTopicMatchMultivariateQueryReturnTrue_01() { final LogsQuery query = new LogsQuery.Builder().address(address).topics(queryParameter).build(); final Log log = new Log(address, BytesValue.fromHexString("0x0102"), logTopics); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } @@ -306,6 +316,7 @@ public void multivariateSurplusTopicMatchMultivariateQueryReturnTrue_02() { final LogsQuery query = new LogsQuery.Builder().address(address).topics(queryParameter).build(); final Log log = new Log(address, BytesValue.fromHexString("0x0102"), logTopics); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } @@ -342,6 +353,7 @@ public void redundantUnivariateTopicMatchMultivariateQueryReturnTrue() { final LogsQuery query = new LogsQuery.Builder().address(address).topics(queryParameter).build(); final Log log = new Log(address, BytesValue.fromHexString("0x0102"), logTopics); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } @@ -415,6 +427,27 @@ public void multivariateTopicMatchMultivariateQueryReturnTrue() { final LogsQuery query = new LogsQuery.Builder().address(address).topics(queryParameter).build(); final Log log = new Log(address, BytesValue.fromHexString("0x0102"), logTopics); + assertThat(query.couldMatch(LogsBloomFilter.compute(List.of(log)))).isTrue(); assertThat(query.matches(log)).isTrue(); } + + @Test + public void emptySubTopicProducesNoMatches() { + final Address address = Address.fromHexString("0x1111111111111111111111111111111111111111"); + + final LogTopic topic1 = + LogTopic.fromHexString( + "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + final LogTopic topic2 = + LogTopic.fromHexString( + "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + final List> queryParameter = + Lists.newArrayList(singletonList(topic1), emptyList()); + + final LogsQuery query = new LogsQuery.Builder().address(address).topics(queryParameter).build(); + final Log log = + new Log(address, BytesValue.fromHexString("0x0102"), Lists.newArrayList(topic1, topic2)); + + assertThat(query.matches(log)).isFalse(); + } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java index 5379718c363..d27c1f6777b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java @@ -21,11 +21,11 @@ import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.StubGenesisConfigOptions; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.ChainHead; import org.hyperledger.besu.ethereum.core.Hash; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java index b6fcf12aa51..ed8920d283b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java @@ -21,14 +21,14 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugStorageRangeAtResult; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.AccountStorageEntry; @@ -77,7 +77,7 @@ public class DebugStorageRangeAtTest { @Before public void setUp() { - when(transaction.hash()).thenReturn(transactionHash); + when(transaction.getHash()).thenReturn(transactionHash); } @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumberTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumberTest.java index c83d2a8ec5e..14432a8fc23 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumberTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumberTest.java @@ -27,9 +27,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.debug.TraceFrame; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockTest.java index 5fbb54f08dd..057e2b505de 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockTest.java @@ -21,16 +21,16 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.Gas; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransactionTest.java index d015574e860..72d183d1661 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransactionTest.java @@ -20,15 +20,15 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTracer; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.StructLog; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.Hash; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumberTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumberTest.java index 4066a43d2eb..40137e8d58b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumberTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlockNumberTest.java @@ -18,10 +18,10 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.junit.Before; import org.junit.Test; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java index 9c6a40147f7..d2816899ae0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java @@ -27,10 +27,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.transaction.CallParameter; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java index 375ff834cd7..5a15afe3091 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java @@ -22,12 +22,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.transaction.CallParameter; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHashTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHashTest.java index d025458fd28..660a848dc17 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHashTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByHashTest.java @@ -20,8 +20,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Hash; import org.junit.Before; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java index a0c38d1918f..7b640376d10 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java @@ -22,7 +22,6 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; @@ -34,6 +33,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.util.bytes.BytesValue; import java.util.List; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java index d4cdbb32bd4..c543108cba4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; @@ -32,6 +31,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.util.bytes.BytesValue; import java.util.ArrayList; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProofTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProofTest.java index b27ab7155bb..3c3caf95024 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProofTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetProofTest.java @@ -23,11 +23,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.proof.GetProofResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.MutableWorldState; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndexTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndexTest.java index 87bbed03ef3..cfce04328ee 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndexTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByBlockHashAndIndexTest.java @@ -20,9 +20,9 @@ import org.hyperledger.besu.crypto.Hash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.util.bytes.Bytes32; import org.hyperledger.besu.util.bytes.BytesValue; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCountTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCountTest.java index 415bd0d8e5f..1003a1af0bf 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCountTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCountTest.java @@ -20,8 +20,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java index cef6e205699..458935d6592 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java @@ -21,11 +21,11 @@ import org.hyperledger.besu.crypto.SECP256K1.Signature; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptRootResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptStatusResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndexTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndexTest.java index 716582e9978..8e9cbd60344 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndexTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockHashAndIndexTest.java @@ -20,15 +20,15 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.SECP256K1.KeyPair; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndexTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndexTest.java index b58443fd401..371482f0135 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndexTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetUncleByBlockNumberAndIndexTest.java @@ -20,15 +20,15 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.SECP256K1.KeyPair; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMiningTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMiningTest.java index 44bd5494b8e..b8856b86afa 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMiningTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMiningTest.java @@ -49,26 +49,26 @@ public void returnsCorrectMethodName() { } @Test - public void shouldReturnTrueWhenMiningCoordinatorExistsAndRunning() { + public void shouldReturnTrueWhenMining() { final JsonRpcRequest request = requestWithParams(); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(request.getId(), true); - when(miningCoordinator.isRunning()).thenReturn(true); + when(miningCoordinator.isMining()).thenReturn(true); final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); - verify(miningCoordinator).isRunning(); + verify(miningCoordinator).isMining(); verifyNoMoreInteractions(miningCoordinator); } @Test - public void shouldReturnFalseWhenMiningCoordinatorExistsAndDisabled() { + public void shouldReturnFalseWhenNotMining() { final JsonRpcRequest request = requestWithParams(); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(request.getId(), false); - when(miningCoordinator.isRunning()).thenReturn(false); + when(miningCoordinator.isMining()).thenReturn(false); final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); - verify(miningCoordinator).isRunning(); + verify(miningCoordinator).isMining(); verifyNoMoreInteractions(miningCoordinator); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilterTest.java index 29d0df9e686..a263b718fd1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilterTest.java @@ -14,14 +14,15 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.refEq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.api.LogsQuery; -import org.hyperledger.besu.ethereum.api.TopicsParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; @@ -29,10 +30,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.LogTopic; -import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Optional; import org.junit.Before; import org.junit.Test; @@ -85,33 +89,32 @@ public void newFilterWithoutAddressAndTopicsParamsInstallsEmptyLogFilter() { final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(request.getId(), "0x1"); final LogsQuery expectedLogsQuery = new LogsQuery.Builder().build(); - when(filterManager.installLogFilter(any(), any(), refEq(expectedLogsQuery))).thenReturn("0x1"); + when(filterManager.installLogFilter(any(), any(), eq(expectedLogsQuery))).thenReturn("0x1"); final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); verify(filterManager) .installLogFilter( - refEq(blockParamLatest()), refEq(blockParamLatest()), refEq(expectedLogsQuery)); + refEq(blockParamLatest()), refEq(blockParamLatest()), eq(expectedLogsQuery)); } @Test public void newFilterWithTopicsOnlyParamInstallsExpectedLogFilter() { - final List> topics = topics(); - final FilterParameter filterParameter = filterParamWithAddressAndTopics(null, topics); + final FilterParameter filterParameter = filterParamWithAddressAndTopics(null, topics()); final JsonRpcRequest request = ethNewFilter(filterParameter); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(request.getId(), "0x1"); final LogsQuery expectedLogsQuery = - new LogsQuery.Builder().topics(new TopicsParameter(topics)).build(); - when(filterManager.installLogFilter(any(), any(), refEq(expectedLogsQuery))).thenReturn("0x1"); + new LogsQuery.Builder().topics(filterParameter.getTopics()).build(); + when(filterManager.installLogFilter(any(), any(), eq(expectedLogsQuery))).thenReturn("0x1"); final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); verify(filterManager) .installLogFilter( - refEq(blockParamLatest()), refEq(blockParamLatest()), refEq(expectedLogsQuery)); + refEq(blockParamLatest()), refEq(blockParamLatest()), eq(expectedLogsQuery)); } @Test @@ -122,45 +125,51 @@ public void newFilterWithAddressOnlyParamInstallsExpectedLogFilter() { final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(request.getId(), "0x1"); final LogsQuery expectedLogsQuery = new LogsQuery.Builder().address(address).build(); - when(filterManager.installLogFilter(any(), any(), refEq(expectedLogsQuery))).thenReturn("0x1"); + when(filterManager.installLogFilter(any(), any(), eq(expectedLogsQuery))).thenReturn("0x1"); final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); verify(filterManager) .installLogFilter( - refEq(blockParamLatest()), refEq(blockParamLatest()), refEq(expectedLogsQuery)); + refEq(blockParamLatest()), refEq(blockParamLatest()), eq(expectedLogsQuery)); } @Test public void newFilterWithAddressAndTopicsParamInstallsExpectedLogFilter() { final Address address = Address.fromHexString("0x0"); - final List> topics = topics(); + final List> topics = topics(); final FilterParameter filterParameter = filterParamWithAddressAndTopics(address, topics); final JsonRpcRequest request = ethNewFilter(filterParameter); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(request.getId(), "0x1"); final LogsQuery expectedLogsQuery = - new LogsQuery.Builder().address(address).topics(new TopicsParameter(topics)).build(); - when(filterManager.installLogFilter(any(), any(), refEq(expectedLogsQuery))).thenReturn("0x1"); + new LogsQuery.Builder().address(address).topics(filterParameter.getTopics()).build(); + when(filterManager.installLogFilter(any(), any(), eq(expectedLogsQuery))).thenReturn("0x1"); final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); verify(filterManager) .installLogFilter( - refEq(blockParamLatest()), refEq(blockParamLatest()), refEq(expectedLogsQuery)); + refEq(blockParamLatest()), refEq(blockParamLatest()), eq(expectedLogsQuery)); } - private List> topics() { - return Arrays.asList( - Arrays.asList("0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")); + private List> topics() { + return singletonList( + singletonList( + LogTopic.fromHexString( + "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"))); } private FilterParameter filterParamWithAddressAndTopics( - final Address address, final List> topics) { - final List addresses = address != null ? Arrays.asList(address.toString()) : null; - return new FilterParameter("latest", "latest", addresses, new TopicsParameter(topics), null); + final Address address, final List> topics) { + return new FilterParameter( + "latest", + "latest", + Optional.ofNullable(address).map(Collections::singletonList).orElse(emptyList()), + topics, + null); } private JsonRpcRequest ethNewFilter(final FilterParameter filterParameter) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSyncingTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSyncingTest.java index 26c8a7621e3..229fe19144d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSyncingTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSyncingTest.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.SyncingResult; +import org.hyperledger.besu.ethereum.core.DefaultSyncStatus; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.plugin.data.SyncStatus; @@ -68,8 +69,7 @@ public void shouldReturnFalseWhenSyncStatusIsEmpty() { @Test public void shouldReturnExpectedValueWhenSyncStatusIsNotEmpty() { final JsonRpcRequest request = requestWithParams(); - final SyncStatus expectedSyncStatus = - new org.hyperledger.besu.ethereum.core.SyncStatus(0, 1, 2); + final SyncStatus expectedSyncStatus = new DefaultSyncStatus(0, 1, 2); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(request.getId(), new SyncingResult(expectedSyncStatus)); final Optional optionalSyncStatus = Optional.of(expectedSyncStatus); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStartTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStartTest.java index bac27f3e941..79834897fdc 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStartTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStartTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; @@ -50,6 +51,7 @@ public void shouldReturnCorrectMethodName() { @Test public void shouldReturnTrueWhenMiningStartsSuccessfully() { + when(miningCoordinator.enable()).thenReturn(true); final JsonRpcRequest request = minerStart(); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, true); @@ -58,6 +60,17 @@ public void shouldReturnTrueWhenMiningStartsSuccessfully() { assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); } + @Test + public void shouldReturnFalseWhenMiningDoesNotStart() { + when(miningCoordinator.enable()).thenReturn(false); + final JsonRpcRequest request = minerStart(); + final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, false); + + final JsonRpcResponse actualResponse = method.response(request); + + assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); + } + @Test public void shouldReturnCoinbaseNotSetErrorWhenCoinbaseHasNotBeenSet() { final JsonRpcRequest request = minerStart(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStopTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStopTest.java index 6977204f31c..3bf5ed8b571 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStopTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStopTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; @@ -46,6 +47,7 @@ public void shouldReturnCorrectMethodName() { @Test public void shouldReturnTrueWhenMiningStopsSuccessfully() { + when(miningCoordinator.disable()).thenReturn(true); final JsonRpcRequest request = minerStop(); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, true); @@ -54,6 +56,17 @@ public void shouldReturnTrueWhenMiningStopsSuccessfully() { assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); } + @Test + public void shouldReturnFalseWhenMiningDoesNotStopSuccessfully() { + when(miningCoordinator.disable()).thenReturn(false); + final JsonRpcRequest request = minerStop(); + final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, false); + + final JsonRpcResponse actualResponse = method.response(request); + + assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); + } + private JsonRpcRequest minerStop() { return new JsonRpcRequest("2.0", "miner_stop", null); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/EeaGetTransactionCountTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivGetEeaTransactionCountTest.java similarity index 81% rename from ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/EeaGetTransactionCountTest.java rename to ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivGetEeaTransactionCountTest.java index e7287be7b1a..6a92d019a41 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/EeaGetTransactionCountTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivGetEeaTransactionCountTest.java @@ -20,8 +20,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea.EeaGetTransactionCount; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea.EeaPrivateNonceProvider; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetEeaTransactionCount; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivateEeaNonceProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; @@ -31,9 +31,9 @@ import org.junit.Before; import org.junit.Test; -public class EeaGetTransactionCountTest { +public class PrivGetEeaTransactionCountTest { - private EeaPrivateNonceProvider nonceProvider = mock(EeaPrivateNonceProvider.class); + private final PrivateEeaNonceProvider nonceProvider = mock(PrivateEeaNonceProvider.class); private JsonRpcRequest request; private final String privateFrom = "thePrivateFromKey"; @@ -43,14 +43,14 @@ public class EeaGetTransactionCountTest { @Before public void setup() { final Object[] jsonBody = new Object[] {address.toString(), privateFrom, privateFor}; - request = new JsonRpcRequest("2.0", "eea_getTransactionCount", jsonBody); + request = new JsonRpcRequest("2.0", "priv_getEeaTransactionCount", jsonBody); } @Test public void validRequestProducesExpectedNonce() { final long reportedNonce = 8L; - final EeaGetTransactionCount method = - new EeaGetTransactionCount(new JsonRpcParameter(), nonceProvider); + final PrivGetEeaTransactionCount method = + new PrivGetEeaTransactionCount(new JsonRpcParameter(), nonceProvider); when(nonceProvider.determineNonce(privateFrom, privateFor, address)).thenReturn(reportedNonce); @@ -58,14 +58,14 @@ public void validRequestProducesExpectedNonce() { assertThat(response).isInstanceOf(JsonRpcSuccessResponse.class); final JsonRpcSuccessResponse successResponse = (JsonRpcSuccessResponse) response; - int returnedValue = Integer.decode((String) successResponse.getResult()); + final int returnedValue = Integer.decode((String) successResponse.getResult()); assertThat(returnedValue).isEqualTo(reportedNonce); } @Test public void nonceProviderThrowsRuntimeExceptionProducesErrorResponse() { - final EeaGetTransactionCount method = - new EeaGetTransactionCount(new JsonRpcParameter(), nonceProvider); + final PrivGetEeaTransactionCount method = + new PrivGetEeaTransactionCount(new JsonRpcParameter(), nonceProvider); when(nonceProvider.determineNonce(privateFrom, privateFor, address)) .thenThrow(RuntimeException.class); @@ -80,8 +80,8 @@ public void nonceProviderThrowsRuntimeExceptionProducesErrorResponse() { @Test public void nonceProviderThrowsAnExceptionProducesErrorResponse() { - final EeaGetTransactionCount method = - new EeaGetTransactionCount(new JsonRpcParameter(), nonceProvider); + final PrivGetEeaTransactionCount method = + new PrivGetEeaTransactionCount(new JsonRpcParameter(), nonceProvider); when(nonceProvider.determineNonce(privateFrom, privateFor, address)) .thenThrow(RuntimeException.class); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/EeaPrivateNonceProviderTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivateEeaNonceProviderTest.java similarity index 89% rename from ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/EeaPrivateNonceProviderTest.java rename to ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivateEeaNonceProviderTest.java index cd9b9731124..c8fe54986b4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/EeaPrivateNonceProviderTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivateEeaNonceProviderTest.java @@ -25,7 +25,7 @@ import org.hyperledger.besu.enclave.types.FindPrivacyGroupRequest; import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.enclave.types.PrivacyGroup.Type; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea.EeaPrivateNonceProvider; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivateEeaNonceProvider; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler; @@ -33,20 +33,20 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; -public class EeaPrivateNonceProviderTest { +public class PrivateEeaNonceProviderTest { private final Address address = Address.fromHexString("55"); - private Enclave enclave = mock(Enclave.class); - private PrivateTransactionHandler privateTransactionHandler = + private final Enclave enclave = mock(Enclave.class); + private final PrivateTransactionHandler privateTransactionHandler = mock(PrivateTransactionHandler.class); - private final EeaPrivateNonceProvider nonceProvider = - new EeaPrivateNonceProvider(enclave, privateTransactionHandler); + private final PrivateEeaNonceProvider nonceProvider = + new PrivateEeaNonceProvider(enclave, privateTransactionHandler); @Test public void validRequestProducesExpectedNonce() { final long reportedNonce = 8L; - PrivacyGroup[] returnedGroups = + final PrivacyGroup[] returnedGroups = new PrivacyGroup[] { new PrivacyGroup("Group1", Type.LEGACY, "Group1_Name", "Group1_Desc", new String[0]), }; @@ -68,7 +68,7 @@ public void validRequestProducesExpectedNonce() { @Test public void noMatchingLegacyGroupsProducesExpectedNonce() { final long reportedNonce = 0L; - PrivacyGroup[] returnedGroups = new PrivacyGroup[0]; + final PrivacyGroup[] returnedGroups = new PrivacyGroup[0]; final ArgumentCaptor groupMembersCaptor = ArgumentCaptor.forClass(FindPrivacyGroupRequest.class); @@ -86,7 +86,7 @@ public void noMatchingLegacyGroupsProducesExpectedNonce() { @Test public void moreThanOneMatchingLegacyGroupThrowsException() { - PrivacyGroup[] returnedGroups = + final PrivacyGroup[] returnedGroups = new PrivacyGroup[] { new PrivacyGroup("Group1", Type.LEGACY, "Group1_Name", "Group1_Desc", new String[0]), new PrivacyGroup("Group2", Type.LEGACY, "Group2_Name", "Group2_Desc", new String[0]), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameterTest.java index 968824f9272..8bc00a89ed3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/FilterParameterTest.java @@ -14,16 +14,23 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.toUnmodifiableList; import static org.assertj.core.api.Assertions.assertThat; -import org.hyperledger.besu.ethereum.api.TopicsParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; +import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.LogTopic; import java.util.Arrays; -import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; import org.junit.Test; public class FilterParameterTest { @@ -126,8 +133,109 @@ public void jsonWithParamsInDifferentOrderShouldDeserializeIntoFilterParameterSu .isEqualToComparingFieldByFieldRecursively(readJsonAsFilterParameter(jsonWithTopicsLast)); } + @Test + public void whenTopicsParameterIsArrayOfStringsFilterContainsListOfSingletonLists() + throws JsonProcessingException { + final List topics = + Lists.newArrayList( + "0xce8688f853ffa65c042b72302433c25d7a230c322caba0901587534b6551091d", + null, + "0x000000000000000000000000244a53ab66ea8901c25efc48c8ab84662643cc74"); + final FilterParameter filter = createFilterWithTopics(topics); + + assertThat(filter.getTopics()) + .containsExactly( + singletonList( + LogTopic.fromHexString( + "0xce8688f853ffa65c042b72302433c25d7a230c322caba0901587534b6551091d")), + singletonList(null), + singletonList( + LogTopic.fromHexString( + "0x000000000000000000000000244a53ab66ea8901c25efc48c8ab84662643cc74"))); + } + + @Test + public void whenTopicsParameterContainsArraysFilterContainsListOfSingletonLists() + throws JsonProcessingException { + final List> topics = + Lists.newArrayList( + singletonList("0xce8688f853ffa65c042b72302433c25d7a230c322caba0901587534b6551091d"), + null, + singletonList("0x000000000000000000000000244a53ab66ea8901c25efc48c8ab84662643cc74")); + + final FilterParameter filter = createFilterWithTopics(topics); + + assertThat(filter.getTopics()) + .containsExactly( + singletonList( + LogTopic.fromHexString( + "0xce8688f853ffa65c042b72302433c25d7a230c322caba0901587534b6551091d")), + singletonList(null), + singletonList( + LogTopic.fromHexString( + "0x000000000000000000000000244a53ab66ea8901c25efc48c8ab84662643cc74"))); + } + + @Test + public void whenTopicArrayContainsNullFilterContainsSingletonListOfAllTopics() + throws JsonProcessingException { + final List> topics = + Lists.newArrayList( + singletonList("0xce8688f853ffa65c042b72302433c25d7a230c322caba0901587534b6551091d"), + null, + singletonList("0x000000000000000000000000244a53ab66ea8901c25efc48c8ab84662643cc74")); + final FilterParameter filter = createFilterWithTopics(topics); + + assertThat(filter.getTopics()) + .containsExactly( + singletonList( + LogTopic.fromHexString( + "0xce8688f853ffa65c042b72302433c25d7a230c322caba0901587534b6551091d")), + singletonList(null), + singletonList( + LogTopic.fromHexString( + "0x000000000000000000000000244a53ab66ea8901c25efc48c8ab84662643cc74"))); + } + + @Test + public void emptyListDecodesCorrectly() throws JsonProcessingException { + final List topics = emptyList(); + final FilterParameter filter = createFilterWithTopics(topics); + + assertThat(filter.getTopics().size()).isZero(); + } + + @Test + public void emptyListAsSubTopicDecodesCorrectly() throws JsonProcessingException { + final List> topics = + Lists.newArrayList( + singletonList("0xce8688f853ffa65c042b72302433c25d7a230c322caba0901587534b6551091d"), + emptyList()); + final FilterParameter filter = createFilterWithTopics(topics); + assertThat(filter.getTopics()) + .containsExactly( + singletonList( + LogTopic.fromHexString( + "0xce8688f853ffa65c042b72302433c25d7a230c322caba0901587534b6551091d")), + emptyList()); + } + + private FilterParameter createFilterWithTopics(final T inputTopics) + throws JsonProcessingException { + final Map payload = new HashMap<>(); + payload.put("topics", inputTopics); + + final String json = new ObjectMapper().writeValueAsString(payload); + return new ObjectMapper().readValue(json, FilterParameter.class); + } + private FilterParameter filterParameterWithAddresses(final String... addresses) { - return new FilterParameter("latest", "latest", Arrays.asList(addresses), null, null); + return new FilterParameter( + "latest", + "latest", + Arrays.stream(addresses).map(Address::fromHexString).collect(toUnmodifiableList()), + null, + null); } private FilterParameter filterParameterWithAddressAndSingleListOfTopics( @@ -135,17 +243,19 @@ private FilterParameter filterParameterWithAddressAndSingleListOfTopics( return new FilterParameter( "latest", "latest", - Arrays.asList(address), - new TopicsParameter(Collections.singletonList(Arrays.asList(topics))), + singletonList(Address.fromHexString(address)), + singletonList( + Arrays.stream(topics).map(LogTopic::fromHexString).collect(toUnmodifiableList())), null); } private FilterParameter filterParameterWithAddressAndMultipleListOfTopics( final String address, final String... topics) { - List topicsList = Arrays.asList(topics); - List> topicsListList = Arrays.asList(topicsList, topicsList); + List topicsList = + Arrays.stream(topics).map(LogTopic::fromHexString).collect(toUnmodifiableList()); + List> topicsListList = Arrays.asList(topicsList, topicsList); return new FilterParameter( - "latest", "latest", Arrays.asList(address), new TopicsParameter(topicsListList), null); + "latest", "latest", singletonList(Address.fromHexString(address)), topicsListList, null); } private JsonRpcRequest readJsonAsJsonRpcRequest(final String jsonWithSingleAddress) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java index 3b0463e1c05..cb3663c6c9f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java @@ -24,14 +24,14 @@ import org.hyperledger.besu.enclave.Enclave; import org.hyperledger.besu.enclave.types.ReceiveRequest; import org.hyperledger.besu.enclave.types.ReceiveResponse; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionGroupResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionLegacyResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.PrivacyParameters; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java index 3d928bbce10..f44fc1bdded 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java @@ -29,9 +29,9 @@ import org.hyperledger.besu.enclave.types.ReceiveResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionReceiptResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.TransactionLocation; import org.hyperledger.besu.ethereum.core.Address; @@ -164,7 +164,7 @@ public void setUp() { public void returnReceiptIfTransactionExists() { final PrivGetTransactionReceipt privGetTransactionReceipt = new PrivGetTransactionReceipt(blockchainQueries, enclave, parameters, privacyParameters); - final Object[] params = new Object[] {transaction.hash()}; + final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequest request = new JsonRpcRequest("1", "priv_getTransactionReceipt", params); final JsonRpcSuccessResponse response = @@ -183,7 +183,7 @@ public void enclavePayloadNotFoundResultsInSuccessButNullResponse() { final PrivGetTransactionReceipt privGetTransactionReceipt = new PrivGetTransactionReceipt( blockchainQueries, failingEnclave, parameters, privacyParameters); - final Object[] params = new Object[] {transaction.hash()}; + final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequest request = new JsonRpcRequest("1", "priv_getTransactionReceipt", params); final JsonRpcSuccessResponse response = @@ -200,7 +200,7 @@ public void markerTransactionNotAvailableResultsInNullResponse() { final PrivGetTransactionReceipt privGetTransactionReceipt = new PrivGetTransactionReceipt(blockchainQueries, enclave, parameters, privacyParameters); - final Object[] params = new Object[] {transaction.hash()}; + final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequest request = new JsonRpcRequest("1", "priv_getTransactionReceipt", params); final JsonRpcSuccessResponse response = @@ -216,7 +216,7 @@ public void enclaveConnectionIssueThrowsRuntimeException() { final PrivGetTransactionReceipt privGetTransactionReceipt = new PrivGetTransactionReceipt( blockchainQueries, failingEnclave, parameters, privacyParameters); - final Object[] params = new Object[] {transaction.hash()}; + final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequest request = new JsonRpcRequest("1", "priv_getTransactionReceipt", params); final Throwable t = catchThrowable(() -> privGetTransactionReceipt.response(request)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java index aa1470ae651..ffb139dc9cd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java @@ -92,8 +92,8 @@ public class TransactionTracerTest { public void setUp() throws Exception { transactionTracer = new TransactionTracer(new BlockReplay(protocolSchedule, blockchain, worldStateArchive)); - when(transaction.hash()).thenReturn(transactionHash); - when(otherTransaction.hash()).thenReturn(otherTransactionHash); + when(transaction.getHash()).thenReturn(transactionHash); + when(otherTransaction.getHash()).thenReturn(otherTransactionHash); when(blockHeader.getNumber()).thenReturn(12L); when(blockHeader.getHash()).thenReturn(blockHash); when(blockHeader.getParentHash()).thenReturn(previousBlockHash); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilderTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilderTest.java index c2fb16fa91c..ac846fade60 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilderTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/SubscriptionBuilderTest.java @@ -17,12 +17,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.blockheaders.NewBlockHeadersSubscription; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.logs.LogsSubscription; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscribeRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.syncing.SyncingSubscription; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; import java.util.function.Function; @@ -41,11 +41,11 @@ public void before() { @Test public void shouldBuildLogsSubscriptionWhenSubscribeRequestTypeIsLogs() { - final FilterParameter filterParameter = filterParameter(); + final LogsQuery logsQuery = logsQuery(); final SubscribeRequest subscribeRequest = - new SubscribeRequest(SubscriptionType.LOGS, filterParameter, null, CONNECTION_ID); + new SubscribeRequest(SubscriptionType.LOGS, logsQuery, null, CONNECTION_ID); final LogsSubscription expectedSubscription = - new LogsSubscription(1L, CONNECTION_ID, filterParameter); + new LogsSubscription(1L, CONNECTION_ID, logsQuery); final Subscription builtSubscription = subscriptionBuilder.build(1L, CONNECTION_ID, subscribeRequest); @@ -96,7 +96,7 @@ public void shouldBuildSubscriptionWhenSubscribeRequestTypeIsSyncing() { public void shouldReturnLogsSubscriptionWhenMappingLogsSubscription() { final Function function = subscriptionBuilder.mapToSubscriptionClass(LogsSubscription.class); - final Subscription subscription = new LogsSubscription(1L, CONNECTION_ID, filterParameter()); + final Subscription subscription = new LogsSubscription(1L, CONNECTION_ID, logsQuery()); assertThat(function.apply(subscription)).isInstanceOf(LogsSubscription.class); } @@ -147,7 +147,7 @@ public void shouldThrownIllegalArgumentExceptionWhenMappingWrongSubscriptionType "NewBlockHeadersSubscription instance can't be mapped to type LogsSubscription"); } - private FilterParameter filterParameter() { - return new FilterParameter(null, null, null, null, null); + private LogsQuery logsQuery() { + return new LogsQuery(null, null); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java index 7a73aaf06c1..681b8b50cfd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java @@ -23,13 +23,13 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.SECP256K1.KeyPair; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.JsonRpcResult; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -174,7 +174,8 @@ private void simulateAddingBlockOnCanonicalChain() { final BlockBody blockBody = new BlockBody(Collections.emptyList(), Collections.emptyList()); final Block testBlock = new Block(blockHeader, blockBody); newBlockHeadersSubscriptionService.onBlockAdded( - BlockAddedEvent.createForHeadAdvancement(testBlock), blockchainQueries.getBlockchain()); + BlockAddedEvent.createForHeadAdvancement(testBlock, Collections.emptyList()), + blockchainQueries.getBlockchain()); verify(blockchainQueries, times(1)).getBlockchain(); } @@ -199,7 +200,7 @@ private List transactionsWithMetadata() { private List transactionsWithHashOnly() { final List hashes = new ArrayList<>(); for (final TransactionWithMetadata transactionWithMetadata : transactionsWithMetadata()) { - hashes.add(transactionWithMetadata.getTransaction().hash()); + hashes.add(transactionWithMetadata.getTransaction().getHash()); } return hashes; } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index 9301454b9f3..25503ba2dde 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -14,249 +14,354 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.logs; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.refEq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.hyperledger.besu.crypto.SECP256K1.KeyPair; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogResult; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; -import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; -import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockDataGenerator; +import org.hyperledger.besu.ethereum.core.BlockDataGenerator.BlockOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; +import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider; import org.hyperledger.besu.ethereum.core.Log; +import org.hyperledger.besu.ethereum.core.LogTopic; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; -import org.hyperledger.besu.ethereum.core.TransactionTestFixture; -import org.hyperledger.besu.util.bytes.BytesValue; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Optional; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class LogsSubscriptionServiceTest { - private final KeyPair keyPair = KeyPair.generate(); - private final BlockHeaderTestFixture blockHeaderTestFixture = new BlockHeaderTestFixture(); - private final TransactionTestFixture txTestFixture = new TransactionTestFixture(); + private final BlockDataGenerator gen = new BlockDataGenerator(1); + private final MutableBlockchain blockchain = + InMemoryStorageProvider.createInMemoryBlockchain(gen.genesisBlock()); private LogsSubscriptionService logsSubscriptionService; + private final AtomicLong nextSubscriptionId = new AtomicLong(); @Mock private SubscriptionManager subscriptionManager; - @Mock private BlockchainQueries blockchainQueries; - @Mock private Blockchain blockchain; @Before public void before() { - logsSubscriptionService = new LogsSubscriptionService(subscriptionManager, blockchainQueries); + logsSubscriptionService = new LogsSubscriptionService(subscriptionManager); + blockchain.observeBlockAdded(logsSubscriptionService); } @Test - public void shouldSendLogMessageWhenBlockAddedEventHasAddedTransactionsMatchingSubscription() { - final Address address = Address.fromHexString("0x0"); - final LogsSubscription subscription = createSubscription(address); - final Transaction transaction = createTransaction(); - final Log log = createLog(address); - final LogResult expectedLogResult = createLogResult(transaction, log, false); + public void singleMatchingLogEvent() { + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + final Block block = blockWithReceipts.getBlock(); + final List receipts = blockWithReceipts.getReceipts(); - logsSubscriptionService.onBlockAdded(createBlockAddedEvent(transaction, null), blockchain); + final int txIndex = 1; + final int logIndex = 1; + final Log targetLog = receipts.get(txIndex).getLogs().get(logIndex); - verify(subscriptionManager) - .sendMessage( - ArgumentMatchers.eq(subscription.getSubscriptionId()), refEq(expectedLogResult)); - } + final LogsSubscription subscription = createSubscription(targetLog.getLogger()); + registerSubscriptions(subscription); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); - @Test - public void shouldSendLogMessageWhenBlockAddedEventHasRemovedTransactionsMatchingSubscription() { - final Address address = Address.fromHexString("0x0"); - final LogsSubscription subscription = createSubscription(address); - final Transaction transaction = createTransaction(); - final Log log = createLog(address); - final LogResult expectedLogResult = createLogResult(transaction, log, true); + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager).sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); - logsSubscriptionService.onBlockAdded(createBlockAddedEvent(null, transaction), blockchain); + final List logResults = captor.getAllValues(); - verify(subscriptionManager) - .sendMessage( - ArgumentMatchers.eq(subscription.getSubscriptionId()), refEq(expectedLogResult)); + assertThat(logResults).hasSize(1); + final LogResult result = logResults.get(0); + assertLogResultMatches(result, block, receipts, txIndex, logIndex, false); } @Test - public void shouldSendMessageForAllLogsMatchingSubscription() { - final Address address = Address.fromHexString("0x0"); - final Log log = createLog(address); - final LogsSubscription subscription = createSubscription(address); - final List addedTransactions = createTransactionsWithLog(log); - final List removedTransactions = createTransactionsWithLog(log); + public void singleMatchingLogEmittedThenRemovedInReorg() { + // Create block that emits an event + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + final Block block = blockWithReceipts.getBlock(); + final List receipts = blockWithReceipts.getReceipts(); + + final int txIndex = 1; + final int logIndex = 1; + final Log targetLog = receipts.get(txIndex).getLogs().get(logIndex); + + final LogsSubscription subscription = createSubscription(targetLog.getLogger()); + registerSubscriptions(subscription); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); + + // Cause a reorg that removes the block which emitted an event + BlockHeader parentHeader = blockchain.getGenesisBlock().getHeader(); + while (!blockchain.getChainHeadHash().equals(parentHeader.getHash())) { + final BlockWithReceipts newBlock = generateBlock(parentHeader, 2, 0, 0); + parentHeader = newBlock.getBlock().getHeader(); + blockchain.appendBlock(newBlock.getBlock(), newBlock.getReceipts()); + } - logsSubscriptionService.onBlockAdded( - createBlockAddedEvent(addedTransactions, removedTransactions), blockchain); + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(2)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); - final int totalOfLogs = addedTransactions.size() + removedTransactions.size(); + final List logResults = captor.getAllValues(); - verify(subscriptionManager, times(totalOfLogs)) - .sendMessage(ArgumentMatchers.eq(subscription.getSubscriptionId()), any()); + assertThat(logResults).hasSize(2); + final LogResult firstLog = logResults.get(0); + assertLogResultMatches(firstLog, block, receipts, txIndex, logIndex, false); + final LogResult secondLog = logResults.get(1); + assertLogResultMatches(secondLog, block, receipts, txIndex, logIndex, true); } @Test - public void shouldSendLogMessageToAllMatchingSubscriptions() { - final Address address = Address.fromHexString("0x0"); - final List subscriptions = createSubscriptions(address); - final Transaction transaction = createTransaction(); - final Log log = createLog(address); - final LogResult expectedLogResult = createLogResult(transaction, log, false); - - logsSubscriptionService.onBlockAdded(createBlockAddedEvent(transaction, null), blockchain); + public void singleMatchingLogEmittedThenMovedInReorg() { + // Create block that emits an event + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + final Block block = blockWithReceipts.getBlock(); + final List receipts = blockWithReceipts.getReceipts(); + + final int txIndex = 1; + final int logIndex = 1; + final Log targetLog = receipts.get(txIndex).getLogs().get(logIndex); + + final LogsSubscription subscription = createSubscription(targetLog.getLogger()); + registerSubscriptions(subscription); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); + + // Cause a reorg that removes the block which emitted an event + BlockHeader parentHeader = blockchain.getGenesisBlock().getHeader(); + while (!blockchain.getChainHeadHash().equals(parentHeader.getHash())) { + final BlockWithReceipts newBlock = generateBlock(parentHeader, 2, 0, 0); + parentHeader = newBlock.getBlock().getHeader(); + blockchain.appendBlock(newBlock.getBlock(), newBlock.getReceipts()); + } - verify(subscriptionManager, times(subscriptions.size())) - .sendMessage(any(), refEq(expectedLogResult)); + // Now add another block that re-emits the target log + final BlockWithReceipts newBlockWithLog = + generateBlock(1, () -> Collections.singletonList(targetLog)); + blockchain.appendBlock(newBlockWithLog.getBlock(), newBlockWithLog.getReceipts()); + // Sanity check + assertThat(blockchain.getChainHeadHash()).isEqualTo(newBlockWithLog.getBlock().getHash()); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(3)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); + + final List logResults = captor.getAllValues(); + + assertThat(logResults).hasSize(3); + final LogResult originalLog = logResults.get(0); + assertLogResultMatches(originalLog, block, receipts, txIndex, logIndex, false); + final LogResult removedLog = logResults.get(1); + assertLogResultMatches(removedLog, block, receipts, txIndex, logIndex, true); + final LogResult updatedLog = logResults.get(2); + assertLogResultMatches( + updatedLog, newBlockWithLog.getBlock(), newBlockWithLog.getReceipts(), 0, 0, false); } @Test - public void shouldNotSendLogMessageWhenBlockAddedEventHasNoTransactions() { - final Address address = Address.fromHexString("0x0"); - createSubscription(address); + public void multipleMatchingLogsEmitted() { + final Log targetLog = gen.log(); + final Log otherLog = gen.log(); + final List logs = Arrays.asList(targetLog, otherLog); + + final LogsSubscription subscription = createSubscription(targetLog.getLogger()); + registerSubscriptions(subscription); + + // Generate blocks with multiple logs matching subscription + final int txCount = 2; + final List targetBlocks = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + final BlockWithReceipts blockWithReceipts = generateBlock(txCount, () -> logs); + targetBlocks.add(blockWithReceipts); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); + + // Add another block with unrelated logs + final BlockWithReceipts otherBlock = generateBlock(txCount, 2, 2); + blockchain.appendBlock(otherBlock.getBlock(), otherBlock.getReceipts()); + } - logsSubscriptionService.onBlockAdded( - createBlockAddedEvent(Collections.emptyList(), Collections.emptyList()), blockchain); + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(targetBlocks.size() * txCount)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); + final List logResults = captor.getAllValues(); + + // Verify all logs are emitted + assertThat(logResults).hasSize(targetBlocks.size() * txCount); + for (int i = 0; i < targetBlocks.size(); i++) { + final BlockWithReceipts targetBlock = targetBlocks.get(i); + for (int j = 0; j < txCount; j++) { + final int resultIndex = i * txCount + j; + assertLogResultMatches( + logResults.get(resultIndex), + targetBlock.getBlock(), + targetBlock.getReceipts(), + j, + 0, + false); + } + } + } - verify(subscriptionManager).subscriptionsOfType(any(), any()); - verify(subscriptionManager, times(0)).sendMessage(any(), any()); + @Test + public void multipleSubscriptionsForSingleMatchingLog() { + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + final Block block = blockWithReceipts.getBlock(); + final List receipts = blockWithReceipts.getReceipts(); + + final int txIndex = 1; + final int logIndex = 1; + final Log targetLog = receipts.get(txIndex).getLogs().get(logIndex); + + final List subscriptions = + Stream.generate(() -> createSubscription(targetLog.getLogger())) + .limit(3) + .collect(Collectors.toList()); + registerSubscriptions(subscriptions); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); + + for (LogsSubscription subscription : subscriptions) { + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); + + final List logResults = captor.getAllValues(); + + assertThat(logResults).hasSize(1); + final LogResult result = logResults.get(0); + assertLogResultMatches(result, block, receipts, txIndex, logIndex, false); + } } @Test - public void shouldNotSendLogMessageWhenLogsDoNotMatchAnySubscription() { - createSubscription(Address.fromHexString("0x0")); - final Transaction transaction = createTransaction(); - final Log log = createLog(Address.fromHexString("0x1")); - createLogResult(transaction, log, false); + public void noLogsEmitted() { + final Address address = Address.fromHexString("0x0"); + final LogsSubscription subscription = createSubscription(address); + registerSubscriptions(subscription); - logsSubscriptionService.onBlockAdded(createBlockAddedEvent(transaction, null), blockchain); + final BlockWithReceipts blockWithReceipts = generateBlock(2, 0, 0); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); - verify(subscriptionManager).subscriptionsOfType(any(), any()); - verify(subscriptionManager, times(0)).sendMessage(any(), any()); + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(0)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); } - private Transaction createTransaction() { - return txTestFixture.createTransaction(keyPair); + @Test + public void noMatchingLogsEmitted() { + final Address address = Address.fromHexString("0x0"); + final LogsSubscription subscription = createSubscription(address); + registerSubscriptions(subscription); + + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(0)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); } - private Log createLog(final Address address) { - return new Log(address, BytesValue.EMPTY, Collections.emptyList()); + private void assertLogResultMatches( + final LogResult result, + final Block block, + final List receipts, + final int txIndex, + final int logIndex, + final boolean isRemoved) { + final Transaction expectedTransaction = block.getBody().getTransactions().get(txIndex); + final Log expectedLog = receipts.get(txIndex).getLogs().get(logIndex); + + assertThat(result.getLogIndex()).isEqualTo(Quantity.create(logIndex)); + assertThat(result.getTransactionIndex()).isEqualTo(Quantity.create(txIndex)); + assertThat(result.getBlockNumber()).isEqualTo(Quantity.create(block.getHeader().getNumber())); + assertThat(result.getBlockHash()).isEqualTo(block.getHash().toString()); + assertThat(result.getTransactionHash()).isEqualTo(expectedTransaction.getHash().toString()); + assertThat(result.getAddress()).isEqualTo(expectedLog.getLogger().toString()); + assertThat(result.getData()).isEqualTo(expectedLog.getData().toString()); + assertThat(result.getTopics()) + .isEqualTo( + expectedLog.getTopics().stream().map(LogTopic::toString).collect(Collectors.toList())); + assertThat(result.isRemoved()).isEqualTo(isRemoved); } - private LogsSubscription createSubscription(final Address address) { - final FilterParameter filterParameter = - new FilterParameter(null, null, Lists.newArrayList(address.toString()), null, null); - final LogsSubscription logsSubscription = new LogsSubscription(1L, "conn", filterParameter); - when(subscriptionManager.subscriptionsOfType(any(), any())) - .thenReturn(Lists.newArrayList(logsSubscription)); - return logsSubscription; + private BlockWithReceipts generateBlock( + final int txCount, final int logsPerTx, final int topicsPerLog) { + final BlockHeader parent = blockchain.getChainHeadHeader(); + return generateBlock(parent, txCount, () -> gen.logs(logsPerTx, topicsPerLog)); } - private List createSubscriptions(final Address address) { - final List subscriptions = new ArrayList<>(); - for (long i = 0; i < 3; i++) { - final FilterParameter filterParameter = - new FilterParameter(null, null, Lists.newArrayList(address.toString()), null, null); - subscriptions.add(new LogsSubscription(i, "conn", filterParameter)); - } - when(subscriptionManager.subscriptionsOfType(any(), any())) - .thenReturn(Lists.newArrayList(subscriptions)); - return subscriptions; + private BlockWithReceipts generateBlock( + final BlockHeader parentHeader, + final int txCount, + final int logsPerTx, + final int topicsPerLog) { + return generateBlock(parentHeader, txCount, () -> gen.logs(logsPerTx, topicsPerLog)); } - private LogResult createLogResult( - final Transaction transaction, final Log log, final boolean removed) { - final TransactionReceiptWithMetadata txReceiptWithMetadata = - createTransactionWithLog(transaction, log); - final LogWithMetadata logWithMetadata = createLogWithMetadata(txReceiptWithMetadata, removed); - return new LogResult(logWithMetadata); + private BlockWithReceipts generateBlock( + final int txCount, final Supplier> logsSupplier) { + final BlockHeader parent = blockchain.getChainHeadHeader(); + return generateBlock(parent, txCount, logsSupplier); } - private TransactionReceiptWithMetadata createTransactionWithLog( - final Transaction transaction, final Log log) { - final BlockHeader blockHeader = blockHeaderTestFixture.buildHeader(); - final TransactionReceipt transactionReceipt = - new TransactionReceipt(Hash.ZERO, 1L, Lists.newArrayList(log), Optional.empty()); - final TransactionReceiptWithMetadata transactionReceiptWithMetadata = - TransactionReceiptWithMetadata.create( - transactionReceipt, - transaction, - transaction.hash(), - 0, - 1L, - blockHeader.getHash(), - blockHeader.getNumber()); + private BlockWithReceipts generateBlock( + final BlockHeader parentHeader, final int txCount, final Supplier> logsSupplier) { + final List receipts = new ArrayList<>(); + final List logs = new ArrayList<>(); + final BlockOptions blockOptions = BlockOptions.create(); + for (int i = 0; i < txCount; i++) { + final Transaction tx = gen.transaction(); + final TransactionReceipt receipt = gen.receipt(logsSupplier.get()); + + receipts.add(receipt); + receipt.getLogs().forEach(logs::add); + blockOptions.addTransaction(tx); + } - when(blockchainQueries.transactionReceiptByTransactionHash(eq(transaction.hash()))) - .thenReturn(Optional.of(transactionReceiptWithMetadata)); + blockOptions.setParentHash(parentHeader.getHash()); + blockOptions.setBlockNumber(parentHeader.getNumber() + 1L); + final Block block = gen.block(blockOptions); - return transactionReceiptWithMetadata; + return new BlockWithReceipts(block, receipts); } - private BlockAddedEvent createBlockAddedEvent( - final Transaction addedTransaction, final Transaction removedTransaction) { - final Block block = mock(Block.class); - return BlockAddedEvent.createForChainReorg( - block, - addedTransaction != null ? Lists.newArrayList(addedTransaction) : Collections.emptyList(), - removedTransaction != null - ? Lists.newArrayList(removedTransaction) - : Collections.emptyList()); + private LogsSubscription createSubscription(final Address address) { + return createSubscription(Arrays.asList(address), Collections.emptyList()); } - private BlockAddedEvent createBlockAddedEvent( - final List addedTransactions, final List removedTransactions) { - final Block block = mock(Block.class); - return BlockAddedEvent.createForChainReorg( - block, - addedTransactions != null ? Lists.newArrayList(addedTransactions) : Collections.emptyList(), - removedTransactions != null - ? Lists.newArrayList(removedTransactions) - : Collections.emptyList()); + private LogsSubscription createSubscription( + final List
addresses, final List> logTopics) { + + return new LogsSubscription( + nextSubscriptionId.incrementAndGet(), "conn", new LogsQuery(addresses, logTopics)); } - private List createTransactionsWithLog(final Log log) { - final ArrayList transactions = - Lists.newArrayList(createTransaction(), createTransaction(), createTransaction()); - transactions.forEach(tx -> createTransactionWithLog(tx, log)); - return transactions; + private void registerSubscriptions(final LogsSubscription... subscriptions) { + registerSubscriptions(Arrays.asList(subscriptions)); } - private LogWithMetadata createLogWithMetadata( - final TransactionReceiptWithMetadata transactionReceiptWithMetadata, final boolean removed) { - return new LogWithMetadata( - 0, - transactionReceiptWithMetadata.getBlockNumber(), - transactionReceiptWithMetadata.getBlockHash(), - transactionReceiptWithMetadata.getTransactionHash(), - transactionReceiptWithMetadata.getTransactionIndex(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(0).getLogger(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(0).getData(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(0).getTopics(), - removed); + private void registerSubscriptions(final List subscriptions) { + when(subscriptionManager.subscriptionsOfType(any(), any())) + .thenReturn(Lists.newArrayList(subscriptions)); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionServiceTest.java index 4779633339d..d9ad8212fe2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDroppedSubscriptionServiceTest.java @@ -97,7 +97,7 @@ private Map messages(final Hash result, final long... subscriptionId private Transaction transaction(final Hash hash) { final Transaction tx = mock(Transaction.class); - when(tx.hash()).thenReturn(hash); + when(tx.getHash()).thenReturn(hash); return tx; } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapperTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapperTest.java index f45d9dd5b6a..a56b5d47385 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapperTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/request/SubscriptionRequestMapperTest.java @@ -14,21 +14,25 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.toUnmodifiableList; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.both; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; -import org.hyperledger.besu.ethereum.api.TopicsParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.methods.WebSocketRpcRequest; +import org.hyperledger.besu.ethereum.api.query.LogsQuery; +import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.LogTopic; -import java.util.Arrays; -import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; import io.vertx.core.json.Json; import org.junit.Before; @@ -158,15 +162,14 @@ public void mapRequestWithSingleAddress() { parseWebSocketRpcRequest( "{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"logs\", {\"address\": \"0x8320fe7702b96808f7bbc0d4a888ed1468216cfd\"}]}"); - final FilterParameter expectedFilterParam = - new FilterParameter( - null, + final SubscribeRequest expectedSubscribeRequest = + new SubscribeRequest( + SubscriptionType.LOGS, + new LogsQuery( + singletonList(Address.fromHexString("0x8320fe7702b96808f7bbc0d4a888ed1468216cfd")), + emptyList()), null, - Arrays.asList("0x8320fe7702b96808f7bbc0d4a888ed1468216cfd"), - new TopicsParameter(Collections.emptyList()), null); - final SubscribeRequest expectedSubscribeRequest = - new SubscribeRequest(SubscriptionType.LOGS, expectedFilterParam, null, null); final SubscribeRequest subscribeRequest = mapper.mapSubscribeRequest(jsonRpcRequest); @@ -180,20 +183,21 @@ public void mapRequestWithMultipleAddresses() { parseWebSocketRpcRequest( "{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"logs\", {\"address\": [\"0x8320fe7702b96808f7bbc0d4a888ed1468216cfd\", \"0xf17f52151EbEF6C7334FAD080c5704D77216b732\"], \"topics\": [\"0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab902\"]}]}"); - final FilterParameter expectedFilterParam = - new FilterParameter( - null, + final SubscribeRequest expectedSubscribeRequest = + new SubscribeRequest( + SubscriptionType.LOGS, + new LogsQuery( + Stream.of( + "0x8320fe7702b96808f7bbc0d4a888ed1468216cfd", + "0xf17f52151EbEF6C7334FAD080c5704D77216b732") + .map(Address::fromHexString) + .collect(toUnmodifiableList()), + singletonList( + singletonList( + LogTopic.fromHexString( + "0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab902")))), null, - Arrays.asList( - "0x8320fe7702b96808f7bbc0d4a888ed1468216cfd", - "0xf17f52151EbEF6C7334FAD080c5704D77216b732"), - new TopicsParameter( - Arrays.asList( - Arrays.asList( - "0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab902"))), null); - final SubscribeRequest expectedSubscribeRequest = - new SubscribeRequest(SubscriptionType.LOGS, expectedFilterParam, null, null); final SubscribeRequest subscribeRequest = mapper.mapSubscribeRequest(jsonRpcRequest); @@ -207,19 +211,20 @@ public void mapRequestWithMultipleTopics() { parseWebSocketRpcRequest( "{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"logs\", {\"address\": \"0x8320fe7702b96808f7bbc0d4a888ed1468216cfd\", \"topics\": [\"0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab902\", \"0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab901\"]}]}"); - final FilterParameter expectedFilterParam = - new FilterParameter( - null, + final SubscribeRequest expectedSubscribeRequest = + new SubscribeRequest( + SubscriptionType.LOGS, + new LogsQuery( + singletonList(Address.fromHexString("0x8320fe7702b96808f7bbc0d4a888ed1468216cfd")), + List.of( + singletonList( + LogTopic.fromHexString( + "0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab902")), + singletonList( + LogTopic.fromHexString( + "0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab901")))), null, - Arrays.asList("0x8320fe7702b96808f7bbc0d4a888ed1468216cfd"), - new TopicsParameter( - Arrays.asList( - Arrays.asList( - "0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab902", - "0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab901"))), null); - final SubscribeRequest expectedSubscribeRequest = - new SubscribeRequest(SubscriptionType.LOGS, expectedFilterParam, null, null); final SubscribeRequest subscribeRequest = mapper.mapSubscribeRequest(jsonRpcRequest); @@ -233,15 +238,14 @@ public void mapRequestToLogsWithoutTopics() { parseWebSocketRpcRequest( "{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"logs\", {\"address\": \"0x8320fe7702b96808f7bbc0d4a888ed1468216cfd\"}]}"); - final FilterParameter expectedFilterParam = - new FilterParameter( - null, + final SubscribeRequest expectedSubscribeRequest = + new SubscribeRequest( + SubscriptionType.LOGS, + new LogsQuery( + singletonList(Address.fromHexString("0x8320fe7702b96808f7bbc0d4a888ed1468216cfd")), + emptyList()), null, - Arrays.asList("0x8320fe7702b96808f7bbc0d4a888ed1468216cfd"), - new TopicsParameter(Collections.emptyList()), null); - final SubscribeRequest expectedSubscribeRequest = - new SubscribeRequest(SubscriptionType.LOGS, expectedFilterParam, null, null); final SubscribeRequest subscribeRequest = mapper.mapSubscribeRequest(jsonRpcRequest); @@ -257,8 +261,8 @@ public void mapRequestToLogsWithInvalidTopicInFilter() { thrown.expect(InvalidSubscriptionRequestException.class); thrown.expectCause( - both(hasMessage(equalTo("Invalid odd-length hex binary representation 0x1"))) - .and(instanceOf(IllegalArgumentException.class))); + both(hasMessage(equalTo("Invalid json rpc parameter at index 1"))) + .and(instanceOf(InvalidJsonRpcParameters.class))); mapper.mapSubscribeRequest(jsonRpcRequest); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionServiceTest.java index 13987413ca1..f1afc1d7170 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/syncing/SyncingSubscriptionServiceTest.java @@ -14,12 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.syncing; -import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atMostOnce; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -27,12 +24,14 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.SyncingResult; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType; -import org.hyperledger.besu.ethereum.core.SyncStatus; +import org.hyperledger.besu.ethereum.core.DefaultSyncStatus; import org.hyperledger.besu.ethereum.core.Synchronizer; +import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.plugin.services.BesuEvents.SyncStatusListener; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.function.Consumer; import org.junit.Before; @@ -54,7 +53,7 @@ public class SyncingSubscriptionServiceTest { public void before() { final ArgumentCaptor captor = ArgumentCaptor.forClass(SyncStatusListener.class); - when(synchronizer.observeSyncStatus(captor.capture())).thenReturn(1L); + when(synchronizer.subscribeSyncStatus(captor.capture())).thenReturn(1L); new SyncingSubscriptionService(subscriptionManager, synchronizer); syncStatusListener = captor.getValue(); } @@ -64,8 +63,8 @@ public void shouldSendSyncStatusWhenReceiveSyncStatus() { final SyncingSubscription subscription = new SyncingSubscription(9L, "conn", SubscriptionType.SYNCING); final List subscriptions = Collections.singletonList(subscription); - final SyncStatus syncStatus = new SyncStatus(0L, 1L, 3L); - final SyncingResult expectedSyncingResult = new SyncingResult(syncStatus); + final Optional syncStatus = Optional.of(new DefaultSyncStatus(0L, 1L, 3L)); + final JsonRpcResult expectedSyncingResult = new SyncingResult(syncStatus.get()); doAnswer( invocation -> { @@ -84,11 +83,12 @@ public void shouldSendSyncStatusWhenReceiveSyncStatus() { } @Test - public void shouldSendNotSyncingStatusWhenReceiveSyncStatusAtHead() { + public void shouldSendNotSyncingResultWhenReceiveNonSyncingStatus() { final SyncingSubscription subscription = new SyncingSubscription(9L, "conn", SubscriptionType.SYNCING); final List subscriptions = Collections.singletonList(subscription); - final SyncStatus syncStatus = new SyncStatus(0L, 1L, 1L); + final Optional syncStatus = Optional.empty(); + final JsonRpcResult expectedSyncingResult = new NotSynchronisingResult(); doAnswer( invocation -> { @@ -102,93 +102,7 @@ public void shouldSendNotSyncingStatusWhenReceiveSyncStatusAtHead() { syncStatusListener.onSyncStatusChanged(syncStatus); verify(subscriptionManager) - .sendMessage( - ArgumentMatchers.eq(subscription.getSubscriptionId()), - any(NotSynchronisingResult.class)); - } - - @Test - public void shouldNotRepeatOutOfSyncMessages() { - final SyncingSubscription subscription = - new SyncingSubscription(9L, "conn", SubscriptionType.SYNCING); - final List subscriptions = Collections.singletonList(subscription); - final SyncStatus syncStatus = new SyncStatus(0L, 1L, 3L); - final SyncingResult expectedSyncingResult = new SyncingResult(syncStatus); - - doAnswer( - invocation -> { - Consumer> consumer = invocation.getArgument(2); - consumer.accept(subscriptions); - return null; - }) - .when(subscriptionManager) - .notifySubscribersOnWorkerThread(any(), any(), any()); - - syncStatusListener.onSyncStatusChanged(syncStatus); - syncStatusListener.onSyncStatusChanged(syncStatus); - - verify(subscriptionManager, atMostOnce()) - .sendMessage( - ArgumentMatchers.eq(subscription.getSubscriptionId()), eq(expectedSyncingResult)); - } - - @Test - public void shouldNotRepeatInSyncMessages() { - final SyncingSubscription subscription = - new SyncingSubscription(9L, "conn", SubscriptionType.SYNCING); - final List subscriptions = Collections.singletonList(subscription); - final SyncStatus syncStatus = new SyncStatus(0L, 3L, 3L); - final SyncingResult expectedSyncingResult = new SyncingResult(syncStatus); - - doAnswer( - invocation -> { - Consumer> consumer = invocation.getArgument(2); - consumer.accept(subscriptions); - return null; - }) - .when(subscriptionManager) - .notifySubscribersOnWorkerThread(any(), any(), any()); - - syncStatusListener.onSyncStatusChanged(syncStatus); - syncStatusListener.onSyncStatusChanged(syncStatus); - - verify(subscriptionManager, atMostOnce()) .sendMessage( ArgumentMatchers.eq(subscription.getSubscriptionId()), eq(expectedSyncingResult)); } - - @Test - public void shouldOnlyReportSyncChange() { - final SyncingSubscription subscription = - new SyncingSubscription(9L, "conn", SubscriptionType.SYNCING); - final List subscriptions = Collections.singletonList(subscription); - - final SyncStatus inSyncStatus = new SyncStatus(0L, 3L, 3L); - final SyncStatus outOfSyncStatus = new SyncStatus(0L, 1L, 3L); - - doAnswer( - invocation -> { - Consumer> consumer = invocation.getArgument(2); - consumer.accept(subscriptions); - return null; - }) - .when(subscriptionManager) - .notifySubscribersOnWorkerThread(any(), any(), any()); - - syncStatusListener.onSyncStatusChanged(outOfSyncStatus); - syncStatusListener.onSyncStatusChanged(inSyncStatus); - syncStatusListener.onSyncStatusChanged(inSyncStatus); - syncStatusListener.onSyncStatusChanged(outOfSyncStatus); - syncStatusListener.onSyncStatusChanged(outOfSyncStatus); - syncStatusListener.onSyncStatusChanged(inSyncStatus); - syncStatusListener.onSyncStatusChanged(inSyncStatus); - - final var resultCaptor = ArgumentCaptor.forClass(JsonRpcResult.class); - final NotSynchronisingResult inSyncResult = new NotSynchronisingResult(); - final SyncingResult outOfSyncingResult = new SyncingResult(outOfSyncStatus); - - verify(subscriptionManager, times(4)).sendMessage(any(), resultCaptor.capture()); - assertThat(resultCaptor.getAllValues()) - .containsOnly(outOfSyncingResult, inSyncResult, outOfSyncingResult, inSyncResult); - } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/queries/BlockchainQueriesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java similarity index 98% rename from ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/queries/BlockchainQueriesTest.java rename to ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java index d7b610bf870..23e446b13ff 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/queries/BlockchainQueriesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java @@ -1,4 +1,5 @@ /* + * * Copyright ConsenSys AG. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with @@ -11,18 +12,15 @@ * specific language governing permissions and limitations under the License. * * SPDX-License-Identifier: Apache-2.0 + * */ -package org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries; +package org.hyperledger.besu.ethereum.api.query; import static com.google.common.base.Preconditions.checkArgument; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.core.InMemoryStorageProvider.createInMemoryBlockchain; import static org.hyperledger.besu.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive; -import org.hyperledger.besu.ethereum.api.BlockWithMetadata; -import org.hyperledger.besu.ethereum.api.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.LogsQuery; -import org.hyperledger.besu.ethereum.api.TransactionWithMetadata; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.Address; @@ -31,6 +29,7 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator.BlockOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.Wei; @@ -514,7 +513,7 @@ private void assertBlockMatchesResultWithTxHashes( for (int i = 0; i < result.getTransactions().size(); i++) { final Hash txResult = result.getTransactions().get(i); final Transaction actualTx = targetBlock.getBody().getTransactions().get(i); - assertThat(txResult).isEqualByComparingTo(actualTx.hash()); + assertThat(txResult).isEqualByComparingTo(actualTx.getHash()); } } diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getLogs_range.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getLogs_range.json new file mode 100644 index 00000000000..34416ddb867 --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/graphql/eth_getLogs_range.json @@ -0,0 +1,40 @@ +{ + "request": "{ logs( filter: { fromBlock:20, toBlock: 24, topics : [], addresses : []}) { index topics data account{address} transaction{hash block {number}} } }", + "response": { + "data": { + "logs": [ + { + "index": 0, + "topics": [ + "0x65c9ac8011e286e89d02a269890f41d67ca2cc597b2c76c7c69321ff492be580" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000002a", + "account": { + "address": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f" + }, + "transaction": { + "hash": "0x97a385bf570ced7821c6495b3877ddd2afd5c452f350f0d4876e98d9161389c6", + "block": { + "number": 23 + } + } + }, + { + "index": 0, + "topics": [], + "data": "0x000000000000000000000000000000000000000000000000000000000000002a", + "account": { + "address": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f" + }, + "transaction": { + "hash": "0x5ecd942096ab3f70c5bcc8f3a98f88c4ff0a3bd986417df9948eb1819db76d0e", + "block": { + "number": 24 + } + } + } + ] + } + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_nullParam.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_nullParam.json index 6c5e697ad75..c5ab156e9db 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_nullParam.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_nullParam.json @@ -4,26 +4,32 @@ "jsonrpc": "2.0", "method": "eth_getLogs", "params": [{ - "fromBlock": "0x17", - "toBlock": "0x17", + "fromBlock": "0x20", + "toBlock": "0x20", "address": [], - "topics": [["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null]] + "topics": [null, ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]] }] }, "response": { "jsonrpc": "2.0", "id": 406, - "result" : [{ - "logIndex" : "0x0", - "removed": false, - "blockNumber" : "0x17", - "blockHash" : "0x3c419f39b340a4c35cc27b8f7880b779dc1abb9814ad13a2a5a55b885cc8ec2d", - "transactionHash" : "0x97a385bf570ced7821c6495b3877ddd2afd5c452f350f0d4876e98d9161389c6", - "transactionIndex" : "0x0", - "address" : "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", - "data" : "0x000000000000000000000000000000000000000000000000000000000000002a", - "topics" : ["0x65c9ac8011e286e89d02a269890f41d67ca2cc597b2c76c7c69321ff492be580"] - }] + "result": [ + { + "logIndex": "0x0", + "removed": false, + "blockNumber": "0x20", + "blockHash": "0x71d59849ddd98543bdfbe8548f5eed559b07b8aaf196369f39134500eab68e53", + "transactionHash": "0xcef53f2311d7c80e9086d661e69ac11a5f3d081e28e02a9ba9b66749407ac310", + "transactionIndex": "0x0", + "address": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9000000000000000000000000000000000000000000000000000000000000002a", + "topics": [ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ] + } + ] }, "statusCode": 200 } \ No newline at end of file diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_toBlockOutOfRange.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_toBlockOutOfRange.json index fbbe13dcde1..22cbf3e71e1 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_toBlockOutOfRange.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_toBlockOutOfRange.json @@ -3,17 +3,40 @@ "id": 406, "jsonrpc": "2.0", "method": "eth_getLogs", - "params": [{ - "fromBlock": "0x17", - "toBlock": "0x21", - "address": [], - "topics": [["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null]] - }] + "params": [ + { + "fromBlock": "0x20", + "toBlock": "0x21", + "address": [], + "topics": [ + [ + "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + null + ] + ] + } + ] }, "response": { "jsonrpc": "2.0", "id": 406, - "result" : [] + "result": [ + { + "logIndex": "0x0", + "removed": false, + "blockNumber": "0x20", + "blockHash": "0x71d59849ddd98543bdfbe8548f5eed559b07b8aaf196369f39134500eab68e53", + "transactionHash": "0xcef53f2311d7c80e9086d661e69ac11a5f3d081e28e02a9ba9b66749407ac310", + "transactionIndex": "0x0", + "address": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9000000000000000000000000000000000000000000000000000000000000002a", + "topics": [ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ] + } + ] }, "statusCode": 200 } \ No newline at end of file diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java index ce0ba2a1c0a..9c58697c69d 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java @@ -27,13 +27,22 @@ import java.util.Optional; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public abstract class AbstractMinerExecutor< C, M extends BlockMiner>> { + private static final Logger LOG = LogManager.getLogger(); + + private final ExecutorService executorService = Executors.newCachedThreadPool(); protected final ProtocolContext protocolContext; - protected final ExecutorService executorService; protected final ProtocolSchedule protocolSchedule; protected final PendingTransactions pendingTransactions; protected final AbstractBlockScheduler blockScheduler; @@ -42,16 +51,16 @@ public abstract class AbstractMinerExecutor< protected volatile BytesValue extraData; protected volatile Wei minTransactionGasPrice; + private final AtomicBoolean stopped = new AtomicBoolean(false); + public AbstractMinerExecutor( final ProtocolContext protocolContext, - final ExecutorService executorService, final ProtocolSchedule protocolSchedule, final PendingTransactions pendingTransactions, final MiningParameters miningParams, final AbstractBlockScheduler blockScheduler, final Function gasLimitCalculator) { this.protocolContext = protocolContext; - this.executorService = executorService; this.protocolSchedule = protocolSchedule; this.pendingTransactions = pendingTransactions; this.extraData = miningParams.getExtraData(); @@ -60,10 +69,32 @@ public AbstractMinerExecutor( this.gasLimitCalculator = gasLimitCalculator; } - public abstract M startAsyncMining( - final Subscribers observers, final BlockHeader parentHeader); + public Optional startAsyncMining( + final Subscribers observers, final BlockHeader parentHeader) { + try { + final M currentRunningMiner = createMiner(observers, parentHeader); + executorService.execute(currentRunningMiner); + return Optional.of(currentRunningMiner); + } catch (RejectedExecutionException e) { + LOG.warn("Unable to start mining.", e); + return Optional.empty(); + } + } + + public void shutDown() { + if (stopped.compareAndSet(false, true)) { + executorService.shutdownNow(); + } + } + + public void awaitShutdown() throws InterruptedException { + if (!executorService.awaitTermination(30, TimeUnit.SECONDS)) { + LOG.error("Failed to shutdown {}.", this.getClass().getSimpleName()); + } + } - public abstract M createMiner(final BlockHeader parentHeader); + public abstract M createMiner( + final Subscribers subscribers, final BlockHeader parentHeader); public void setExtraData(final BytesValue extraData) { this.extraData = extraData.copy(); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java index c5b73062525..b211763e7cc 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.logging.log4j.Logger; @@ -38,14 +39,22 @@ public abstract class AbstractMiningCoordinator< C, M extends BlockMiner>> implements BlockAddedObserver, MiningCoordinator { + private enum State { + IDLE, + RUNNING, + STOPPED + } + private static final Logger LOG = getLogger(); - protected boolean isEnabled = false; - protected volatile Optional currentRunningMiner = Optional.empty(); private final Subscribers minedBlockObservers = Subscribers.create(); private final AbstractMinerExecutor executor; - protected final Blockchain blockchain; private final SyncState syncState; + private final Blockchain blockchain; + + private State state = State.IDLE; + private boolean isEnabled = false; + protected Optional currentRunningMiner = Optional.empty(); public AbstractMiningCoordinator( final Blockchain blockchain, @@ -55,7 +64,7 @@ public AbstractMiningCoordinator( this.blockchain = blockchain; this.syncState = syncState; this.blockchain.observeBlockAdded(this); - syncState.addInSyncListener(this::inSyncChanged); + syncState.subscribeInSync(this::inSyncChanged); } @Override @@ -63,75 +72,116 @@ public Optional createBlock( final BlockHeader parentHeader, final List transactions, final List ommers) { - M miner = executor.createMiner(parentHeader); + final M miner = executor.createMiner(Subscribers.none(), parentHeader); return Optional.of(miner.createBlock(parentHeader, transactions, ommers)); } @Override - public void enable() { + public void start() { synchronized (this) { - if (isEnabled) { + if (state != State.IDLE) { + return; + } + state = State.RUNNING; + startMiningIfPossible(); + } + } + + @Override + public void stop() { + synchronized (this) { + if (state != State.RUNNING) { return; } - if (syncState.isInSync()) { - startAsyncMiningOperation(); + state = State.STOPPED; + haltCurrentMiningOperation(); + executor.shutDown(); + } + } + + @Override + public void awaitStop() throws InterruptedException { + executor.awaitShutdown(); + } + + @Override + public boolean enable() { + synchronized (this) { + if (isEnabled) { + return true; } isEnabled = true; + startMiningIfPossible(); } + return true; } @Override - public void disable() { + public boolean disable() { synchronized (this) { if (!isEnabled) { - return; + return false; } - haltCurrentMiningOperation(); isEnabled = false; + haltCurrentMiningOperation(); } + return false; } @Override - public boolean isRunning() { + public boolean isMining() { synchronized (this) { return currentRunningMiner.isPresent(); } } - protected void startAsyncMiningOperation() { + private synchronized boolean startMiningIfPossible() { + if ((state != State.RUNNING) || !isEnabled || !syncState.isInSync() || isMining()) { + return false; + } + + startAsyncMiningOperation(); + return true; + } + + private void startAsyncMiningOperation() { final BlockHeader parentHeader = blockchain.getChainHeadHeader(); - currentRunningMiner = Optional.of(executor.startAsyncMining(minedBlockObservers, parentHeader)); + currentRunningMiner = executor.startAsyncMining(minedBlockObservers, parentHeader); } - protected void haltCurrentMiningOperation() { - currentRunningMiner.ifPresent(M::cancel); + private synchronized boolean haltCurrentMiningOperation() { + final AtomicBoolean wasHalted = new AtomicBoolean(false); + currentRunningMiner.ifPresent( + (miner) -> { + haltMiner(miner); + wasHalted.set(true); + }); currentRunningMiner = Optional.empty(); + return wasHalted.get(); + } + + protected void haltMiner(final M miner) { + miner.cancel(); } @Override public void onBlockAdded(final BlockAddedEvent event, final Blockchain blockchain) { synchronized (this) { - if (isEnabled - && event.isNewCanonicalHead() + if (event.isNewCanonicalHead() && newChainHeadInvalidatesMiningOperation(event.getBlock().getHeader())) { haltCurrentMiningOperation(); - if (syncState.isInSync()) { - startAsyncMiningOperation(); - } + startMiningIfPossible(); } } } - public void inSyncChanged(final boolean inSync) { + void inSyncChanged(final boolean inSync) { synchronized (this) { - if (isEnabled && inSync) { + if (inSync && startMiningIfPossible()) { LOG.info("Resuming mining operations"); - startAsyncMiningOperation(); - } else if (!inSync) { - if (isEnabled) { - LOG.info("Pausing mining while behind chain head"); - } - haltCurrentMiningOperation(); + } + if (!inSync && haltCurrentMiningOperation()) { + LOG.info("Pausing mining while behind chain head"); } } } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMinerExecutor.java index 4298f6e928d..063dccf4701 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMinerExecutor.java @@ -26,7 +26,6 @@ import org.hyperledger.besu.util.Subscribers; import java.util.Optional; -import java.util.concurrent.ExecutorService; import java.util.function.Function; public class EthHashMinerExecutor extends AbstractMinerExecutor { @@ -35,7 +34,6 @@ public class EthHashMinerExecutor extends AbstractMinerExecutor protocolContext, - final ExecutorService executorService, final ProtocolSchedule protocolSchedule, final PendingTransactions pendingTransactions, final MiningParameters miningParams, @@ -43,7 +41,6 @@ public EthHashMinerExecutor( final Function gasLimitCalculator) { super( protocolContext, - executorService, protocolSchedule, pendingTransactions, miningParams, @@ -53,23 +50,16 @@ public EthHashMinerExecutor( } @Override - public EthHashBlockMiner startAsyncMining( + public Optional startAsyncMining( final Subscribers observers, final BlockHeader parentHeader) { if (!coinbase.isPresent()) { throw new CoinbaseNotSetException("Unable to start mining without a coinbase."); - } else { - final EthHashBlockMiner currentRunningMiner = createMiner(observers, parentHeader); - executorService.execute(currentRunningMiner); - return currentRunningMiner; } + return super.startAsyncMining(observers, parentHeader); } @Override - public EthHashBlockMiner createMiner(final BlockHeader parentHeader) { - return createMiner(Subscribers.none(), parentHeader); - } - - private EthHashBlockMiner createMiner( + public EthHashBlockMiner createMiner( final Subscribers observers, final BlockHeader parentHeader) { final EthHashSolver solver = new EthHashSolver(new RandomNonceGenerator(), new EthHasher.Light()); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMiningCoordinator.java index 18c61993117..967888be45f 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMiningCoordinator.java @@ -71,13 +71,9 @@ public boolean submitWork(final EthHashSolution solution) { } @Override - protected void haltCurrentMiningOperation() { - currentRunningMiner.ifPresent( - miner -> { - miner.cancel(); - miner.getHashesPerSecond().ifPresent(val -> cachedHashesPerSecond = Optional.of(val)); - }); - currentRunningMiner = Optional.empty(); + protected void haltMiner(final EthHashBlockMiner miner) { + miner.cancel(); + miner.getHashesPerSecond().ifPresent(val -> cachedHashesPerSecond = Optional.of(val)); } @Override diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java index b82a524e787..6bf79cfc2ca 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java @@ -28,11 +28,27 @@ public interface MiningCoordinator { - void enable(); + void start(); - void disable(); + void stop(); - boolean isRunning(); + void awaitStop() throws InterruptedException; + + /** + * If mining is disabled, enable it. + * + * @return True if mining is enabled. + */ + boolean enable(); + + /** + * If mining is enabled, disable it. + * + * @return True if mining is disabled. + */ + boolean disable(); + + boolean isMining(); Wei getMinTransactionGasPrice(); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java new file mode 100644 index 00000000000..e4e884e1438 --- /dev/null +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java @@ -0,0 +1,81 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.blockcreation; + +import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.Wei; +import org.hyperledger.besu.util.bytes.BytesValue; + +import java.util.List; +import java.util.Optional; + +public class NoopMiningCoordinator implements MiningCoordinator { + + private final MiningParameters miningParameters; + + public NoopMiningCoordinator(final MiningParameters miningParameters) { + this.miningParameters = miningParameters; + } + + @Override + public void start() {} + + @Override + public void stop() {} + + @Override + public void awaitStop() {} + + @Override + public boolean enable() { + return false; + } + + @Override + public boolean disable() { + return true; + } + + @Override + public boolean isMining() { + return false; + } + + @Override + public Wei getMinTransactionGasPrice() { + return miningParameters.getMinTransactionGasPrice(); + } + + @Override + public void setExtraData(final BytesValue extraData) {} + + @Override + public Optional
getCoinbase() { + return miningParameters.getCoinbase(); + } + + @Override + public Optional createBlock( + final BlockHeader parentHeader, + final List transactions, + final List ommers) { + return Optional.empty(); + } +} diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java index ac558966abf..df02770b831 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java @@ -16,6 +16,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -31,6 +32,7 @@ import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import java.util.Collections; +import java.util.Optional; import org.junit.Before; import org.junit.Test; @@ -50,13 +52,14 @@ public class AbstractMiningCoordinatorTest { @Before public void setUp() { - when(minerExecutor.startAsyncMining(any(), any())).thenReturn(blockMiner); + when(minerExecutor.startAsyncMining(any(), any())).thenReturn(Optional.of(blockMiner)); } @Test public void shouldNotStartMiningWhenEnabledAndOutOfSync() { when(syncState.isInSync()).thenReturn(false); miningCoordinator.enable(); + miningCoordinator.start(); verifyZeroInteractions(minerExecutor, blockMiner); } @@ -64,6 +67,7 @@ public void shouldNotStartMiningWhenEnabledAndOutOfSync() { public void shouldStartMiningWhenEnabledAndInSync() { when(syncState.isInSync()).thenReturn(true); miningCoordinator.enable(); + miningCoordinator.start(); verify(minerExecutor).startAsyncMining(any(), any()); verifyNoMoreInteractions(minerExecutor, blockMiner); } @@ -72,7 +76,10 @@ public void shouldStartMiningWhenEnabledAndInSync() { public void shouldStartMiningWhenEnabledAndBecomeInSync() { when(syncState.isInSync()).thenReturn(false); miningCoordinator.enable(); + miningCoordinator.start(); + verify(minerExecutor, never()).startAsyncMining(any(), any()); + when(syncState.isInSync()).thenReturn(true); miningCoordinator.inSyncChanged(true); verify(minerExecutor).startAsyncMining(any(), any()); @@ -83,6 +90,7 @@ public void shouldStartMiningWhenEnabledAndBecomeInSync() { public void shouldHaltMiningWhenBecomingOutOfSync() { when(syncState.isInSync()).thenReturn(true); miningCoordinator.enable(); + miningCoordinator.start(); verify(minerExecutor).startAsyncMining(any(), any()); miningCoordinator.inSyncChanged(false); @@ -95,8 +103,10 @@ public void shouldHaltMiningWhenBecomingOutOfSync() { public void shouldNotStartWhenBlockAddedAndOutOfSync() { when(syncState.isInSync()).thenReturn(false); miningCoordinator.enable(); + miningCoordinator.start(); - miningCoordinator.onBlockAdded(BlockAddedEvent.createForHeadAdvancement(BLOCK), blockchain); + miningCoordinator.onBlockAdded( + BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); verifyNoMoreInteractions(minerExecutor, blockMiner); } @@ -105,8 +115,10 @@ public void shouldNotStartWhenBlockAddedAndOutOfSync() { public void shouldRestartMiningWhenBlockAddedAndInSync() { when(syncState.isInSync()).thenReturn(true); miningCoordinator.enable(); + miningCoordinator.start(); - miningCoordinator.onBlockAdded(BlockAddedEvent.createForHeadAdvancement(BLOCK), blockchain); + miningCoordinator.onBlockAdded( + BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); verify(blockMiner).cancel(); verify(minerExecutor, times(2)).startAsyncMining(any(), any()); @@ -114,17 +126,94 @@ public void shouldRestartMiningWhenBlockAddedAndInSync() { verifyNoMoreInteractions(minerExecutor, blockMiner); } + @Test + public void shouldNotStartMiningWhenBecomingInSyncIfMinerNotStarted() { + miningCoordinator.enable(); + when(syncState.isInSync()).thenReturn(true); + miningCoordinator.inSyncChanged(true); + verifyNoMoreInteractions(minerExecutor, blockMiner); + } + @Test public void shouldNotStartMiningWhenBecomingInSyncIfMinerNotEnabled() { + miningCoordinator.disable(); + miningCoordinator.start(); + when(syncState.isInSync()).thenReturn(true); + miningCoordinator.inSyncChanged(true); + verifyNoMoreInteractions(minerExecutor, blockMiner); + } + + @Test + public void shouldNotStartMiningWhenBecomingInSyncIfMinerStopped() { + miningCoordinator.enable(); + miningCoordinator.start(); + miningCoordinator.stop(); + verify(minerExecutor).shutDown(); when(syncState.isInSync()).thenReturn(true); miningCoordinator.inSyncChanged(true); + + verifyNoMoreInteractions(minerExecutor, blockMiner); + } + + @Test + public void shouldNotStartMiningWhenBecomingInSyncIfMinerStoppedThenStarted() { + miningCoordinator.enable(); + miningCoordinator.start(); + miningCoordinator.stop(); + verify(minerExecutor).shutDown(); + miningCoordinator.start(); + + when(syncState.isInSync()).thenReturn(true); + miningCoordinator.inSyncChanged(true); + verifyNoMoreInteractions(minerExecutor, blockMiner); } @Test public void shouldNotStartMiningWhenBlockAddedAndInSyncIfMinerNotEnabled() { + miningCoordinator.disable(); + miningCoordinator.start(); + when(syncState.isInSync()).thenReturn(true); + miningCoordinator.onBlockAdded( + BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); + + verifyNoMoreInteractions(minerExecutor, blockMiner); + } + + @Test + public void shouldNotStartMiningWhenBlockAddedAndInSyncIfMinerNotStarted() { + miningCoordinator.enable(); + when(syncState.isInSync()).thenReturn(true); + miningCoordinator.onBlockAdded( + BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); + verifyNoMoreInteractions(minerExecutor, blockMiner); + } + + @Test + public void shouldNotStartMiningWhenBlockAddedAndInSyncIfStopped() { + miningCoordinator.enable(); + miningCoordinator.start(); + miningCoordinator.stop(); + verify(minerExecutor).shutDown(); + + when(syncState.isInSync()).thenReturn(true); + miningCoordinator.onBlockAdded( + BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); + + verifyNoMoreInteractions(minerExecutor, blockMiner); + } + + @Test + public void shouldNotStartMiningWhenBlockAddedAndInSyncIfStoppedThenStarted() { + miningCoordinator.enable(); + miningCoordinator.start(); + miningCoordinator.stop(); + verify(minerExecutor).shutDown(); + miningCoordinator.start(); + when(syncState.isInSync()).thenReturn(true); - miningCoordinator.onBlockAdded(BlockAddedEvent.createForHeadAdvancement(BLOCK), blockchain); + miningCoordinator.onBlockAdded( + BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); verifyNoMoreInteractions(minerExecutor, blockMiner); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelectorTest.java index 342f7b75086..6ec4ea1f007 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelectorTest.java @@ -471,9 +471,9 @@ public void shouldDiscardTransactionsThatFailValidation() { selector.buildTransactionListForBlock(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(validTransaction.hash())) + Assertions.assertThat(pendingTransactions.getTransactionByHash(validTransaction.getHash())) .isPresent(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(invalidTransaction.hash())) + Assertions.assertThat(pendingTransactions.getTransactionByHash(invalidTransaction.getHash())) .isNotPresent(); } @@ -517,7 +517,7 @@ public void transactionWithIncorrectNonceRemainsInPoolAndNotSelected() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(futureTransaction.hash())) + Assertions.assertThat(pendingTransactions.getTransactionByHash(futureTransaction.getHash())) .isPresent(); assertThat(results.getTransactions().size()).isEqualTo(0); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMinerExecutorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMinerExecutorTest.java index a0137fa2d3b..1a3a99550c4 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMinerExecutorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMinerExecutorTest.java @@ -25,7 +25,6 @@ import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.util.Subscribers; -import java.util.concurrent.Executors; import java.util.function.Function; import org.junit.Test; @@ -48,7 +47,6 @@ public void startingMiningWithoutCoinbaseThrowsException() { final EthHashMinerExecutor executor = new EthHashMinerExecutor( null, - Executors.newCachedThreadPool(), null, pendingTransactions, miningParameters, @@ -74,7 +72,6 @@ public void settingCoinbaseToNullThrowsException() { final EthHashMinerExecutor executor = new EthHashMinerExecutor( null, - Executors.newCachedThreadPool(), null, pendingTransactions, miningParameters, diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMiningCoordinatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMiningCoordinatorTest.java index b7d1eb6af8a..26fc1eb9cc1 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMiningCoordinatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/EthHashMiningCoordinatorTest.java @@ -48,7 +48,7 @@ public void miningCoordinatorIsCreatedDisabledWithNoReportableMiningStatistics() new EthHashMiningCoordinator(executionContext.getBlockchain(), executor, syncState); final EthHashSolution solution = new EthHashSolution(1L, Hash.EMPTY, new byte[Bytes32.SIZE]); - assertThat(miningCoordinator.isRunning()).isFalse(); + assertThat(miningCoordinator.isMining()).isFalse(); assertThat(miningCoordinator.hashesPerSecond()).isEqualTo(Optional.empty()); assertThat(miningCoordinator.getWorkDefinition()).isEqualTo(Optional.empty()); assertThat(miningCoordinator.submitWork(solution)).isFalse(); @@ -63,12 +63,15 @@ public void reportedHashRateIsCachedIfNoCurrentDataInMiner() { when(miner.getHashesPerSecond()).thenReturn(hashRate1, hashRate2, hashRate3); - when(executor.startAsyncMining(any(), any())).thenReturn(miner); + when(executor.startAsyncMining(any(), any())).thenReturn(Optional.of(miner)); final EthHashMiningCoordinator miningCoordinator = new EthHashMiningCoordinator(executionContext.getBlockchain(), executor, syncState); - miningCoordinator.enable(); // Must enable prior returning data + // Must enable prior returning data + miningCoordinator.enable(); + miningCoordinator.start(); + assertThat(miningCoordinator.hashesPerSecond()).isEqualTo(hashRate1); assertThat(miningCoordinator.hashesPerSecond()).isEqualTo(hashRate1); assertThat(miningCoordinator.hashesPerSecond()).isEqualTo(hashRate3); diff --git a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/worldstate/PrunerIntegrationTest.java b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/worldstate/PrunerIntegrationTest.java index 053a4df3a38..92211163c33 100644 --- a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/worldstate/PrunerIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/worldstate/PrunerIntegrationTest.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage; import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie; +import org.hyperledger.besu.ethereum.worldstate.Pruner.PruningPhase; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.testutil.MockExecutorService; @@ -107,8 +108,8 @@ private void testPruner( new Pruner( markSweepPruner, blockchain, - new MockExecutorService(), - new PruningConfiguration(blockConfirmations, numBlocksToKeep)); + new PruningConfiguration(blockConfirmations, numBlocksToKeep), + MockExecutorService::new); pruner.start(); @@ -119,13 +120,9 @@ private void testPruner( var fullyMarkedBlockNum = cycle * numBlockInCycle + 1; // This should cause a full mark and sweep cycle - assertThat(pruner.getState()).isEqualByComparingTo(Pruner.State.IDLE); + assertThat(pruner.getPruningPhase()).isEqualByComparingTo(PruningPhase.IDLE); generateBlockchainData(numBlockInCycle, accountsPerBlock); - assertThat(pruner.getState()).isEqualByComparingTo(Pruner.State.IDLE); - - // Restarting the Pruner shouldn't matter since we're idle - pruner.stop(); - pruner.start(); + assertThat(pruner.getPruningPhase()).isEqualByComparingTo(PruningPhase.IDLE); // Collect the nodes we expect to keep final Set expectedNodes = new HashSet<>(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java index b19713e2e9c..9a4573452c3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.chain; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import java.util.Collections; @@ -26,6 +27,7 @@ public class BlockAddedEvent { private final List addedTransactions; private final List removedTransactions; private final EventType eventType; + private List logsWithMetadata; public enum EventType { HEAD_ADVANCED, @@ -37,29 +39,41 @@ private BlockAddedEvent( final EventType eventType, final Block block, final List addedTransactions, - final List removedTransactions) { + final List removedTransactions, + final List logsWithMetadata) { this.eventType = eventType; this.block = block; this.addedTransactions = addedTransactions; this.removedTransactions = removedTransactions; + this.logsWithMetadata = logsWithMetadata; } - public static BlockAddedEvent createForHeadAdvancement(final Block block) { + public static BlockAddedEvent createForHeadAdvancement( + final Block block, final List logsWithMetadata) { return new BlockAddedEvent( - EventType.HEAD_ADVANCED, block, block.getBody().getTransactions(), Collections.emptyList()); + EventType.HEAD_ADVANCED, + block, + block.getBody().getTransactions(), + Collections.emptyList(), + logsWithMetadata); } public static BlockAddedEvent createForChainReorg( final Block block, final List addedTransactions, - final List removedTransactions) { + final List removedTransactions, + final List logsWithMetadata) { return new BlockAddedEvent( - EventType.CHAIN_REORG, block, addedTransactions, removedTransactions); + EventType.CHAIN_REORG, block, addedTransactions, removedTransactions, logsWithMetadata); } public static BlockAddedEvent createForFork(final Block block) { return new BlockAddedEvent( - EventType.FORK, block, Collections.emptyList(), Collections.emptyList()); + EventType.FORK, + block, + Collections.emptyList(), + Collections.emptyList(), + Collections.emptyList()); } public Block getBlock() { @@ -81,4 +95,8 @@ public List getAddedTransactions() { public List getRemovedTransactions() { return removedTransactions; } + + public List getLogsWithMetadata() { + return logsWithMetadata; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 0ed1b617681..713d7184350 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -22,7 +22,9 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.metrics.BesuMetricCategory; @@ -41,8 +43,11 @@ import java.util.NoSuchElementException; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; public class DefaultBlockchain implements MutableBlockchain { @@ -134,21 +139,11 @@ public static Blockchain create( private static boolean validateStorageNonEmpty(final BlockchainStorage blockchainStorage) { // Run a few basic checks to make sure data looks available and consistent - final Optional maybeHead = blockchainStorage.getChainHead(); - if (maybeHead.isEmpty()) { - return false; - } - final Optional genesisHash = - blockchainStorage.getBlockHash(BlockHeader.GENESIS_BLOCK_NUMBER); - if (genesisHash.isEmpty()) { - return false; - } - final Optional td = blockchainStorage.getTotalDifficulty(maybeHead.get()); - if (td.isEmpty()) { - return false; - } - - return true; + return blockchainStorage + .getChainHead() + .flatMap(blockchainStorage::getTotalDifficulty) + .isPresent() + && blockchainStorage.getBlockHash(BlockHeader.GENESIS_BLOCK_NUMBER).isPresent(); } @Override @@ -171,6 +166,11 @@ public BlockHeader getChainHeadHeader() { return chainHeader; } + @Override + public Block getChainHeadBlock() { + return new Block(chainHeader, blockchainStorage.getBlockBody(chainHeader.getHash()).get()); + } + @Override public Optional getBlockHeader(final long blockNumber) { return blockchainStorage.getBlockHash(blockNumber).flatMap(blockchainStorage::getBlockHeader); @@ -225,16 +225,16 @@ public synchronized void appendBlock(final Block block, final List receipts) { + private BlockAddedEvent appendBlockHelper(final BlockWithReceipts blockWithReceipts) { + final Block block = blockWithReceipts.getBlock(); + final List receipts = blockWithReceipts.getReceipts(); final Hash hash = block.getHash(); final UInt256 td = calculateTotalDifficulty(block); @@ -246,7 +246,8 @@ private BlockAddedEvent appendBlockHelper( updater.putTotalDifficulty(hash, td); // Update canonical chain data - final BlockAddedEvent blockAddedEvent = updateCanonicalChainData(updater, block, td); + final BlockAddedEvent blockAddedEvent = + updateCanonicalChainData(updater, blockWithReceipts, td); updater.commit(); if (blockAddedEvent.isNewCanonicalHead()) { @@ -261,19 +262,19 @@ private UInt256 calculateTotalDifficulty(final Block block) { return block.getHeader().getDifficulty(); } - final Optional maybeParentId = - blockchainStorage.getTotalDifficulty(block.getHeader().getParentHash()); - if (!maybeParentId.isPresent()) { - throw new IllegalStateException("Blockchain is missing total difficulty data."); - } - final UInt256 parentTd = maybeParentId.get(); - return block.getHeader().getDifficulty().plus(parentTd); + final UInt256 parentTotalDifficulty = + blockchainStorage + .getTotalDifficulty(block.getHeader().getParentHash()) + .orElseThrow( + () -> new IllegalStateException("Blockchain is missing total difficulty data.")); + return block.getHeader().getDifficulty().plus(parentTotalDifficulty); } private BlockAddedEvent updateCanonicalChainData( final BlockchainStorage.Updater updater, - final Block newBlock, + final BlockWithReceipts blockWithReceipts, final UInt256 totalDifficulty) { + final Block newBlock = blockWithReceipts.getBlock(); final Hash chainHead = blockchainStorage.getChainHead().orElse(null); if (newBlock.getHeader().getNumber() != BlockHeader.GENESIS_BLOCK_NUMBER && chainHead == null) { throw new IllegalStateException("Blockchain is missing chain head."); @@ -286,11 +287,14 @@ private BlockAddedEvent updateCanonicalChainData( updater.putBlockHash(newBlock.getHeader().getNumber(), newBlockHash); updater.setChainHead(newBlockHash); indexTransactionForBlock(updater, newBlockHash, newBlock.getBody().getTransactions()); - return BlockAddedEvent.createForHeadAdvancement(newBlock); + return BlockAddedEvent.createForHeadAdvancement( + newBlock, + LogWithMetadata.generate( + blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), false)); } else if (totalDifficulty.compareTo(blockchainStorage.getTotalDifficulty(chainHead).get()) > 0) { // New block represents a chain reorganization - return handleChainReorg(updater, newBlock); + return handleChainReorg(updater, blockWithReceipts); } else { // New block represents a fork return handleFork(updater, newBlock); @@ -307,11 +311,11 @@ private BlockAddedEvent handleFork(final BlockchainStorage.Updater updater, fina final Collection forkHeads = blockchainStorage.getForkHeads(); // Check to see if this block advances any existing fork. - final Hash parentHash = fork.getHeader().getParentHash(); - final Optional parent = - forkHeads.stream().filter(head -> head.equals(parentHash)).findAny(); // This block will replace its parent - parent.ifPresent(forkHeads::remove); + forkHeads.stream() + .filter(head -> head.equals(fork.getHeader().getParentHash())) + .findAny() + .ifPresent(forkHeads::remove); forkHeads.add(fork.getHash()); @@ -320,58 +324,59 @@ private BlockAddedEvent handleFork(final BlockchainStorage.Updater updater, fina } private BlockAddedEvent handleChainReorg( - final BlockchainStorage.Updater updater, final Block newChainHead) { - final Hash oldChainHead = blockchainStorage.getChainHead().get(); - BlockHeader oldChain = blockchainStorage.getBlockHeader(oldChainHead).get(); - BlockHeader newChain = newChainHead.getHeader(); + final BlockchainStorage.Updater updater, final BlockWithReceipts newChainHeadWithReceipts) { + BlockWithReceipts oldChainWithReceipts = getBlockWithReceipts(chainHeader).get(); + BlockWithReceipts currentOldChainWithReceipts = oldChainWithReceipts; + BlockWithReceipts currentNewChainWithReceipts = newChainHeadWithReceipts; // Update chain head - updater.setChainHead(newChain.getHash()); + updater.setChainHead(currentNewChainWithReceipts.getHeader().getHash()); - // Track transactions to be added and removed + // Track transactions and logs to be added and removed final Map> newTransactions = new HashMap<>(); final List removedTransactions = new ArrayList<>(); + final List addedLogsWithMetadata = new ArrayList<>(); + final List removedLogsWithMetadata = new ArrayList<>(); - while (newChain.getNumber() > oldChain.getNumber()) { + while (currentNewChainWithReceipts.getNumber() > currentOldChainWithReceipts.getNumber()) { // If new chain is longer than old chain, walk back until we meet the old chain by number // adding indexing for new chain along the way. - final Hash blockHash = newChain.getHash(); - updater.putBlockHash(newChain.getNumber(), blockHash); - final List newTxs = - blockHash.equals(newChainHead.getHash()) - ? newChainHead.getBody().getTransactions() - : blockchainStorage.getBlockBody(blockHash).get().getTransactions(); - newTransactions.put(blockHash, newTxs); - - newChain = blockchainStorage.getBlockHeader(newChain.getParentHash()).get(); + final Hash blockHash = currentNewChainWithReceipts.getHash(); + updater.putBlockHash(currentNewChainWithReceipts.getNumber(), blockHash); + + newTransactions.put( + blockHash, currentNewChainWithReceipts.getBlock().getBody().getTransactions()); + addAddedLogsWithMetadata(addedLogsWithMetadata, currentNewChainWithReceipts); + + currentNewChainWithReceipts = getParentBlockWithReceipts(currentNewChainWithReceipts); } - while (oldChain.getNumber() > newChain.getNumber()) { + while (currentOldChainWithReceipts.getNumber() > currentNewChainWithReceipts.getNumber()) { // If oldChain is longer than new chain, walk back until we meet the new chain by number, // updating as we go. - updater.removeBlockHash(oldChain.getNumber()); + updater.removeBlockHash(currentOldChainWithReceipts.getNumber()); + removedTransactions.addAll( - blockchainStorage.getBlockBody(oldChain.getHash()).get().getTransactions()); + currentOldChainWithReceipts.getBlock().getBody().getTransactions()); + addRemovedLogsWithMetadata(removedLogsWithMetadata, currentOldChainWithReceipts); - oldChain = blockchainStorage.getBlockHeader(oldChain.getParentHash()).get(); + currentOldChainWithReceipts = getParentBlockWithReceipts(currentOldChainWithReceipts); } - while (!oldChain.getHash().equals(newChain.getHash())) { + while (!currentOldChainWithReceipts.getHash().equals(currentNewChainWithReceipts.getHash())) { // Walk back until we meet the common ancestor between the two chains, updating as we go. - final Hash newBlockHash = newChain.getHash(); - updater.putBlockHash(newChain.getNumber(), newBlockHash); - - // Collect transaction to be updated - final List newTxs = - newBlockHash.equals(newChainHead.getHash()) - ? newChainHead.getBody().getTransactions() - : blockchainStorage.getBlockBody(newBlockHash).get().getTransactions(); - newTransactions.put(newBlockHash, newTxs); + final Hash newBlockHash = currentNewChainWithReceipts.getHash(); + updater.putBlockHash(currentNewChainWithReceipts.getNumber(), newBlockHash); + + newTransactions.put( + newBlockHash, currentNewChainWithReceipts.getBlock().getBody().getTransactions()); removedTransactions.addAll( - blockchainStorage.getBlockBody(oldChain.getHash()).get().getTransactions()); + currentOldChainWithReceipts.getBlock().getBody().getTransactions()); + addAddedLogsWithMetadata(addedLogsWithMetadata, currentNewChainWithReceipts); + addRemovedLogsWithMetadata(removedLogsWithMetadata, currentOldChainWithReceipts); - newChain = blockchainStorage.getBlockHeader(newChain.getParentHash()).get(); - oldChain = blockchainStorage.getBlockHeader(oldChain.getParentHash()).get(); + currentNewChainWithReceipts = getParentBlockWithReceipts(currentNewChainWithReceipts); + currentOldChainWithReceipts = getParentBlockWithReceipts(currentOldChainWithReceipts); } // Update indexed transactions @@ -386,16 +391,20 @@ private BlockAddedEvent handleChainReorg( // Update tracked forks final Collection forks = blockchainStorage.getForkHeads(); // Old head is now a fork - forks.add(oldChainHead); + forks.add(oldChainWithReceipts.getHash()); // Remove new chain head's parent if it was tracked as a fork final Optional parentFork = - forks.stream().filter(f -> f.equals(newChainHead.getHeader().getParentHash())).findAny(); + forks.stream() + .filter(f -> f.equals(newChainHeadWithReceipts.getHeader().getParentHash())) + .findAny(); parentFork.ifPresent(forks::remove); updater.setForkHeads(forks); return BlockAddedEvent.createForChainReorg( - newChainHead, + newChainHeadWithReceipts.getBlock(), newTransactions.values().stream().flatMap(Collection::stream).collect(toList()), - removedTransactions); + removedTransactions, + Stream.concat(removedLogsWithMetadata.stream(), addedLogsWithMetadata.stream()) + .collect(Collectors.toUnmodifiableList())); } @Override @@ -407,12 +416,11 @@ public boolean rewindToBlock(final long blockNumber) { final BlockchainStorage.Updater updater = blockchainStorage.updater(); try { - final Optional oldBlockHeader = - blockchainStorage.getBlockHeader(blockHash.get()); - final Optional oldBlockBody = blockchainStorage.getBlockBody(blockHash.get()); - final Block block = new Block(oldBlockHeader.get(), oldBlockBody.get()); + final BlockHeader oldBlockHeader = blockchainStorage.getBlockHeader(blockHash.get()).get(); + final BlockWithReceipts blockWithReceipts = getBlockWithReceipts(oldBlockHeader).get(); + final Block block = blockWithReceipts.getBlock(); - handleChainReorg(updater, block); + handleChainReorg(updater, blockWithReceipts); updater.commit(); updateCacheForNewCanonicalHead(block, calculateTotalDifficulty(block)); @@ -435,7 +443,7 @@ void updateCacheForNewCanonicalHead(final Block block, final UInt256 uInt256) { private static void indexTransactionForBlock( final BlockchainStorage.Updater updater, final Hash hash, final List txs) { for (int i = 0; i < txs.size(); i++) { - final Hash txHash = txs.get(i).hash(); + final Hash txHash = txs.get(i).getHash(); final TransactionLocation loc = new TransactionLocation(hash, i); updater.putTransactionLocation(txHash, loc); } @@ -444,7 +452,7 @@ private static void indexTransactionForBlock( private static void clearIndexedTransactionsForBlock( final BlockchainStorage.Updater updater, final List txs) { for (final Transaction tx : txs) { - updater.removeTransactionLocation(tx.hash()); + updater.removeTransactionLocation(tx.getHash()); } } @@ -458,7 +466,7 @@ private void setGenesis(final Block genesisBlock) { genesisBlock.getHeader().getNumber() == BlockHeader.GENESIS_BLOCK_NUMBER, "Invalid genesis block."); final Optional maybeHead = blockchainStorage.getChainHead(); - if (!maybeHead.isPresent()) { + if (maybeHead.isEmpty()) { // Initialize blockchain store with genesis block. final BlockchainStorage.Updater updater = blockchainStorage.updater(); final Hash hash = genesisBlock.getHash(); @@ -472,7 +480,7 @@ private void setGenesis(final Block genesisBlock) { } else { // Verify genesis block is consistent with stored blockchain. final Optional genesisHash = getBlockHashByNumber(BlockHeader.GENESIS_BLOCK_NUMBER); - if (!genesisHash.isPresent()) { + if (genesisHash.isEmpty()) { throw new IllegalStateException("Blockchain is missing genesis block data."); } if (!genesisHash.get().equals(genesisBlock.getHash())) { @@ -497,6 +505,40 @@ private boolean blockIsConnected(final Block block) { return blockchainStorage.getBlockHeader(block.getHeader().getParentHash()).isPresent(); } + private void addAddedLogsWithMetadata( + final List logsWithMetadata, final BlockWithReceipts blockWithReceipts) { + logsWithMetadata.addAll( + 0, + LogWithMetadata.generate( + blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), false)); + } + + private void addRemovedLogsWithMetadata( + final List logsWithMetadata, final BlockWithReceipts blockWithReceipts) { + logsWithMetadata.addAll( + Lists.reverse( + LogWithMetadata.generate( + blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), true))); + } + + private Optional getBlockWithReceipts(final BlockHeader blockHeader) { + return blockchainStorage + .getBlockBody(blockHeader.getHash()) + .map(body -> new Block(blockHeader, body)) + .flatMap( + block -> + blockchainStorage + .getTransactionReceipts(blockHeader.getHash()) + .map(receipts -> new BlockWithReceipts(block, receipts))); + } + + private BlockWithReceipts getParentBlockWithReceipts(final BlockWithReceipts blockWithReceipts) { + return blockchainStorage + .getBlockHeader(blockWithReceipts.getHeader().getParentHash()) + .flatMap(this::getBlockWithReceipts) + .get(); + } + @Override public long observeBlockAdded(final BlockAddedObserver observer) { checkNotNull(observer); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/BlockWithReceipts.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java similarity index 82% rename from ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/BlockWithReceipts.java rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java index 6b96a8dd254..ae642b065ad 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/BlockWithReceipts.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java @@ -12,23 +12,18 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.eth.sync.fastsync; - -import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.Hash; -import org.hyperledger.besu.ethereum.core.TransactionReceipt; +package org.hyperledger.besu.ethereum.core; import java.util.List; import java.util.Objects; import com.google.common.base.MoreObjects; -class BlockWithReceipts { +public class BlockWithReceipts { private final Block block; private final List receipts; - BlockWithReceipts(final Block block, final List receipts) { + public BlockWithReceipts(final Block block, final List receipts) { this.block = block; this.receipts = receipts; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SyncStatus.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/DefaultSyncStatus.java similarity index 69% rename from ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SyncStatus.java rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/DefaultSyncStatus.java index 8740885a4f0..c1f2aa8e815 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SyncStatus.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/DefaultSyncStatus.java @@ -16,26 +16,17 @@ import java.util.Objects; -public final class SyncStatus implements org.hyperledger.besu.plugin.data.SyncStatus { +public final class DefaultSyncStatus implements org.hyperledger.besu.plugin.data.SyncStatus { private final long startingBlock; private final long currentBlock; private final long highestBlock; - private final boolean inSync; - public SyncStatus(final long startingBlock, final long currentBlock, final long highestBlock) { - this(startingBlock, currentBlock, highestBlock, currentBlock == highestBlock); - } - - public SyncStatus( - final long startingBlock, - final long currentBlock, - final long highestBlock, - final boolean inSync) { + public DefaultSyncStatus( + final long startingBlock, final long currentBlock, final long highestBlock) { this.startingBlock = startingBlock; this.currentBlock = currentBlock; this.highestBlock = highestBlock; - this.inSync = inSync; } @Override @@ -53,11 +44,6 @@ public long getHighestBlock() { return highestBlock; } - @Override - public boolean inSync() { - return inSync; - } - @Override public boolean equals(final Object o) { if (this == o) { @@ -66,15 +52,14 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - final SyncStatus that = (SyncStatus) o; + final DefaultSyncStatus that = (DefaultSyncStatus) o; return startingBlock == that.startingBlock && currentBlock == that.currentBlock - && highestBlock == that.highestBlock - && inSync == that.inSync; + && highestBlock == that.highestBlock; } @Override public int hashCode() { - return Objects.hash(startingBlock, currentBlock, highestBlock, inSync); + return Objects.hash(startingBlock, currentBlock, highestBlock); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogTopic.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogTopic.java index 3ffa370c2fd..0eb1579f353 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogTopic.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogTopic.java @@ -44,7 +44,7 @@ public static LogTopic of(final BytesValue bytes) { } public static LogTopic fromHexString(final String str) { - return new LogTopic(BytesValue.fromHexString(str)); + return str == null ? null : LogTopic.create(BytesValue.fromHexString(str)); } /** diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java similarity index 63% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/LogWithMetadata.java rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index 2f00c537a83..79a616f22a3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -1,4 +1,5 @@ /* + * * Copyright ConsenSys AG. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with @@ -11,19 +12,18 @@ * specific language governing permissions and limitations under the License. * * SPDX-License-Identifier: Apache-2.0 + * */ -package org.hyperledger.besu.ethereum.api; +package org.hyperledger.besu.ethereum.core; -import org.hyperledger.besu.ethereum.core.Address; -import org.hyperledger.besu.ethereum.core.Hash; -import org.hyperledger.besu.ethereum.core.LogTopic; import org.hyperledger.besu.util.bytes.BytesValue; +import java.util.ArrayList; import java.util.List; import com.google.common.base.MoreObjects; -public class LogWithMetadata { +public class LogWithMetadata extends Log { private final int logIndex; private final long blockNumber; @@ -45,6 +45,7 @@ public LogWithMetadata( final BytesValue data, final List topics, final boolean removed) { + super(address, data, topics); this.logIndex = logIndex; this.blockNumber = blockNumber; this.blockHash = blockHash; @@ -56,6 +57,48 @@ public LogWithMetadata( this.removed = removed; } + public static List generate( + final TransactionReceipt receipt, + final long number, + final Hash blockHash, + final Hash transactionHash, + final int transactionIndex, + final boolean removed) { + + final List logs = new ArrayList<>(); + for (int logIndex = 0; logIndex < receipt.getLogs().size(); ++logIndex) { + logs.add( + new LogWithMetadata( + logIndex, + number, + blockHash, + transactionHash, + transactionIndex, + receipt.getLogs().get(logIndex).getLogger(), + receipt.getLogs().get(logIndex).getData(), + receipt.getLogs().get(logIndex).getTopics(), + removed)); + } + + return logs; + } + + public static List generate( + final Block block, final List receipts, final boolean removed) { + final List logsWithMetadata = new ArrayList<>(); + for (int txi = 0; txi < receipts.size(); ++txi) { + logsWithMetadata.addAll( + generate( + receipts.get(txi), + block.getHeader().getNumber(), + block.getHash(), + block.getBody().getTransactions().get(txi).getHash(), + txi, + removed)); + } + return logsWithMetadata; + } + // The index of this log within the entire ordered list of logs associated with the block this log // belongs to. public int getLogIndex() { @@ -78,14 +121,17 @@ public int getTransactionIndex() { return transactionIndex; } - public Address getAddress() { + @Override + public Address getLogger() { return address; } + @Override public BytesValue getData() { return data; } + @Override public List getTopics() { return topics; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogsBloomFilter.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogsBloomFilter.java index 5f1e43bd5d7..4524e07352c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogsBloomFilter.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogsBloomFilter.java @@ -76,6 +76,12 @@ public static LogsBloomFilter compute(final Collection logs) { return bloom; } + public static LogsBloomFilter computeBytes(final BytesValue bytesValue) { + final LogsBloomFilter bloom = new LogsBloomFilter(); + bloom.insertBytesValue(bytesValue); + return bloom; + } + /** * Creates a bloom filter from the given RLP-encoded input. * @@ -129,13 +135,17 @@ public BytesValue getBytes() { } public void insertLog(final Log log) { - setBits(keccak256(log.getLogger())); + insertBytesValue(log.getLogger()); for (final LogTopic topic : log.getTopics()) { - setBits(keccak256(topic)); + insertBytesValue(topic); } } + private void insertBytesValue(final BytesValue bytesValue) { + setBits(keccak256(bytesValue)); + } + private void setBit(final int index) { final int byteIndex = BYTE_SIZE - 1 - index / 8; final int bitIndex = index % 8; @@ -148,6 +158,22 @@ public void digest(final LogsBloomFilter other) { } } + public boolean couldContain(final LogsBloomFilter subset) { + if (subset == null) { + return true; + } + if (subset.size() != data.size()) { + return false; + } + for (int i = 0; i < data.size(); i++) { + final byte subsetValue = subset.data.get(i); + if ((data.get(i) & subsetValue) != subsetValue) { + return false; + } + } + return true; + } + @Override public String toString() { return data.toString(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Synchronizer.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Synchronizer.java index f77320a2122..e74a71e5f15 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Synchronizer.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Synchronizer.java @@ -22,17 +22,58 @@ /** Provides an interface to block synchronization processes. */ public interface Synchronizer { + // Default tolerance used to determine whether or not this node is "in sync" + long DEFAULT_IN_SYNC_TOLERANCE = 5; + void start(); void stop(); + void awaitStop() throws InterruptedException; + /** * @return the status, based on SyncingResult When actively synchronizing blocks, alternatively * empty */ Optional getSyncStatus(); - long observeSyncStatus(final BesuEvents.SyncStatusListener listener); + long subscribeSyncStatus(final BesuEvents.SyncStatusListener listener); + + boolean unsubscribeSyncStatus(long observerId); + + /** + * Add a listener that will be notified when this node's sync status changes. A node is considered + * in-sync if the local chain height is no more than {@code DEFAULT_IN_SYNC_TOLERANCE} behind the + * highest estimated remote chain height. + * + * @param listener The callback to invoke when the sync status changes + * @return A subscription id that can be used to unsubscribe from these events + */ + long subscribeInSync(final InSyncListener listener); + + /** + * Add a listener that will be notified when this node's sync status changes. A node is considered + * in-sync if the local chain height is no more than {@code syncTolerance} behind the highest + * estimated remote chain height. + * + * @param listener The callback to invoke when the sync status changes + * @param syncTolerance The tolerance used to determine whether this node is in-sync. A value of + * zero means that the node is considered in-sync only when the local chain height is greater + * than or equal to the best estimated remote chain height. + * @return A subscription id that can be used to unsubscribe from these events + */ + long subscribeInSync(final InSyncListener listener, final long syncTolerance); + + /** + * Unsubscribe from in sync events. + * + * @param listenerId The id returned when subscribing + * @return {@code true} if a subscription was cancelled + */ + boolean unsubscribeInSync(final long listenerId); - boolean removeObserver(long observerId); + @FunctionalInterface + interface InSyncListener { + void onInSyncStatusChange(boolean newSyncStatus); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index ef48ca293a4..793a533d7c0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -218,6 +218,7 @@ public SECP256K1.Signature getSignature() { * * @return the transaction payload */ + @Override public BytesValue getPayload() { return payload; } @@ -335,7 +336,8 @@ public BigInteger getV() { * * @return the transaction hash */ - public Hash hash() { + @Override + public Hash getHash() { if (hash == null) { final BytesValue rlp = RLP.encode(this::writeTo); hash = Hash.hash(rlp); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractMessageProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractMessageProcessor.java index 4de9049952a..e52a1322238 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractMessageProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractMessageProcessor.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.ModificationNotAllowedException; import org.hyperledger.besu.ethereum.vm.EVM; import org.hyperledger.besu.ethereum.vm.MessageFrame; import org.hyperledger.besu.ethereum.vm.OperationTracer; @@ -155,6 +156,8 @@ private void codeExecute(final MessageFrame frame, final OperationTracer operati evm.runToHalt(frame, operationTracer); } catch (final ExceptionalHaltException e) { frame.setState(MessageFrame.State.EXCEPTIONAL_HALT); + } catch (final ModificationNotAllowedException e) { + frame.setState(MessageFrame.State.REVERT); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java new file mode 100644 index 00000000000..913c410dc5c --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java @@ -0,0 +1,142 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import org.hyperledger.besu.ethereum.core.Account; +import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.mainnet.contractvalidation.MaxCodeSizeRule; +import org.hyperledger.besu.ethereum.vm.MessageFrame; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.Optional; +import java.util.OptionalInt; + +import com.google.common.collect.ImmutableSet; + +public class ClassicProtocolSpecs { + + public static final int SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT = 24576; + + private static final Address RIPEMD160_PRECOMPILE = + Address.fromHexString("0x0000000000000000000000000000000000000003"); + + // A consensus bug at Ethereum mainnet transaction 0xcf416c53 + // deleted an empty account even when the message execution scope + // failed, but the transaction itself succeeded. + private static final ImmutableSet
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES = + ImmutableSet.of(RIPEMD160_PRECOMPILE); + + public static ProtocolSpecBuilder tangerineWhistleDefinition( + final Optional chainId, + final OptionalInt contractSizeLimit, + final OptionalInt configStackSizeLimit) { + return MainnetProtocolSpecs.homesteadDefinition(contractSizeLimit, configStackSizeLimit) + .gasCalculator(TangerineWhistleGasCalculator::new) + .transactionValidatorBuilder( + gasCalculator -> new MainnetTransactionValidator(gasCalculator, true, chainId)) + .name("ClassicTangerineWhistle"); + } + + public static ProtocolSpecBuilder dieHardDefinition( + final Optional chainId, + final OptionalInt configContractSizeLimit, + final OptionalInt configStackSizeLimit) { + return tangerineWhistleDefinition(chainId, OptionalInt.empty(), configStackSizeLimit) + .gasCalculator(SpuriousDragonGasCalculator::new) + .name("DieHard"); + } + + public static ProtocolSpecBuilder defuseDifficultyBombDefinition( + final Optional chainId, + final OptionalInt contractSizeLimit, + final OptionalInt configStackSizeLimit) { + return MainnetProtocolSpecs.tangerineWhistleDefinition(contractSizeLimit, configStackSizeLimit) + .difficultyCalculator(MainnetDifficultyCalculators.DIFFICULTY_BOMB_REMOVED) + .transactionValidatorBuilder( + gasCalculator -> new MainnetTransactionValidator(gasCalculator, true, chainId)) + .name("DefuseDifficultyBomb"); + } + + // TODO edwardmack, this is just a place holder definiton, REPLACE with real definition + public static ProtocolSpecBuilder atlantisDefinition( + final Optional chainId, + final OptionalInt configContractSizeLimit, + final OptionalInt configStackSizeLimit) { + final int contractSizeLimit = + configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); + final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); + + return MainnetProtocolSpecs.tangerineWhistleDefinition( + OptionalInt.empty(), configStackSizeLimit) + .gasCalculator(SpuriousDragonGasCalculator::new) + .skipZeroBlockRewards(true) + .messageCallProcessorBuilder( + (evm, precompileContractRegistry) -> + new MainnetMessageCallProcessor( + evm, + precompileContractRegistry, + SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) + .contractCreationProcessorBuilder( + (gasCalculator, evm) -> + new MainnetContractCreationProcessor( + gasCalculator, + evm, + true, + Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), + 1, + SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) + .transactionValidatorBuilder( + gasCalculator -> new MainnetTransactionValidator(gasCalculator, true, chainId)) + .transactionProcessorBuilder( + (gasCalculator, + transactionValidator, + contractCreationProcessor, + messageCallProcessor) -> + new MainnetTransactionProcessor( + gasCalculator, + transactionValidator, + contractCreationProcessor, + messageCallProcessor, + true, + stackSizeLimit, + Account.DEFAULT_VERSION)) + .name("Atlantis"); + } + + // TODO edwardmack, this is just a place holder definiton, REPLACE with real definition + public static ProtocolSpecBuilder aghartaDefinition( + final Optional chainId, + final OptionalInt configContractSizeLimit, + final OptionalInt configStackSizeLimit, + final boolean enableRevertReason) { + final int contractSizeLimit = + configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); + return MainnetProtocolSpecs.constantinopleFixDefinition( + chainId, configContractSizeLimit, configStackSizeLimit, enableRevertReason) + .gasCalculator(IstanbulGasCalculator::new) + .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::istanbul) + .contractCreationProcessorBuilder( + (gasCalculator, evm) -> + new MainnetContractCreationProcessor( + gasCalculator, + evm, + true, + Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), + 1, + SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) + .name("Agharta"); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetDifficultyCalculators.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetDifficultyCalculators.java index 232ff25e727..84fede69ddd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetDifficultyCalculators.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetDifficultyCalculators.java @@ -67,6 +67,17 @@ private MainnetDifficultyCalculators() {} return periodCount > 1 ? adjustForPeriod(periodCount, difficulty) : difficulty; }; + public static DifficultyCalculator DIFFICULTY_BOMB_REMOVED = + (time, parent, protocolContext) -> { + final BigInteger parentDifficulty = difficulty(parent.getDifficulty()); + final BigInteger difficulty = + ensureMinimumDifficulty( + BigInteger.valueOf(Math.max(1 - (time - parent.getTimestamp()) / 10, -99L)) + .multiply(parentDifficulty.divide(DIFFICULTY_BOUND_DIVISOR)) + .add(parentDifficulty)); + return difficulty; + }; + public static DifficultyCalculator BYZANTIUM = (time, parent, protocolContext) -> calculateByzantiumDifficulty(time, parent, BYZANTIUM_FAKE_BLOCK_OFFSET); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java index b91c92b105c..9c3d7ca668a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -165,6 +165,36 @@ public ProtocolSchedule createProtocolSchedule() { config.getEvmStackSize(), isRevertReasonEnabled)); + // specs for Ethereum Classic network + addProtocolSpec( + protocolSchedule, + config.getEcip1015BlockNumber(), + ClassicProtocolSpecs.tangerineWhistleDefinition( + chainId, config.getContractSizeLimit(), config.getEvmStackSize())); + addProtocolSpec( + protocolSchedule, + config.getDieHardBlockNumber(), + ClassicProtocolSpecs.dieHardDefinition( + chainId, config.getContractSizeLimit(), config.getEvmStackSize())); + addProtocolSpec( + protocolSchedule, + config.getDefuseDifficultyBombBlockNumber(), + ClassicProtocolSpecs.defuseDifficultyBombDefinition( + chainId, config.getContractSizeLimit(), config.getEvmStackSize())); + addProtocolSpec( + protocolSchedule, + config.getAtlantisBlockNumber(), + ClassicProtocolSpecs.atlantisDefinition( + chainId, config.getContractSizeLimit(), config.getEvmStackSize())); + addProtocolSpec( + protocolSchedule, + config.getAghartaBlockNumber(), + ClassicProtocolSpecs.aghartaDefinition( + chainId, + config.getContractSizeLimit(), + config.getEvmStackSize(), + isRevertReasonEnabled)); + LOG.info("Protocol schedule created with milestones: {}", protocolSchedule.listMilestones()); return protocolSchedule; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index 6757c8630a0..0b32b21cfa4 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -131,16 +131,6 @@ private Optional process( return Optional.of(new TransactionSimulatorResult(transaction, result)); } - public Optional doesAddressExist(final Address address, final Hash blockHeaderHash) { - final BlockHeader header = blockchain.getBlockHeader(blockHeaderHash).orElse(null); - return doesAddressExist(address, header); - } - - public Optional doesAddressExist(final Address address, final long blockNumber) { - final BlockHeader header = blockchain.getBlockHeader(blockNumber).orElse(null); - return doesAddressExist(address, header); - } - public Optional doesAddressExistAtHead(final Address address) { return doesAddressExist(address, blockchain.getChainHeadHeader()); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutablePrivateWorldStateUpdater.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutablePrivateWorldStateUpdater.java index 4a0152e1096..48bc8293222 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutablePrivateWorldStateUpdater.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutablePrivateWorldStateUpdater.java @@ -60,7 +60,7 @@ public DefaultEvmAccount getAccount(final Address address) { publicAccount.setImmutable(true); return publicAccount; } - return null; + return privateAccount; } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/Pruner.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/Pruner.java index aebd1988304..17460d34d08 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/Pruner.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/Pruner.java @@ -22,34 +22,43 @@ import org.hyperledger.besu.ethereum.core.Hash; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; import com.google.common.annotations.VisibleForTesting; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Pruner { + private static final Logger LOG = LogManager.getLogger(); private final MarkSweepPruner pruningStrategy; private final Blockchain blockchain; - private final ExecutorService executorService; private Long blockAddedObserverId; private final long blocksRetained; - private final AtomicReference state = new AtomicReference<>(State.IDLE); + private final AtomicReference pruningPhase = + new AtomicReference<>(PruningPhase.IDLE); private volatile long markBlockNumber = 0; private volatile BlockHeader markedBlockHeader; private long blockConfirmations; - public Pruner( + private AtomicReference state = new AtomicReference<>(State.IDLE); + private final Supplier executorServiceSupplier; + private ExecutorService executorService; + + @VisibleForTesting + Pruner( final MarkSweepPruner pruningStrategy, final Blockchain blockchain, - final ExecutorService executorService, - final PruningConfiguration pruningConfiguration) { + final PruningConfiguration pruningConfiguration, + final Supplier executorServiceSupplier) { this.pruningStrategy = pruningStrategy; - this.executorService = executorService; this.blockchain = blockchain; + this.executorServiceSupplier = executorServiceSupplier; this.blocksRetained = pruningConfiguration.getBlocksRetained(); this.blockConfirmations = pruningConfiguration.getBlockConfirmations(); checkArgument( @@ -57,17 +66,47 @@ public Pruner( "blockConfirmations and blocksRetained must be non-negative. blockConfirmations must be less than blockRetained."); } + public Pruner( + final MarkSweepPruner pruningStrategy, + final Blockchain blockchain, + final PruningConfiguration pruningConfiguration) { + this(pruningStrategy, blockchain, pruningConfiguration, getDefaultExecutorSupplier()); + } + + private static Supplier getDefaultExecutorSupplier() { + return () -> + Executors.newSingleThreadExecutor( + new ThreadFactoryBuilder() + .setDaemon(true) + .setPriority(Thread.MIN_PRIORITY) + .setNameFormat("StatePruning-%d") + .build()); + } + public void start() { - LOG.info("Starting Pruner."); - pruningStrategy.prepare(); - blockAddedObserverId = - blockchain.observeBlockAdded((event, blockchain) -> handleNewBlock(event)); + + if (state.compareAndSet(State.IDLE, State.RUNNING)) { + LOG.info("Starting Pruner."); + executorService = executorServiceSupplier.get(); + pruningStrategy.prepare(); + blockAddedObserverId = + blockchain.observeBlockAdded((event, blockchain) -> handleNewBlock(event)); + } } - public void stop() throws InterruptedException { - pruningStrategy.cleanup(); - blockchain.removeObserver(blockAddedObserverId); - executorService.awaitTermination(10, TimeUnit.SECONDS); + public void stop() { + if (state.compareAndSet(State.RUNNING, State.STOPPED)) { + LOG.info("Stopping Pruner."); + pruningStrategy.cleanup(); + blockchain.removeObserver(blockAddedObserverId); + executorService.shutdownNow(); + } + } + + public void awaitStop() throws InterruptedException { + if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) { + LOG.error("Failed to shutdown Pruner executor service."); + } } private void handleNewBlock(final BlockAddedEvent event) { @@ -76,15 +115,17 @@ private void handleNewBlock(final BlockAddedEvent event) { } final long blockNumber = event.getBlock().getHeader().getNumber(); - if (state.compareAndSet(State.IDLE, State.MARK_BLOCK_CONFIRMATIONS_AWAITING)) { + if (pruningPhase.compareAndSet( + PruningPhase.IDLE, PruningPhase.MARK_BLOCK_CONFIRMATIONS_AWAITING)) { markBlockNumber = blockNumber; } else if (blockNumber >= markBlockNumber + blockConfirmations - && state.compareAndSet(State.MARK_BLOCK_CONFIRMATIONS_AWAITING, State.MARKING)) { + && pruningPhase.compareAndSet( + PruningPhase.MARK_BLOCK_CONFIRMATIONS_AWAITING, PruningPhase.MARKING)) { markedBlockHeader = blockchain.getBlockHeader(markBlockNumber).get(); mark(markedBlockHeader); } else if (blockNumber >= markBlockNumber + blocksRetained && blockchain.blockIsOnCanonicalChain(markedBlockHeader.getHash()) - && state.compareAndSet(State.MARKING_COMPLETE, State.SWEEPING)) { + && pruningPhase.compareAndSet(PruningPhase.MARKING_COMPLETE, PruningPhase.SWEEPING)) { sweep(); } } @@ -98,7 +139,7 @@ private void mark(final BlockHeader header) { execute( () -> { pruningStrategy.mark(stateRoot); - state.compareAndSet(State.MARKING, State.MARKING_COMPLETE); + pruningPhase.compareAndSet(PruningPhase.MARKING, PruningPhase.MARKING_COMPLETE); }); } @@ -110,7 +151,7 @@ private void sweep() { execute( () -> { pruningStrategy.sweepBefore(markBlockNumber); - state.compareAndSet(State.SWEEPING, State.IDLE); + pruningPhase.compareAndSet(PruningPhase.SWEEPING, PruningPhase.IDLE); }); } @@ -120,20 +161,26 @@ private void execute(final Runnable action) { } catch (final Throwable t) { LOG.error("Pruning failed", t); pruningStrategy.cleanup(); - state.set(State.IDLE); + pruningPhase.set(PruningPhase.IDLE); } } @VisibleForTesting - State getState() { - return state.get(); + PruningPhase getPruningPhase() { + return pruningPhase.get(); } - enum State { + enum PruningPhase { IDLE, MARK_BLOCK_CONFIRMATIONS_AWAITING, MARKING, MARKING_COMPLETE, SWEEPING; } + + private enum State { + IDLE, + RUNNING, + STOPPED + } } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java index 020aafa509d..f58a4b38dff 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java @@ -35,13 +35,16 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.OptionalLong; import java.util.Random; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.IntStream; +import java.util.stream.Stream; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; @@ -203,11 +206,14 @@ public List blockSequence( } public Block genesisBlock() { - final BlockOptions options = - new BlockOptions() - .setBlockNumber(BlockHeader.GENESIS_BLOCK_NUMBER) - .setStateRoot(Hash.EMPTY_TRIE_HASH) - .setParentHash(Hash.ZERO); + return genesisBlock(new BlockOptions()); + } + + public Block genesisBlock(final BlockOptions options) { + options + .setBlockNumber(BlockHeader.GENESIS_BLOCK_NUMBER) + .setStateRoot(Hash.EMPTY_TRIE_HASH) + .setParentHash(Hash.ZERO); return block(options); } @@ -349,6 +355,10 @@ public TransactionReceipt receipt() { return receipt(positiveLong()); } + public TransactionReceipt receipt(final List logs) { + return new TransactionReceipt(hash(), positiveLong(), logs, Optional.empty()); + } + public UInt256 storageKey() { return uint256(); } @@ -365,8 +375,22 @@ public List receipts(final Block block) { return receipts; } + public List logs(final int logsCount, final int topicsPerLog) { + return Stream.generate(() -> log(topicsPerLog)).limit(logsCount).collect(Collectors.toList()); + } + public Log log() { - return new Log(address(), bytesValue(5 + random.nextInt(10)), Collections.emptyList()); + return log(0); + } + + public Log log(final int topicCount) { + final List topics = + Stream.generate(this::logTopic).limit(topicCount).collect(Collectors.toList()); + return new Log(address(), bytesValue(5, 15), topics); + } + + private LogTopic logTopic() { + return LogTopic.create(bytesValue(LogTopic.SIZE)); } private Bytes32 bytes32() { @@ -377,6 +401,18 @@ public BytesValue bytesValue(final int size) { return BytesValue.wrap(bytes(size)); } + public BytesValue bytesValue() { + return bytesValue(1, 20); + } + + public BytesValue bytesValue(final int minSize, final int maxSize) { + checkArgument(minSize >= 0); + checkArgument(maxSize >= 0); + checkArgument(maxSize > minSize); + final int size = random.nextInt(maxSize - minSize) + minSize; + return BytesValue.wrap(bytes(size)); + } + /** * Creates a UInt256 with a value that fits within maxByteSize * @@ -409,18 +445,6 @@ public LogsBloomFilter logsBloom() { return new LogsBloomFilter(BytesValue.of(bytes(LogsBloomFilter.BYTE_SIZE))); } - public BytesValue bytesValue() { - return bytesValue(1, 20); - } - - public BytesValue bytesValue(final int minSize, final int maxSize) { - checkArgument(minSize >= 0); - checkArgument(maxSize >= 0); - checkArgument(maxSize > minSize); - final int size = random.nextInt(maxSize - minSize) + minSize; - return BytesValue.wrap(bytes(size)); - } - private byte[] bytes(final int size) { return bytes(size, 0); } @@ -463,7 +487,7 @@ public static class BlockOptions { private Optional parentHash = Optional.empty(); private Optional stateRoot = Optional.empty(); private Optional difficulty = Optional.empty(); - private Optional> transactions = Optional.empty(); + private List transactions = new ArrayList<>(); private Optional extraData = Optional.empty(); private Optional blockHeaderFunctions = Optional.empty(); @@ -472,7 +496,7 @@ public static BlockOptions create() { } public List getTransactions(final List defaultValue) { - return transactions.orElse(defaultValue); + return transactions.isEmpty() ? defaultValue : transactions; } public long getBlockNumber(final long defaultValue) { @@ -500,13 +524,14 @@ public BlockHeaderFunctions getBlockHeaderFunctions(final BlockHeaderFunctions d } public BlockOptions addTransaction(final Transaction... tx) { - if (!transactions.isPresent()) { - transactions = Optional.of(new ArrayList<>()); - } - transactions.get().addAll(Arrays.asList(tx)); + transactions.addAll(Arrays.asList(tx)); return this; } + public BlockOptions addTransaction(final Collection txs) { + return addTransaction(txs.toArray(new Transaction[] {})); + } + public BlockOptions setBlockNumber(final long blockNumber) { this.blockNumber = OptionalLong.of(blockNumber); return this; diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/NonBesuBlockHeader.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/NonBesuBlockHeader.java new file mode 100644 index 00000000000..b564a0eee26 --- /dev/null +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/NonBesuBlockHeader.java @@ -0,0 +1,113 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core; + +import org.hyperledger.besu.plugin.data.Address; +import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.Hash; +import org.hyperledger.besu.plugin.data.Quantity; +import org.hyperledger.besu.plugin.data.UnformattedData; +import org.hyperledger.besu.util.bytes.BytesValue; + +public class NonBesuBlockHeader implements BlockHeader { + + final Hash blockHash; + final BytesValue extraData; + + public NonBesuBlockHeader(final Hash blockHash, final BytesValue extraData) { + this.blockHash = blockHash; + this.extraData = extraData; + } + + @Override + public Hash getParentHash() { + return null; + } + + @Override + public Hash getOmmersHash() { + return null; + } + + @Override + public Address getCoinbase() { + return null; + } + + @Override + public Hash getStateRoot() { + return null; + } + + @Override + public Hash getTransactionsRoot() { + return null; + } + + @Override + public Hash getReceiptsRoot() { + return null; + } + + @Override + public UnformattedData getLogsBloom() { + return null; + } + + @Override + public Quantity getDifficulty() { + return null; + } + + @Override + public long getNumber() { + return 0; + } + + @Override + public long getGasLimit() { + return 0; + } + + @Override + public long getGasUsed() { + return 0; + } + + @Override + public long getTimestamp() { + return 0; + } + + @Override + public UnformattedData getExtraData() { + return extraData; + } + + @Override + public Hash getMixHash() { + return null; + } + + @Override + public long getNonce() { + return 0; + } + + @Override + public Hash getBlockHash() { + return blockHash; + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java index 16782898418..7ec4c028fb2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -38,6 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; +import com.google.common.collect.Lists; import org.junit.Test; public class DefaultBlockchainTest { @@ -156,9 +158,16 @@ public void appendBlock() { final BlockDataGenerator.BlockOptions options = new BlockDataGenerator.BlockOptions() .setBlockNumber(1L) + .addTransaction(gen.transactions(5)) .setParentHash(genesisBlock.getHash()); final Block newBlock = gen.block(options); final List receipts = gen.receipts(newBlock); + blockchain.observeBlockAdded( + ((event, blockchain1) -> + assertThat(event.getLogsWithMetadata()) + .containsExactly( + LogWithMetadata.generate(newBlock, receipts, false) + .toArray(new LogWithMetadata[] {})))); blockchain.appendBlock(newBlock, receipts); assertBlockIsHead(blockchain, newBlock); @@ -226,15 +235,25 @@ public void createSmallChain() { public void appendBlockWithReorgToChainAtEqualHeight() { final BlockDataGenerator gen = new BlockDataGenerator(1); - // Setup an initial blockchain + // Setup final int chainLength = 3; final List chain = gen.blockSequence(chainLength); final List> blockReceipts = chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); + List expectedLogsWithMetadata = new ArrayList<>(); + + // Add initial blocks for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } assertThat(blockchain.getForks()).isEmpty(); final Block originalHead = chain.get(chainLength - 1); @@ -264,9 +283,18 @@ public void appendBlockWithReorgToChainAtEqualHeight() { } // Check old transactions have been removed for (final Transaction tx : originalHead.getBody().getTransactions()) { - assertThat(blockchain.getTransactionByHash(tx.hash())).isNotPresent(); + assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); } + // LogWithMetadata reflecting removal of originalHead's logs + final List removedLogs = + Lists.reverse( + LogWithMetadata.generate( + originalHead, blockchain.getTxReceipts(originalHead.getHash()).get(), true)); + expectedLogsWithMetadata.addAll(removedLogs); + // LogWithMetadata reflecting addition of originalHead's logs + expectedLogsWithMetadata.addAll(LogWithMetadata.generate(fork, forkReceipts, false)); + assertBlockIsHead(blockchain, fork); assertTotalDifficultiesAreConsistent(blockchain, fork); // Old chain head should now be tracked as a fork. @@ -277,6 +305,8 @@ public void appendBlockWithReorgToChainAtEqualHeight() { for (int i = commonAncestor + 1; i < chainLength; i++) { assertThat(blockchain.blockIsOnCanonicalChain(chain.get(i).getHash())).isFalse(); } + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test @@ -290,8 +320,15 @@ public void appendBlockWithReorgToShorterChain() { chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); + List expectedLogsWithMetadata = new ArrayList<>(); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } final Block originalHead = chain.get(originalChainLength - 1); @@ -340,7 +377,7 @@ public void appendBlockWithReorgToShorterChain() { assertTotalDifficultiesAreConsistent(blockchain, originalHead); // Check transactions were not indexed for (final Transaction tx : forkBlocks.get(0).getBody().getTransactions()) { - assertThat(blockchain.getTransactionByHash(tx.hash())).isNotPresent(); + assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); } // Appended block should be tracked as a fork assertThat(blockchain.blockIsOnCanonicalChain(forkBlocks.get(0).getHash())).isFalse(); @@ -362,7 +399,20 @@ public void appendBlockWithReorgToShorterChain() { removedTransactions.addAll(chain.get(i).getBody().getTransactions()); } for (final Transaction tx : removedTransactions) { - assertThat(blockchain.getTransactionByHash(tx.hash())).isNotPresent(); + assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); + } + // LogWithMetadata reflecting removal of logs + for (int i = originalChainLength - 1; i >= forkStart; i--) { + final Block currentBlock = chain.get(i); + expectedLogsWithMetadata.addAll( + Lists.reverse( + LogWithMetadata.generate( + currentBlock, blockchain.getTxReceipts(currentBlock.getHash()).get(), true))); + } + // LogWithMetadata reflecting addition of logs + for (int i = 0; i < forkBlocks.size(); i++) { + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(forkBlocks.get(i), forkReceipts.get(i), false)); } // Check that blockNumber index for previous chain head has been removed @@ -375,6 +425,8 @@ public void appendBlockWithReorgToShorterChain() { for (int i = commonAncestor + 1; i < originalChainLength; i++) { assertThat(blockchain.blockIsOnCanonicalChain(chain.get(i).getHash())).isFalse(); } + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test @@ -388,8 +440,15 @@ public void appendBlockWithReorgToLongerChain() { chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); + List expectedLogsWithMetadata = new ArrayList<>(); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } final Block originalHead = chain.get(originalChainLength - 1); @@ -432,7 +491,7 @@ public void appendBlockWithReorgToLongerChain() { assertTotalDifficultiesAreConsistent(blockchain, originalHead); // Check transactions were not indexed for (final Transaction tx : forkBlocks.get(0).getBody().getTransactions()) { - assertThat(blockchain.getTransactionByHash(tx.hash())).isNotPresent(); + assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); } // Appended block should be tracked as a fork assertThat(blockchain.blockIsOnCanonicalChain(forkBlocks.get(0).getHash())).isFalse(); @@ -454,7 +513,20 @@ public void appendBlockWithReorgToLongerChain() { removedTransactions.addAll(chain.get(i).getBody().getTransactions()); } for (final Transaction tx : removedTransactions) { - assertThat(blockchain.getTransactionByHash(tx.hash())).isNotPresent(); + assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); + } + // LogWithMetadata reflecting removal of logs + for (int i = originalChainLength - 1; i >= forkStart; i--) { + final Block currentBlock = chain.get(i); + expectedLogsWithMetadata.addAll( + Lists.reverse( + LogWithMetadata.generate( + currentBlock, blockchain.getTxReceipts(currentBlock.getHash()).get(), true))); + } + // LogWithMetadata reflecting addition of logs + for (int i = 0; i < forkBlocks.size(); i++) { + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(forkBlocks.get(i), forkReceipts.get(i), false)); } // Old chain head should now be tracked as a fork. forks = blockchain.getForks(); @@ -464,6 +536,8 @@ public void appendBlockWithReorgToLongerChain() { for (int i = commonAncestor + 1; i < originalChainLength; i++) { assertThat(blockchain.blockIsOnCanonicalChain(chain.get(i).getHash())).isFalse(); } + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test @@ -477,8 +551,15 @@ public void reorgWithOverlappingTransactions() { chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); + List expectedLogsWithMetadata = new ArrayList<>(); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } final Transaction overlappingTx = chain.get(chainLength - 1).getBody().getTransactions().get(0); @@ -510,13 +591,25 @@ public void reorgWithOverlappingTransactions() { // Check old transactions have been removed for (final Transaction tx : chain.get(chainLength - 1).getBody().getTransactions()) { - final Optional actualTransaction = blockchain.getTransactionByHash(tx.hash()); + final Optional actualTransaction = blockchain.getTransactionByHash(tx.getHash()); if (tx.equals(overlappingTx)) { assertThat(actualTransaction).isPresent(); } else { assertThat(actualTransaction).isNotPresent(); } } + // LogWithMetadata reflecting removal of logs + for (int i = chainLength - 1; i >= forkBlock; i--) { + final Block currentBlock = chain.get(i); + expectedLogsWithMetadata.addAll( + Lists.reverse( + LogWithMetadata.generate( + currentBlock, blockchain.getTxReceipts(currentBlock.getHash()).get(), true))); + } + // LogWithMetadata reflecting addition of logs + expectedLogsWithMetadata.addAll(LogWithMetadata.generate(fork, forkReceipts, false)); + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test @@ -548,7 +641,7 @@ public void rewindChain() { // Check transactions were not indexed for (final Transaction tx : originalHead.getBody().getTransactions()) { - assertThat(blockchain.getTransactionByHash(tx.hash())).isNotPresent(); + assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); } // Check that blockNumber index for previous chain head has been removed @@ -569,8 +662,15 @@ public void appendBlockForFork() { chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); + List expectedLogsWithMetadata = new ArrayList<>(); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } final Block originalHead = chain.get(originalChainLength - 1); @@ -608,7 +708,7 @@ public void appendBlockForFork() { assertTotalDifficultiesAreConsistent(blockchain, originalHead); // Check transactions were not indexed for (final Transaction tx : forkBlock.getBody().getTransactions()) { - assertThat(blockchain.getTransactionByHash(tx.hash())).isNotPresent(); + assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); } // Appended block should be tracked as a fork assertThat(blockchain.blockIsOnCanonicalChain(forkBlock.getHash())).isFalse(); @@ -638,6 +738,9 @@ public void appendBlockForFork() { // Head should not have changed assertBlockIsHead(blockchain, originalHead); + // We should only have the log events from when we initially created the chain. None from forks. + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test @@ -775,7 +878,7 @@ private void assertBlockDataIsStored( final List txs = block.getBody().getTransactions(); for (int i = 0; i < txs.size(); i++) { final Transaction expected = txs.get(i); - final Transaction actual = blockchain.getTransactionByHash(expected.hash()).get(); + final Transaction actual = blockchain.getTransactionByHash(expected.getHash()).get(); assertThat(actual).isEqualTo(expected); } final List actualReceipts = blockchain.getTxReceipts(hash).get(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java index 8d02dceb0e3..4fa1dbb3ccc 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java @@ -120,7 +120,7 @@ public void milestone(final String milestone) { assertThat(actualRlp).isEqualTo(rlp); assertThat(transaction.getSender()).isEqualTo(expected.getSender()); - assertThat(transaction.hash()).isEqualTo(expected.getHash()); + assertThat(transaction.getHash()).isEqualTo(expected.getHash()); } catch (final Exception e) { assertThat(expected.isSucceeds()).isFalse(); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java index d33be49374e..b00e11836a8 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java @@ -42,8 +42,8 @@ public void shouldReturnDefaultProtocolSpecsWhenCustomNumbersAreNotUsed() { Assertions.assertThat(sched.getByBlockNumber(7_080_000L).getName()).isEqualTo("Byzantium"); Assertions.assertThat(sched.getByBlockNumber(7_280_000L).getName()) .isEqualTo("ConstantinopleFix"); - Assertions.assertThat(sched.getByBlockNumber(Long.MAX_VALUE).getName()) - .isEqualTo("ConstantinopleFix"); + Assertions.assertThat(sched.getByBlockNumber(9_069_000L).getName()).isEqualTo("Istanbul"); + Assertions.assertThat(sched.getByBlockNumber(Long.MAX_VALUE).getName()).isEqualTo("Istanbul"); } @Test diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/PrunerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/PrunerTest.java index b60fd543481..d155d06e660 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/PrunerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/PrunerTest.java @@ -37,6 +37,7 @@ import java.util.List; import java.util.concurrent.ExecutorService; +import java.util.function.Supplier; import org.junit.Test; import org.junit.runner.RunWith; @@ -52,11 +53,12 @@ public class PrunerTest { @Mock private MarkSweepPruner markSweepPruner; private final ExecutorService mockExecutorService = new MockExecutorService(); + private final Supplier mockExecutorServiceSupplier = () -> mockExecutorService; private final Block genesisBlock = gen.genesisBlock(); @Test - public void shouldMarkCorrectBlockAndSweep() throws InterruptedException { + public void shouldMarkCorrectBlockAndSweep() { final BlockchainStorage blockchainStorage = new KeyValueStoragePrefixedKeyBlockchainStorage( new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); @@ -65,7 +67,10 @@ public void shouldMarkCorrectBlockAndSweep() throws InterruptedException { final Pruner pruner = new Pruner( - markSweepPruner, blockchain, mockExecutorService, new PruningConfiguration(0, 1)); + markSweepPruner, + blockchain, + new PruningConfiguration(0, 1), + mockExecutorServiceSupplier); pruner.start(); final Block block1 = appendBlockWithParent(blockchain, genesisBlock); @@ -78,8 +83,7 @@ public void shouldMarkCorrectBlockAndSweep() throws InterruptedException { } @Test - public void shouldOnlySweepAfterBlockConfirmationPeriodAndRetentionPeriodEnds() - throws InterruptedException { + public void shouldOnlySweepAfterBlockConfirmationPeriodAndRetentionPeriodEnds() { final BlockchainStorage blockchainStorage = new KeyValueStoragePrefixedKeyBlockchainStorage( new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); @@ -88,7 +92,10 @@ public void shouldOnlySweepAfterBlockConfirmationPeriodAndRetentionPeriodEnds() final Pruner pruner = new Pruner( - markSweepPruner, blockchain, mockExecutorService, new PruningConfiguration(1, 2)); + markSweepPruner, + blockchain, + new PruningConfiguration(1, 2), + mockExecutorServiceSupplier); pruner.start(); final Hash markBlockStateRootHash = @@ -106,8 +113,7 @@ public void shouldOnlySweepAfterBlockConfirmationPeriodAndRetentionPeriodEnds() } @Test - public void abortsPruningWhenFullyMarkedBlockNoLongerOnCanonicalChain() - throws InterruptedException { + public void abortsPruningWhenFullyMarkedBlockNoLongerOnCanonicalChain() { final BlockchainStorage blockchainStorage = new KeyValueStoragePrefixedKeyBlockchainStorage( new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); @@ -117,7 +123,10 @@ public void abortsPruningWhenFullyMarkedBlockNoLongerOnCanonicalChain() // start pruner so it can start handling block added events final Pruner pruner = new Pruner( - markSweepPruner, blockchain, mockExecutorService, new PruningConfiguration(0, 1)); + markSweepPruner, + blockchain, + new PruningConfiguration(0, 1), + mockExecutorServiceSupplier); pruner.start(); /* @@ -156,24 +165,24 @@ public void shouldRejectInvalidArguments() { new Pruner( markSweepPruner, mockchain, - mockExecutorService, - new PruningConfiguration(-1, -2))) + new PruningConfiguration(-1, -2), + mockExecutorServiceSupplier)) .isInstanceOf(IllegalArgumentException.class); assertThatThrownBy( () -> new Pruner( markSweepPruner, mockchain, - mockExecutorService, - new PruningConfiguration(10, 8))) + new PruningConfiguration(10, 8), + mockExecutorServiceSupplier)) .isInstanceOf(IllegalArgumentException.class); assertThatThrownBy( () -> new Pruner( markSweepPruner, mockchain, - mockExecutorService, - new PruningConfiguration(10, 10))) + new PruningConfiguration(10, 10), + mockExecutorServiceSupplier)) .isInstanceOf(IllegalArgumentException.class); } @@ -187,7 +196,10 @@ public void shouldCleanUpPruningStrategyOnShutdown() throws InterruptedException final Pruner pruner = new Pruner( - markSweepPruner, blockchain, mockExecutorService, new PruningConfiguration(0, 1)); + markSweepPruner, + blockchain, + new PruningConfiguration(0, 1), + mockExecutorServiceSupplier); pruner.start(); pruner.stop(); verify(markSweepPruner).cleanup(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/StateTrieAccountValueTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/StateTrieAccountValueTest.java new file mode 100644 index 00000000000..45ca4245c08 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/StateTrieAccountValueTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.worldstate; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.Wei; +import org.hyperledger.besu.ethereum.rlp.RLP; +import org.hyperledger.besu.ethereum.rlp.RLPInput; +import org.hyperledger.besu.util.bytes.BytesValue; + +import org.junit.Test; + +public class StateTrieAccountValueTest { + + @Test + public void roundTripMainNetAccountValueVersionZero() { + final long nonce = 0; + final Wei balance = Wei.ZERO; + // Have the storageRoot and codeHash as different values to ensure the encode / decode + // doesn't cross the values over. + final Hash storageRoot = Hash.EMPTY_TRIE_HASH; + final Hash codeHash = Hash.EMPTY_LIST_HASH; + final int version = 0; + + roundTripMainNetAccountValue(nonce, balance, storageRoot, codeHash, version); + } + + @Test + public void roundTripMainNetAccountValueVersionNotZero() { + final long nonce = 0; + final Wei balance = Wei.ZERO; + final Hash storageRoot = Hash.EMPTY_TRIE_HASH; + final Hash codeHash = Hash.EMPTY_LIST_HASH; + final int version = 1; + + roundTripMainNetAccountValue(nonce, balance, storageRoot, codeHash, version); + } + + @Test + public void roundTripMainNetAccountValueMax() { + final long nonce = (Long.MAX_VALUE >> 1); + final Wei balance = + Wei.fromHexString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + final Hash storageRoot = Hash.EMPTY_TRIE_HASH; + final Hash codeHash = Hash.EMPTY_LIST_HASH; + final int version = Integer.MAX_VALUE; + + roundTripMainNetAccountValue(nonce, balance, storageRoot, codeHash, version); + } + + private void roundTripMainNetAccountValue( + final long nonce, + final Wei balance, + final Hash storageRoot, + final Hash codeHash, + final int version) { + + StateTrieAccountValue accountValue = + new StateTrieAccountValue(nonce, balance, storageRoot, codeHash, version); + BytesValue encoded = RLP.encode(accountValue::writeTo); + final RLPInput in = RLP.input(encoded); + StateTrieAccountValue roundTripAccountValue = StateTrieAccountValue.readFrom(in); + + assertThat(nonce).isEqualTo(roundTripAccountValue.getNonce()); + assertThat(balance).isEqualTo(roundTripAccountValue.getBalance()); + assertThat(storageRoot).isEqualTo(roundTripAccountValue.getStorageRoot()); + assertThat(codeHash).isEqualTo(roundTripAccountValue.getCodeHash()); + assertThat(version).isEqualTo(roundTripAccountValue.getVersion()); + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainHeadEstimate.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainHeadEstimate.java new file mode 100644 index 00000000000..462cc31eb26 --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainHeadEstimate.java @@ -0,0 +1,46 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.eth.manager; + +import org.hyperledger.besu.ethereum.chain.ChainHead; +import org.hyperledger.besu.util.uint.UInt256; + +public interface ChainHeadEstimate { + + UInt256 getEstimatedTotalDifficulty(); + + long getEstimatedHeight(); + + /** + * Returns true if this chain state represents a chain that is "better" than the chain represented + * by the supplied {@link ChainHead}. "Better" currently means that this chain is longer or + * heavier than the supplied {@code chainToCheck}. + * + * @param chainToCheck The chain being compared. + * @return true if this {@link ChainState} represents a better chain than {@code chainToCheck}. + */ + default boolean chainIsBetterThan(final ChainHead chainToCheck) { + return hasHigherDifficultyThan(chainToCheck) || hasLongerChainThan(chainToCheck); + } + + default boolean hasHigherDifficultyThan(final ChainHead chainToCheck) { + return getEstimatedTotalDifficulty().compareTo(chainToCheck.getTotalDifficulty()) > 0; + } + + default boolean hasLongerChainThan(final ChainHead chainToCheck) { + return getEstimatedHeight() > chainToCheck.getHeight(); + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainState.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainState.java index d8e076760d0..33924780673 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainState.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainState.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.eth.manager; -import org.hyperledger.besu.ethereum.chain.ChainHead; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.util.Subscribers; @@ -22,7 +21,7 @@ import com.google.common.base.MoreObjects; -public class ChainState { +public class ChainState implements ChainHeadEstimate { // The best block by total difficulty that we know about private final BestBlock bestBlock = new BestBlock(); // The highest block that we've seen @@ -40,14 +39,20 @@ public void removeEstimatedHeightListener(final long listenerId) { estimatedHeightListeners.unsubscribe(listenerId); } + public ChainStateSnapshot getSnapshot() { + return new ChainStateSnapshot(getEstimatedTotalDifficulty(), getEstimatedHeight()); + } + public boolean hasEstimatedHeight() { return estimatedHeightKnown; } + @Override public long getEstimatedHeight() { return estimatedHeight; } + @Override public UInt256 getEstimatedTotalDifficulty() { return bestBlock.getTotalDifficulty(); } @@ -98,34 +103,14 @@ public void updateForAnnouncedBlock( public void updateHeightEstimate(final long blockNumber) { synchronized (this) { - estimatedHeightKnown = true; if (blockNumber > estimatedHeight) { + estimatedHeightKnown = true; estimatedHeight = blockNumber; estimatedHeightListeners.forEach(e -> e.onEstimatedHeightChanged(estimatedHeight)); } } } - /** - * Returns true if this chain state represents a chain that is "better" than the chain represented - * by the supplied {@link ChainHead}. "Better" currently means that this chain is longer or - * heavier than the supplied {@code chainToCheck}. - * - * @param chainToCheck The chain being compared. - * @return true if this {@link ChainState} represents a better chain than {@code chainToCheck}. - */ - public boolean chainIsBetterThan(final ChainHead chainToCheck) { - return hasHigherDifficultyThan(chainToCheck) || hasLongerChainThan(chainToCheck); - } - - private boolean hasHigherDifficultyThan(final ChainHead chainToCheck) { - return bestBlock.getTotalDifficulty().compareTo(chainToCheck.getTotalDifficulty()) > 0; - } - - private boolean hasLongerChainThan(final ChainHead chainToCheck) { - return estimatedHeight > chainToCheck.getHeight(); - } - @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateSnapshot.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateSnapshot.java new file mode 100644 index 00000000000..bdfe8848355 --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateSnapshot.java @@ -0,0 +1,38 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.eth.manager; + +import org.hyperledger.besu.util.uint.UInt256; + +public class ChainStateSnapshot implements ChainHeadEstimate { + private final UInt256 totalDifficulty; + private final long chainHeight; + + public ChainStateSnapshot(final UInt256 totalDifficulty, final long chainHeight) { + this.totalDifficulty = totalDifficulty; + this.chainHeight = chainHeight; + } + + @Override + public UInt256 getEstimatedTotalDifficulty() { + return totalDifficulty; + } + + @Override + public long getEstimatedHeight() { + return chainHeight; + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java index 3adf56f28ef..1fd0174587e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java @@ -326,10 +326,16 @@ public boolean hasSeenBlock(final Hash hash) { return knownBlocks.contains(hash); } + /** @return This peer's current chain state. */ public ChainState chainState() { return chainHeadState; } + /** @return A read-only snapshot of this peer's current {@code chainState} } */ + public ChainHeadEstimate chainStateSnapshot() { + return chainHeadState.getSnapshot(); + } + public void registerHeight(final Hash blockHash, final long height) { chainHeadState.update(blockHash, height); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index 5b38a8db2a4..01243e12fa3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -211,6 +211,12 @@ public void processMessage(final Capability cap, final Message message) { return; } else if (!peer.statusHasBeenReceived()) { // Peers are required to send status messages before any other message type + LOG.debug( + "{} requires a Status ({}) message to be sent first. Instead, received message {}. Disconnecting from {}.", + this.getClass().getSimpleName(), + EthPV62.STATUS, + message.getData().getCode(), + peer); peer.disconnect(DisconnectReason.BREACH_OF_PROTOCOL); return; } @@ -218,7 +224,7 @@ public void processMessage(final Capability cap, final Message message) { // Dispatch eth message final EthMessage ethMessage = new EthMessage(peer, message.getData()); if (!peer.validateReceivedMessage(ethMessage)) { - LOG.warn("Unsolicited message received from {}, disconnecting", peer); + LOG.debug("Unsolicited message received from, disconnecting: {}", peer); peer.disconnect(DisconnectReason.BREACH_OF_PROTOCOL); return; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java index 3bbb1b1388c..d43b6015636 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java @@ -84,6 +84,8 @@ private void handleGetBlockHeaders(final EthMessage message) { ethereumWireProtocolConfiguration.getMaxGetBlockHeaders()); message.getPeer().send(response); } catch (final RLPException e) { + LOG.debug( + "Received malformed GET_BLOCK_HEADERS message, disconnecting: {}", message.getPeer(), e); message.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); } catch (final PeerNotConnected peerNotConnected) { // Peer disconnected before we could respond - nothing to do @@ -100,6 +102,8 @@ private void handleGetBlockBodies(final EthMessage message) { ethereumWireProtocolConfiguration.getMaxGetBlockBodies()); message.getPeer().send(response); } catch (final RLPException e) { + LOG.debug( + "Received malformed GET_BLOCK_BODIES message, disconnecting: {}", message.getPeer(), e); message.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); } catch (final PeerNotConnected peerNotConnected) { // Peer disconnected before we could respond - nothing to do @@ -114,6 +118,7 @@ private void handleGetReceipts(final EthMessage message) { blockchain, message.getData(), ethereumWireProtocolConfiguration.getMaxGetReceipts()); message.getPeer().send(response); } catch (final RLPException e) { + LOG.debug("Received malformed GET_RECEIPTS message, disconnecting: {}", message.getPeer(), e); message.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); } catch (final PeerNotConnected peerNotConnected) { // Peer disconnected before we could respond - nothing to do @@ -130,6 +135,8 @@ private void handleGetNodeData(final EthMessage message) { ethereumWireProtocolConfiguration.getMaxGetNodeData()); message.getPeer().send(response); } catch (final RLPException e) { + LOG.debug( + "Received malformed GET_NODE_DATA message, disconnecting: {}", message.getPeer(), e); message.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); } catch (final PeerNotConnected peerNotConnected) { // Peer disconnected before we could respond - nothing to do diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java index 8fa5a734c93..bbe716a3864 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java @@ -31,7 +31,11 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeoutException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public abstract class AbstractPeerRequestTask extends AbstractPeerTask { + private static final Logger LOG = LogManager.getLogger(); private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5); private Duration timeout = DEFAULT_TIMEOUT; @@ -100,6 +104,7 @@ private void handleMessage( result.ifPresent(promise::complete); } catch (final RLPException e) { // Peer sent us malformed data - disconnect + LOG.debug("Disconnecting with BREACH_OF_PROTOCOL due to malformed message: {}", peer, e); peer.disconnect(DisconnectReason.BREACH_OF_PROTOCOL); promise.completeExceptionally(new PeerBreachedProtocolException()); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockBroadcaster.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockBroadcaster.java index 768af0f3996..df63664ea47 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockBroadcaster.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockBroadcaster.java @@ -21,8 +21,6 @@ import org.hyperledger.besu.util.Subscribers; import org.hyperledger.besu.util.uint.UInt256; -import java.util.function.Consumer; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -30,13 +28,14 @@ public class BlockBroadcaster { private static final Logger LOG = LogManager.getLogger(); private final EthContext ethContext; - private final Subscribers> blockPropagatedSubscribers = Subscribers.create(); + private final Subscribers blockPropagatedSubscribers = + Subscribers.create(); public BlockBroadcaster(final EthContext ethContext) { this.ethContext = ethContext; } - public long subscribePropagateNewBlocks(final Consumer callback) { + public long subscribePropagateNewBlocks(final BlockPropagatedSubscriber callback) { return blockPropagatedSubscribers.subscribe(callback); } @@ -45,7 +44,7 @@ public void unsubscribePropagateNewBlocks(final long id) { } public void propagate(final Block block, final UInt256 totalDifficulty) { - blockPropagatedSubscribers.forEach(listener -> listener.accept(block)); + blockPropagatedSubscribers.forEach(listener -> listener.accept(block, totalDifficulty)); final NewBlockMessage newBlockMessage = NewBlockMessage.create(block, totalDifficulty); ethContext .getEthPeers() @@ -61,4 +60,9 @@ public void propagate(final Block block, final UInt256 totalDifficulty) { } }); } + + @FunctionalInterface + public interface BlockPropagatedSubscriber { + void accept(Block block, UInt256 totalDifficulty); + } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index 24ea2dfe411..b87097bfec6 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -175,6 +175,10 @@ private void handleNewBlockFromNetwork(final EthMessage message) { importOrSavePendingBlock(block); } catch (final RLPException e) { + LOG.debug( + "Malformed NEW_BLOCK message received from peer, disconnecting: {}", + message.getPeer(), + e); message.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); } } @@ -226,6 +230,10 @@ private void handleNewBlockHashesFromNetwork(final EthMessage message) { .whenComplete((r, t) -> requestedBlocks.remove(newBlock.hash())); } } catch (final RLPException e) { + LOG.debug( + "Malformed NEW_BLOCK_HASHES message received from peer, disconnecting: {}", + message.getPeer(), + e); message.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTracker.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTracker.java index b2b444f01de..25364146ea6 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTracker.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTracker.java @@ -83,7 +83,8 @@ public void onPeerConnected(final EthPeer peer) { peer.chainState().update(chainHeadHeader); trailingPeerLimiter.enforceTrailingPeerLimit(); } else { - LOG.debug("Failed to retrieve chain head information for " + peer, error); + LOG.debug( + "Failed to retrieve chain head information. Disconnecting {}. ", peer, error); peer.disconnect(DisconnectReason.USELESS_PEER); } }); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java index 51004654d8d..77b48056f5f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java @@ -34,7 +34,6 @@ import org.hyperledger.besu.plugin.services.BesuEvents.SyncStatusListener; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.util.ExceptionUtils; -import org.hyperledger.besu.util.Subscribers; import java.nio.file.Path; import java.time.Clock; @@ -51,7 +50,6 @@ public class DefaultSynchronizer implements Synchronizer { private final Optional maybePruner; private final SyncState syncState; private final AtomicBoolean running = new AtomicBoolean(false); - private final Subscribers syncStatusListeners = Subscribers.create(); private final BlockPropagationManager blockPropagationManager; private final Optional> fastSyncDownloader; private final FullSyncDownloader fullSyncDownloader; @@ -108,7 +106,7 @@ public DefaultSynchronizer( BesuMetricCategory.ETHEREUM, "best_known_block_number", "The estimated highest block available", - () -> syncState.syncStatus().getHighestBlock()); + syncState::bestChainHeight); metricsSystem.createIntegerGauge( BesuMetricCategory.SYNCHRONIZER, "in_sync", @@ -126,7 +124,6 @@ private TrailingPeerRequirements calculateTrailingPeerRequirements() { public void start() { if (running.compareAndSet(false, true)) { LOG.info("Starting synchronizer."); - syncState.addSyncStatusListener(this::syncStatusCallback); blockPropagationManager.start(); if (fastSyncDownloader.isPresent()) { fastSyncDownloader.get().start().whenComplete(this::handleFastSyncResult); @@ -144,6 +141,14 @@ public void stop() { LOG.info("Stopping synchronizer"); fastSyncDownloader.ifPresent(FastSyncDownloader::stop); fullSyncDownloader.stop(); + maybePruner.ifPresent(Pruner::stop); + } + } + + @Override + public void awaitStop() throws InterruptedException { + if (maybePruner.isPresent()) { + maybePruner.get().awaitStop(); } } @@ -179,25 +184,32 @@ public Optional getSyncStatus() { if (!running.get()) { return Optional.empty(); } - final SyncStatus syncStatus = syncState.syncStatus(); - if (syncStatus.inSync()) { - return Optional.empty(); - } - return Optional.of(syncStatus); + return syncState.syncStatus(); } @Override - public long observeSyncStatus(final SyncStatusListener listener) { + public long subscribeSyncStatus(final SyncStatusListener listener) { checkNotNull(listener); - return syncStatusListeners.subscribe(listener); + return syncState.subscribeSyncStatus(listener); } @Override - public boolean removeObserver(final long observerId) { - return syncStatusListeners.unsubscribe(observerId); + public boolean unsubscribeSyncStatus(final long subscriberId) { + return syncState.unsubscribeSyncStatus(subscriberId); } - private void syncStatusCallback(final SyncStatus status) { - syncStatusListeners.forEach(c -> c.onSyncStatusChanged(status)); + @Override + public long subscribeInSync(final InSyncListener listener) { + return syncState.subscribeInSync(listener); + } + + @Override + public long subscribeInSync(final InSyncListener listener, final long syncTolerance) { + return syncState.subscribeInSync(listener, syncTolerance); + } + + @Override + public boolean unsubscribeInSync(final long listenerId) { + return syncState.unsubscribeSyncStatus(listenerId); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java index 996dcdcb91a..cd57de371dd 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.sync.tasks.GetReceiptsForHeadersTask; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStep.java index e2559b3c17c..5179bd788cb 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStep.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.eth.sync.ValidationPolicy; import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncTargetManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncTargetManager.java index 1c64a18a6ac..1762a01576b 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncTargetManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncTargetManager.java @@ -61,7 +61,7 @@ public FastSyncTargetManager( @Override protected CompletableFuture> selectBestAvailableSyncTarget() { - final Optional maybeBestPeer = ethContext.getEthPeers().bestPeer(); + final Optional maybeBestPeer = ethContext.getEthPeers().bestPeerWithHeightEstimate(); if (!maybeBestPeer.isPresent()) { LOG.info("No sync target, wait for peers."); return completedFuture(Optional.empty()); @@ -91,6 +91,12 @@ private CompletableFuture> confirmPivotBlockHeader(final EthPe .thenApply( result -> { if (peerHasDifferentPivotBlock(result)) { + LOG.warn( + "Best peer has wrong pivot block (#{}) expecting {} but received {}. Disconnect: {}", + pivotBlockHeader.getNumber(), + pivotBlockHeader.getHash(), + result.size() == 1 ? result.get(0).getHash() : "invalid response", + bestPeer); bestPeer.disconnect(DisconnectReason.USELESS_PEER); return Optional.empty(); } else { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManager.java index e8a60419bee..9aa41a2a682 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManager.java @@ -70,7 +70,7 @@ protected Optional finalizeSelectedSyncTarget(final SyncTarget syncT @Override protected CompletableFuture> selectBestAvailableSyncTarget() { - final Optional maybeBestPeer = ethContext.getEthPeers().bestPeer(); + final Optional maybeBestPeer = ethContext.getEthPeers().bestPeerWithHeightEstimate(); if (!maybeBestPeer.isPresent()) { LOG.info("No sync target, wait for peers."); return completedFuture(Optional.empty()); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/InSyncTracker.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/InSyncTracker.java new file mode 100644 index 00000000000..9e7032d4de6 --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/InSyncTracker.java @@ -0,0 +1,107 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.ethereum.eth.sync.state; + +import org.hyperledger.besu.ethereum.chain.ChainHead; +import org.hyperledger.besu.ethereum.core.Synchronizer.InSyncListener; +import org.hyperledger.besu.ethereum.eth.manager.ChainHeadEstimate; + +import java.util.Optional; +import java.util.function.Consumer; + +/** Tracks the sync status of this node within the specified {@code syncTolerance}. */ +class InSyncTracker { + private InSyncState state = InSyncState.UNKNOWN; + // If the local chain is no more than {@code syncTolerance} behind the estimated highest chain, + // then the tracker considers this local node to be in sync + private final long syncTolerance; + + private final InSyncListener listener; + + private InSyncTracker(final InSyncListener listener, final long syncTolerance) { + this.listener = listener; + this.syncTolerance = syncTolerance; + } + + public static InSyncTracker create(final InSyncListener listener, final long syncTolerance) { + return new InSyncTracker(listener, syncTolerance); + } + + public static boolean isInSync( + final ChainHead localChain, final ChainHeadEstimate remoteChain, final long syncTolerance) { + final boolean inSyncByHeight = + remoteChain.getEstimatedHeight() - localChain.getHeight() <= syncTolerance; + return inSyncByHeight || !remoteChain.chainIsBetterThan(localChain); + } + + synchronized void checkState( + final ChainHead localChain, + final Optional syncTargetChain, + final Optional bestPeerChain) { + final boolean currentSyncStatus = + currentSyncStatus(localChain, syncTargetChain, bestPeerChain).orElse(true); + + final InSyncState newState = InSyncState.fromInSync(currentSyncStatus); + if (state != newState) { + // Sync status has changed, notify listener + state = newState; + state.ifKnown(listener::onInSyncStatusChange); + } + } + + private Optional currentSyncStatus( + final ChainHead localChain, + final Optional syncTargetChain, + final Optional bestPeerChain) { + final Optional inSyncWithSyncTarget = + syncTargetChain.map(remote -> isInSync(localChain, remote)); + final Optional inSyncWithBestPeer = + bestPeerChain.map(remote -> isInSync(localChain, remote)); + // If we're out of sync with either peer, we're out of sync + if (inSyncWithSyncTarget.isPresent() && !inSyncWithSyncTarget.get()) { + return Optional.of(false); + } + if (inSyncWithBestPeer.isPresent() && !inSyncWithBestPeer.get()) { + return Optional.of(false); + } + // Otherwise, if either peer is in sync, we're in sync + return inSyncWithSyncTarget.or(() -> inSyncWithBestPeer); + } + + private boolean isInSync(final ChainHead localChain, final ChainHeadEstimate remoteChain) { + return isInSync(localChain, remoteChain, syncTolerance); + } + + private enum InSyncState { + UNKNOWN(Optional.empty()), + IN_SYNC(Optional.of(true)), + OUT_OF_SYNC(Optional.of(false)); + + private final Optional inSync; + + InSyncState(final Optional inSync) { + this.inSync = inSync; + } + + static InSyncState fromInSync(final boolean inSync) { + return inSync ? IN_SYNC : OUT_OF_SYNC; + } + + public void ifKnown(final Consumer handler) { + inSync.ifPresent(handler::accept); + } + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java index 159c03b9789..42dfa29fbae 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java @@ -17,83 +17,89 @@ import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.ChainHead; import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.SyncStatus; +import org.hyperledger.besu.ethereum.core.DefaultSyncStatus; +import org.hyperledger.besu.ethereum.core.Synchronizer; +import org.hyperledger.besu.ethereum.core.Synchronizer.InSyncListener; +import org.hyperledger.besu.ethereum.eth.manager.ChainHeadEstimate; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; +import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.plugin.services.BesuEvents.SyncStatusListener; import org.hyperledger.besu.util.Subscribers; +import java.util.Map; import java.util.Optional; - -import com.google.common.annotations.VisibleForTesting; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; public class SyncState { - private static final long SYNC_TOLERANCE = 5; + private final Blockchain blockchain; private final EthPeers ethPeers; - private long startingBlock; - private boolean lastInSync = true; - private final Subscribers inSyncListeners = Subscribers.create(); + private final AtomicLong inSyncSubscriberId = new AtomicLong(); + private final Map inSyncTrackers = new ConcurrentHashMap<>(); private final Subscribers syncStatusListeners = Subscribers.create(); - private Optional syncTarget = Optional.empty(); - private long chainHeightListenerId; + private volatile long chainHeightListenerId; + private volatile Optional syncTarget = Optional.empty(); public SyncState(final Blockchain blockchain, final EthPeers ethPeers) { this.blockchain = blockchain; this.ethPeers = ethPeers; - this.startingBlock = this.blockchain.getChainHeadBlockNumber(); blockchain.observeBlockAdded( (event, chain) -> { if (event.isNewCanonicalHead()) { checkInSync(); } - switch (event.getEventType()) { - case CHAIN_REORG: - publishReorg(); - // fall through - case HEAD_ADVANCED: - publishSyncStatus(); - break; - case FORK: - // don't broadcast detected forks - break; - } }); } - @VisibleForTesting - public void publishSyncStatus() { - final SyncStatus syncStatus = syncStatus(); - syncStatusListeners.forEach(c -> c.onSyncStatusChanged(syncStatus)); + /** + * Add a listener that will be notified when this node's sync status changes. A node is considered + * in-sync if the local chain height is no more than {@code SYNC_TOLERANCE} behind the highest + * estimated remote chain height. + * + * @param listener The callback to invoke when the sync status changes + * @return An {@code Unsubscriber} that can be used to stop listening for these events + */ + public long subscribeInSync(final InSyncListener listener) { + return subscribeInSync(listener, Synchronizer.DEFAULT_IN_SYNC_TOLERANCE); } - private void publishReorg() { - final long chainHeadBlockNumber = blockchain.getChainHeadBlockNumber(); - final SyncStatus syncStatus = - new SyncStatus( - startingBlock, chainHeadBlockNumber, bestChainHeight(chainHeadBlockNumber), false); + /** + * Add a listener that will be notified when this node's sync status changes. A node is considered + * in-sync if the local chain height is no more than {@code syncTolerance} behind the highest + * estimated remote chain height. + * + * @param listener The callback to invoke when the sync status changes + * @param syncTolerance The tolerance used to determine whether this node is in-sync. A value of + * zero means that the node is considered in-sync only when the local chain height is greater + * than or equal to the best estimated remote chain height. + * @return An {@code Unsubscriber} that can be used to stop listening for these events + */ + public long subscribeInSync(final InSyncListener listener, final long syncTolerance) { + final InSyncTracker inSyncTracker = InSyncTracker.create(listener, syncTolerance); + final long id = inSyncSubscriberId.incrementAndGet(); + inSyncTrackers.put(id, inSyncTracker); - syncStatusListeners.forEach(c -> c.onSyncStatusChanged(syncStatus)); + return id; } - public void addInSyncListener(final InSyncListener observer) { - inSyncListeners.subscribe(observer); + public boolean unsubscribeInSync(final long subscriberId) { + return inSyncTrackers.remove(subscriberId) != null; } - public long addSyncStatusListener(final SyncStatusListener observer) { - return syncStatusListeners.subscribe(observer); + public long subscribeSyncStatus(final SyncStatusListener listener) { + return syncStatusListeners.subscribe(listener); } - public void removeSyncStatusListener(final long listenerId) { - syncStatusListeners.unsubscribe(listenerId); + public boolean unsubscribeSyncStatus(final long listenerId) { + return syncStatusListeners.unsubscribe(listenerId); } - public SyncStatus syncStatus() { - final long chainHeadBlockNumber = blockchain.getChainHeadBlockNumber(); - return new SyncStatus( - startingBlock, chainHeadBlockNumber, bestChainHeight(chainHeadBlockNumber)); + public Optional syncStatus() { + return syncStatus(syncTarget); } public Optional syncTarget() { @@ -106,29 +112,44 @@ public void setSyncTarget(final EthPeer peer, final BlockHeader commonAncestor) } public boolean isInSync() { - return isInSync(SYNC_TOLERANCE); + return isInSync(Synchronizer.DEFAULT_IN_SYNC_TOLERANCE); } public boolean isInSync(final long syncTolerance) { + return isInSync( + getLocalChainHead(), getSyncTargetChainHead(), getBestPeerChainHead(), syncTolerance); + } + + private boolean isInSync( + final ChainHead localChain, + final Optional syncTargetChain, + final Optional bestPeerChain, + final long syncTolerance) { // Sync target may be temporarily empty while we switch sync targets during a sync, so // check both the sync target and our best peer to determine if we're in sync or not - return isInSyncWithTarget(syncTolerance) && isInSyncWithBestPeer(syncTolerance); + return isInSync(localChain, syncTargetChain, syncTolerance) + && isInSync(localChain, bestPeerChain, syncTolerance); } - private boolean isInSyncWithTarget(final long syncTolerance) { - return syncTarget - .map(t -> t.estimatedTargetHeight() - blockchain.getChainHeadBlockNumber() <= syncTolerance) + private boolean isInSync( + final ChainHead localChain, + final Optional remoteChain, + final long syncTolerance) { + return remoteChain + .map(remoteState -> InSyncTracker.isInSync(localChain, remoteState, syncTolerance)) .orElse(true); } - private boolean isInSyncWithBestPeer(final long syncTolerance) { - final ChainHead chainHead = blockchain.getChainHead(); - return ethPeers - .bestPeerWithHeightEstimate() - .filter(peer -> peer.chainState().chainIsBetterThan(chainHead)) - .map(EthPeer::chainState) - .map(chainState -> chainState.getEstimatedHeight() - chainHead.getHeight() <= syncTolerance) - .orElse(true); + private ChainHead getLocalChainHead() { + return blockchain.getChainHead(); + } + + private Optional getSyncTargetChainHead() { + return syncTarget.map(SyncTarget::peer).map(EthPeer::chainStateSnapshot); + } + + private Optional getBestPeerChainHead() { + return ethPeers.bestPeerWithHeightEstimate().map(EthPeer::chainStateSnapshot); } public void disconnectSyncTarget(final DisconnectReason reason) { @@ -139,13 +160,33 @@ public void clearSyncTarget() { replaceSyncTarget(Optional.empty()); } - private void replaceSyncTarget(final Optional newTarget) { + private synchronized void replaceSyncTarget(final Optional newTarget) { + if (syncTarget.equals(newTarget)) { + // Nothing to do + return; + } syncTarget.ifPresent(this::removeEstimatedHeightListener); syncTarget = newTarget; newTarget.ifPresent(this::addEstimatedHeightListener); + publishSyncStatus(newTarget); checkInSync(); } + private void publishSyncStatus(final Optional newTarget) { + final Optional syncStatus = syncStatus(newTarget); + syncStatusListeners.forEach(c -> c.onSyncStatusChanged(syncStatus)); + } + + private Optional syncStatus(final Optional maybeTarget) { + return maybeTarget.map( + target -> { + final long chainHeadBlockNumber = blockchain.getChainHeadBlockNumber(); + final long commonAncestor = target.commonAncestor().getNumber(); + final long highestKnownBlock = bestChainHeight(chainHeadBlockNumber); + return new DefaultSyncStatus(commonAncestor, chainHeadBlockNumber, highestKnownBlock); + }); + } + private void removeEstimatedHeightListener(final SyncTarget target) { target.removePeerChainEstimatedHeightListener(chainHeightListenerId); } @@ -155,6 +196,11 @@ private void addEstimatedHeightListener(final SyncTarget target) { target.addPeerChainEstimatedHeightListener(estimatedHeight -> checkInSync()); } + public long bestChainHeight() { + final long localChainHeight = blockchain.getChainHeadBlockNumber(); + return bestChainHeight(localChainHeight); + } + public long bestChainHeight(final long localChainHeight) { return Math.max( localChainHeight, @@ -165,19 +211,13 @@ public long bestChainHeight(final long localChainHeight) { } private synchronized void checkInSync() { - final boolean currentInSync = isInSync(); - if (lastInSync != currentInSync) { - lastInSync = currentInSync; - if (!currentInSync) { - // when we fall out of sync change our starting block - startingBlock = blockchain.getChainHeadBlockNumber(); - } - inSyncListeners.forEach(c -> c.onSyncStatusChanged(currentInSync)); - } - } - - @FunctionalInterface - public interface InSyncListener { - void onSyncStatusChanged(boolean newSyncStatus); + ChainHead localChain = getLocalChainHead(); + Optional syncTargetChain = getSyncTargetChainHead(); + Optional bestPeerChain = getBestPeerChainHead(); + + inSyncTrackers + .values() + .forEach( + (syncTracker) -> syncTracker.checkState(localChain, syncTargetChain, bestPeerChain)); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTask.java index 4d007e19270..31800c03f2b 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/PersistBlockTask.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; @@ -67,22 +68,20 @@ public static Supplier>> forSequentialBlocks( final List blocks, final HeaderValidationMode headerValidationMode, final MetricsSystem metricsSystem) { - checkArgument(blocks.size() > 0); + checkArgument(!blocks.isEmpty(), "No blocks to import provided"); return () -> { final List successfulImports = new ArrayList<>(); - CompletableFuture future = null; - for (final Block block : blocks) { - if (future == null) { - future = - importBlockAndAddToList( - protocolSchedule, - protocolContext, - block, - successfulImports, - headerValidationMode, - metricsSystem); - continue; - } + final Iterator blockIterator = blocks.iterator(); + CompletableFuture future = + importBlockAndAddToList( + protocolSchedule, + protocolContext, + blockIterator.next(), + successfulImports, + headerValidationMode, + metricsSystem); + while (blockIterator.hasNext()) { + final Block block = blockIterator.next(); future = future.thenCompose( b -> @@ -122,34 +121,34 @@ public static Supplier>> forUnorderedBlocks( final List blocks, final HeaderValidationMode headerValidationMode, final MetricsSystem metricsSystem) { - checkArgument(blocks.size() > 0); + checkArgument(!blocks.isEmpty(), "No blocks to import provided"); return () -> { final CompletableFuture> finalResult = new CompletableFuture<>(); final List successfulImports = new ArrayList<>(); - CompletableFuture future = null; - for (final Block block : blocks) { - if (future == null) { - future = - PersistBlockTask.create( - protocolSchedule, protocolContext, block, headerValidationMode, metricsSystem) - .run(); - continue; - } + final Iterator> tasks = + blocks.stream() + .map( + block -> + PersistBlockTask.create( + protocolSchedule, + protocolContext, + block, + headerValidationMode, + metricsSystem)) + .iterator(); + + CompletableFuture future = tasks.next().run(); + while (tasks.hasNext()) { + final PersistBlockTask task = tasks.next(); future = future .handle((r, t) -> r) .thenCompose( - (r) -> { + r -> { if (r != null) { successfulImports.add(r); } - return PersistBlockTask.create( - protocolSchedule, - protocolContext, - block, - headerValidationMode, - metricsSystem) - .run(); + return task.run(); }); } future.whenComplete( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PeerTransactionTracker.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PeerTransactionTracker.java index 888bb0cce1b..4e517b26b3e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PeerTransactionTracker.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PeerTransactionTracker.java @@ -35,7 +35,7 @@ public class PeerTransactionTracker implements EthPeer.DisconnectCallback { public synchronized void markTransactionsAsSeen( final EthPeer peer, final Collection transactions) { final Set seenTransactionsForPeer = getOrCreateSeenTransactionsForPeer(peer); - transactions.stream().map(Transaction::hash).forEach(seenTransactionsForPeer::add); + transactions.stream().map(Transaction::getHash).forEach(seenTransactionsForPeer::add); } public synchronized void addToPeerSendQueue(final EthPeer peer, final Transaction transaction) { @@ -64,7 +64,8 @@ private Set getOrCreateSeenTransactionsForPeer(final EthPeer peer) { private boolean hasPeerSeenTransaction(final EthPeer peer, final Transaction transaction) { final Set seenTransactionsForPeer = seenTransactions.get(peer); - return seenTransactionsForPeer != null && seenTransactionsForPeer.contains(transaction.hash()); + return seenTransactionsForPeer != null + && seenTransactionsForPeer.contains(transaction.getHash()); } private Set createTransactionsSet() { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java index 21d75fec57e..e06ff91eafc 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java @@ -149,17 +149,11 @@ void transactionAddedToBlock(final Transaction transaction) { private void doRemoveTransaction(final Transaction transaction, final boolean addedToBlock) { synchronized (pendingTransactions) { - final TransactionInfo removedTransactionInfo = pendingTransactions.remove(transaction.hash()); + final TransactionInfo removedTransactionInfo = + pendingTransactions.remove(transaction.getHash()); if (removedTransactionInfo != null) { prioritizedTransactions.remove(removedTransactionInfo); - Optional.ofNullable(transactionsBySender.get(transaction.getSender())) - .ifPresent( - transactionsForSender -> { - transactionsForSender.remove(transaction.getNonce()); - if (transactionsForSender.isEmpty()) { - transactionsBySender.remove(transaction.getSender()); - } - }); + removeTransactionTrackedBySenderAndNonce(transaction); incrementTransactionRemovedCounter( removedTransactionInfo.isReceivedFromLocalSource(), addedToBlock); } @@ -240,20 +234,42 @@ private boolean addTransaction(final TransactionInfo transactionInfo) { } private boolean addTransactionForSenderAndNonce(final TransactionInfo transactionInfo) { - final Map transactionsForSender = - transactionsBySender.computeIfAbsent(transactionInfo.getSender(), key -> new TreeMap<>()); final TransactionInfo existingTransaction = - transactionsForSender.get(transactionInfo.getNonce()); + getTrackedTransactionBySenderAndNonce(transactionInfo); if (existingTransaction != null) { if (!shouldReplace(existingTransaction, transactionInfo)) { return false; } removeTransaction(existingTransaction.getTransaction()); } - transactionsForSender.put(transactionInfo.getNonce(), transactionInfo); + trackTransactionBySenderAndNonce(transactionInfo); return true; } + private void trackTransactionBySenderAndNonce(final TransactionInfo transactionInfo) { + final Map transactionsForSender = + transactionsBySender.computeIfAbsent(transactionInfo.getSender(), key -> new TreeMap<>()); + transactionsForSender.put(transactionInfo.getNonce(), transactionInfo); + } + + private void removeTransactionTrackedBySenderAndNonce(final Transaction transaction) { + Optional.ofNullable(transactionsBySender.get(transaction.getSender())) + .ifPresent( + transactionsForSender -> { + transactionsForSender.remove(transaction.getNonce()); + if (transactionsForSender.isEmpty()) { + transactionsBySender.remove(transaction.getSender()); + } + }); + } + + private TransactionInfo getTrackedTransactionBySenderAndNonce( + final TransactionInfo transactionInfo) { + final Map transactionsForSender = + transactionsBySender.computeIfAbsent(transactionInfo.getSender(), key -> new TreeMap<>()); + return transactionsForSender.get(transactionInfo.getNonce()); + } + private boolean shouldReplace( final TransactionInfo existingTransaction, final TransactionInfo newTransaction) { return newTransaction @@ -362,7 +378,7 @@ public boolean isReceivedFromLocalSource() { } public Hash getHash() { - return transaction.hash(); + return transaction.getHash(); } public Instant getAddedToPoolAt() { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java index 10e9a25122c..f6978a2fe40 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java @@ -135,7 +135,7 @@ public void addRemoteTransactions(final Collection transactions) { } final Set addedTransactions = new HashSet<>(); for (final Transaction transaction : transactions) { - if (pendingTransactions.containsTransaction(transaction.hash())) { + if (pendingTransactions.containsTransaction(transaction.getHash())) { // We already have this transaction, don't even validate it. duplicateTransactionCounter.labels(REMOTE).inc(); continue; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessor.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessor.java index e9fd19b98bf..0a514cc4aaf 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessor.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessor.java @@ -82,6 +82,7 @@ private void processTransactionsMessage( transactionPool.addRemoteTransactions(transactions); } catch (final RLPException ex) { if (peer != null) { + LOG.debug("Malformed transaction message received, disconnecting: {}", peer, ex); peer.disconnect(DisconnectReason.BREACH_OF_PROTOCOL); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateTest.java index ec2030d7f60..3f8a70af9db 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ChainStateTest.java @@ -43,6 +43,20 @@ public void statusReceivedUpdatesBestBlock() { assertThat(chainState.getBestBlock().getTotalDifficulty()).isEqualTo(INITIAL_TOTAL_DIFFICULTY); } + @Test + public void updateHeightEstimate_toZero() { + chainState.updateHeightEstimate(0L); + assertThat(chainState.hasEstimatedHeight()).isFalse(); + assertThat(chainState.getEstimatedHeight()).isEqualTo(0L); + } + + @Test + public void updateHeightEstimate_toNonZeroValue() { + chainState.updateHeightEstimate(1L); + assertThat(chainState.hasEstimatedHeight()).isTrue(); + assertThat(chainState.getEstimatedHeight()).isEqualTo(1L); + } + @Test public void updateBestBlockAndHeightFromHashAndHeight() { final long blockNumber = 12; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/TrailingPeerLimiterTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/TrailingPeerLimiterTest.java index 9ec9369b8bc..ddd136c2f70 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/TrailingPeerLimiterTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/TrailingPeerLimiterTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.util.uint.UInt256; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.junit.Before; @@ -116,7 +117,8 @@ public void shouldRecheckTrailingPeersWhenBlockAddedThatIsMultipleOf100() { BlockAddedEvent.createForHeadAdvancement( new Block( new BlockHeaderTestFixture().number(500).buildHeader(), - new BlockBody(emptyList(), emptyList()))); + new BlockBody(emptyList(), emptyList())), + Collections.emptyList()); trailingPeerLimiter.onBlockAdded(blockAddedEvent, blockchain); assertDisconnections(ethPeer1); @@ -132,7 +134,8 @@ public void shouldNotRecheckTrailingPeersWhenBlockAddedIsNotAMultipleOf100() { BlockAddedEvent.createForHeadAdvancement( new Block( new BlockHeaderTestFixture().number(599).buildHeader(), - new BlockBody(emptyList(), emptyList()))); + new BlockBody(emptyList(), emptyList())), + Collections.emptyList()); trailingPeerLimiter.onBlockAdded(blockAddedEvent, blockchain); assertDisconnections(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java index 7cf995155b4..8740413e312 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStepTest.java index f5cc2bf5336..c054aaf3e4a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStepTest.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.eth.sync.ValidationPolicy; import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java index 86f711f590e..9a3cf1428bb 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.util.uint.UInt256; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -82,6 +83,34 @@ public void tearDown() { ethProtocolManager.stop(); } + @Test + public void findSyncTarget_withHeightEstimates() { + when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) + .thenReturn(true); + final RespondingEthPeer bestPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, UInt256.MAX_VALUE, 1); + + final CompletableFuture result = syncTargetManager.findSyncTarget(Optional.empty()); + bestPeer.respond(responder); + + assertThat(result) + .isCompletedWithValue( + new SyncTarget(bestPeer.getEthPeer(), localBlockchain.getBlockHeader(4L).get())); + } + + @Test + public void findSyncTarget_noHeightEstimates() { + when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) + .thenReturn(true); + final RespondingEthPeer bestPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, UInt256.MAX_VALUE, 0); + + final CompletableFuture result = syncTargetManager.findSyncTarget(Optional.empty()); + bestPeer.respond(responder); + + assertThat(result).isNotCompleted(); + } + @Test public void shouldDisconnectPeerIfWorldStateIsUnavailableForCommonAncestor() { when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java index 9af33988f3f..cd6837adf30 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java @@ -16,86 +16,108 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; -import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; -import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.chain.ChainHead; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockDataGenerator; +import org.hyperledger.besu.ethereum.core.BlockDataGenerator.BlockOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import org.hyperledger.besu.ethereum.core.Hash; -import org.hyperledger.besu.ethereum.core.SyncStatus; +import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider; +import org.hyperledger.besu.ethereum.core.Synchronizer; +import org.hyperledger.besu.ethereum.core.Synchronizer.InSyncListener; +import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.eth.manager.ChainHeadEstimate; import org.hyperledger.besu.ethereum.eth.manager.ChainState; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; +import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; +import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; +import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; +import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.plugin.services.BesuEvents.SyncStatusListener; import org.hyperledger.besu.util.uint.UInt256; -import java.util.Collections; +import java.util.List; import java.util.Optional; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.junit.MockitoJUnitRunner; +@RunWith(MockitoJUnitRunner.class) public class SyncStateTest { - private static final long OUR_CHAIN_HEAD_NUMBER = 500; - private static final UInt256 OUR_CHAIN_DIFFICULTY = UInt256.of(500); - private static final long TARGET_CHAIN_DELTA = 100; + private static final UInt256 standardDifficultyPerBlock = UInt256.of(1L); + private static final long OUR_CHAIN_HEAD_NUMBER = 20; + private static final UInt256 OUR_CHAIN_DIFFICULTY = + standardDifficultyPerBlock.times(OUR_CHAIN_HEAD_NUMBER); + private static final long TARGET_CHAIN_DELTA = 20; private static final long TARGET_CHAIN_HEIGHT = OUR_CHAIN_HEAD_NUMBER + TARGET_CHAIN_DELTA; - private static final UInt256 TARGET_DIFFICULTY = OUR_CHAIN_DIFFICULTY.plus(TARGET_CHAIN_DELTA); + private static final UInt256 TARGET_DIFFICULTY = + standardDifficultyPerBlock.times(TARGET_CHAIN_HEIGHT); - private final Blockchain blockchain = mock(Blockchain.class); - private final EthPeers ethPeers = mock(EthPeers.class); - private final SyncState.InSyncListener inSyncListener = mock(SyncState.InSyncListener.class); + private final InSyncListener inSyncListener = mock(InSyncListener.class); + private final InSyncListener inSyncListenerExact = mock(InSyncListener.class); private final SyncStatusListener syncStatusListener = mock(SyncStatusListener.class); - private final EthPeer syncTargetPeer = mock(EthPeer.class); - private final ChainState syncTargetPeerChainState = spy(new ChainState()); - private final EthPeer otherPeer = mock(EthPeer.class); - private final ChainState otherPeerChainState = spy(new ChainState()); + + private final BlockDataGenerator gen = new BlockDataGenerator(1); + private final Block genesisBlock = + gen.genesisBlock(new BlockOptions().setDifficulty(UInt256.ZERO)); + private final MutableBlockchain blockchain = + InMemoryStorageProvider.createInMemoryBlockchain(genesisBlock); + + @Captor ArgumentCaptor> syncStatusCaptor; + + private EthProtocolManager ethProtocolManager; + private EthPeers ethPeers; + private RespondingEthPeer syncTargetPeer; + private RespondingEthPeer otherPeer; private SyncState syncState; - private BlockAddedObserver blockAddedObserver; @Before public void setUp() { - final ArgumentCaptor captor = - ArgumentCaptor.forClass(BlockAddedObserver.class); + ethProtocolManager = + EthProtocolManagerTestUtil.create( + blockchain, InMemoryStorageProvider.createInMemoryWorldStateArchive()); + ethPeers = spy(ethProtocolManager.ethContext().getEthPeers()); + syncTargetPeer = createPeer(TARGET_DIFFICULTY, TARGET_CHAIN_HEIGHT); + otherPeer = createPeer(UInt256.ZERO, 0); - final ChainHead ourChainHead = - new ChainHead(Hash.ZERO, OUR_CHAIN_DIFFICULTY, OUR_CHAIN_HEAD_NUMBER); + advanceLocalChain(OUR_CHAIN_HEAD_NUMBER); - when(blockchain.observeBlockAdded(captor.capture())).thenReturn(1L); - when(blockchain.getChainHeadBlockNumber()).thenReturn(OUR_CHAIN_HEAD_NUMBER); - when(blockchain.getChainHead()).thenReturn(ourChainHead); - when(syncTargetPeer.chainState()).thenReturn(syncTargetPeerChainState); - when(otherPeer.chainState()).thenReturn(otherPeerChainState); syncState = new SyncState(blockchain, ethPeers); - blockAddedObserver = captor.getValue(); - syncState.addInSyncListener(inSyncListener); - syncState.addSyncStatusListener(syncStatusListener); + syncState.subscribeInSync(inSyncListener); + syncState.subscribeInSync(inSyncListenerExact, 0); + syncState.subscribeSyncStatus(syncStatusListener); } @Test public void isInSync_noPeers() { + otherPeer.disconnect(DisconnectReason.REQUESTED); + syncTargetPeer.disconnect(DisconnectReason.REQUESTED); + syncState.clearSyncTarget(); assertThat(syncState.isInSync()).isTrue(); } @Test public void isInSync_singlePeerWithWorseChainBetterHeight() { - updateChainState(otherPeerChainState, TARGET_CHAIN_HEIGHT, OUR_CHAIN_DIFFICULTY.minus(1L)); - when(ethPeers.bestPeerWithHeightEstimate()).thenReturn(Optional.of(otherPeer)); - doReturn(false).when(otherPeerChainState).chainIsBetterThan(any()); + updateChainState(otherPeer.getEthPeer(), TARGET_CHAIN_HEIGHT, OUR_CHAIN_DIFFICULTY.minus(1L)); + final EthPeer peer = mockWorseChain(otherPeer.getEthPeer()); + doReturn(Optional.of(peer)).when(ethPeers).bestPeerWithHeightEstimate(); assertThat(syncState.syncTarget()).isEmpty(); // Sanity check assertThat(syncState.isInSync()).isTrue(); @@ -105,9 +127,9 @@ public void isInSync_singlePeerWithWorseChainBetterHeight() { @Test public void isInSync_singlePeerWithWorseChainWorseHeight() { updateChainState( - otherPeerChainState, OUR_CHAIN_HEAD_NUMBER - 1L, OUR_CHAIN_DIFFICULTY.minus(1L)); - when(ethPeers.bestPeerWithHeightEstimate()).thenReturn(Optional.of(otherPeer)); - doReturn(false).when(otherPeerChainState).chainIsBetterThan(any()); + otherPeer.getEthPeer(), OUR_CHAIN_HEAD_NUMBER - 1L, OUR_CHAIN_DIFFICULTY.minus(1L)); + final EthPeer peer = mockWorseChain(otherPeer.getEthPeer()); + doReturn(Optional.of(peer)).when(ethPeers).bestPeerWithHeightEstimate(); assertThat(syncState.syncTarget()).isEmpty(); // Sanity check assertThat(syncState.isInSync()).isTrue(); @@ -116,9 +138,9 @@ public void isInSync_singlePeerWithWorseChainWorseHeight() { @Test public void isInSync_singlePeerWithBetterChainWorseHeight() { - updateChainState(otherPeerChainState, OUR_CHAIN_HEAD_NUMBER - 1L, TARGET_DIFFICULTY); - when(ethPeers.bestPeerWithHeightEstimate()).thenReturn(Optional.of(otherPeer)); - doReturn(true).when(otherPeerChainState).chainIsBetterThan(any()); + updateChainState(otherPeer.getEthPeer(), OUR_CHAIN_HEAD_NUMBER - 1L, TARGET_DIFFICULTY); + final EthPeer peer = mockBetterChain(otherPeer.getEthPeer()); + doReturn(Optional.of(peer)).when(ethPeers).bestPeerWithHeightEstimate(); assertThat(syncState.syncTarget()).isEmpty(); // Sanity check assertThat(syncState.isInSync()).isTrue(); @@ -127,9 +149,9 @@ public void isInSync_singlePeerWithBetterChainWorseHeight() { @Test public void isInSync_singlePeerWithBetterChainBetterHeight() { - updateChainState(otherPeerChainState, TARGET_CHAIN_HEIGHT, TARGET_DIFFICULTY); - when(ethPeers.bestPeerWithHeightEstimate()).thenReturn(Optional.of(otherPeer)); - doReturn(true).when(otherPeerChainState).chainIsBetterThan(any()); + updateChainState(otherPeer.getEthPeer(), TARGET_CHAIN_HEIGHT, TARGET_DIFFICULTY); + final EthPeer peer = mockBetterChain(otherPeer.getEthPeer()); + doReturn(Optional.of(peer)).when(ethPeers).bestPeerWithHeightEstimate(); assertThat(syncState.syncTarget()).isEmpty(); // Sanity check assertThat(syncState.isInSync()).isFalse(); @@ -140,8 +162,8 @@ public void isInSync_singlePeerWithBetterChainBetterHeight() { @Test public void isInSync_syncTargetWithBetterHeight() { - updateChainState(syncTargetPeerChainState, TARGET_CHAIN_HEIGHT, TARGET_DIFFICULTY); - syncState.setSyncTarget(syncTargetPeer, blockHeaderAt(0L)); + otherPeer.disconnect(DisconnectReason.REQUESTED); + setupOutOfSyncState(); assertThat(syncState.syncTarget()).isPresent(); // Sanity check assertThat(syncState.isInSync()).isFalse(); @@ -152,8 +174,10 @@ public void isInSync_syncTargetWithBetterHeight() { @Test public void isInSync_syncTargetWithWorseHeight() { - updateChainState(syncTargetPeerChainState, OUR_CHAIN_HEAD_NUMBER - 1L, TARGET_DIFFICULTY); - syncState.setSyncTarget(syncTargetPeer, blockHeaderAt(0L)); + otherPeer.disconnect(DisconnectReason.REQUESTED); + final long heightDifference = 20L; + advanceLocalChain(TARGET_CHAIN_HEIGHT + heightDifference); + setupOutOfSyncState(); assertThat(syncState.syncTarget()).isPresent(); // Sanity check assertThat(syncState.isInSync()).isTrue(); @@ -162,11 +186,9 @@ public void isInSync_syncTargetWithWorseHeight() { @Test public void isInSync_outOfSyncWithTargetAndOutOfSyncWithBestPeer() { - updateChainState(syncTargetPeerChainState, TARGET_CHAIN_HEIGHT, TARGET_DIFFICULTY); - syncState.setSyncTarget(syncTargetPeer, blockHeaderAt(0L)); - updateChainState(otherPeerChainState, TARGET_CHAIN_HEIGHT, TARGET_DIFFICULTY); - when(ethPeers.bestPeerWithHeightEstimate()).thenReturn(Optional.of(otherPeer)); - doReturn(true).when(otherPeerChainState).chainIsBetterThan(any()); + setupOutOfSyncState(); + updateChainState(otherPeer.getEthPeer(), TARGET_CHAIN_HEIGHT, TARGET_DIFFICULTY); + doReturn(Optional.of(otherPeer.getEthPeer())).when(ethPeers).bestPeerWithHeightEstimate(); assertThat(syncState.isInSync()).isFalse(); assertThat(syncState.isInSync(0)).isFalse(); @@ -177,112 +199,421 @@ public void isInSync_outOfSyncWithTargetAndOutOfSyncWithBestPeer() { @Test public void isInSync_inSyncWithTargetOutOfSyncWithBestPeer() { + setupOutOfSyncState(); + advanceLocalChain(TARGET_CHAIN_HEIGHT); + final long heightDifference = 20L; updateChainState( - syncTargetPeerChainState, OUR_CHAIN_HEAD_NUMBER - 1L, OUR_CHAIN_DIFFICULTY.minus(1L)); - syncState.setSyncTarget(syncTargetPeer, blockHeaderAt(0L)); - updateChainState(otherPeerChainState, TARGET_CHAIN_HEIGHT, TARGET_DIFFICULTY); - when(ethPeers.bestPeerWithHeightEstimate()).thenReturn(Optional.of(otherPeer)); - doReturn(true).when(otherPeerChainState).chainIsBetterThan(any()); + otherPeer.getEthPeer(), + TARGET_CHAIN_HEIGHT + heightDifference, + TARGET_DIFFICULTY.plus(heightDifference)); + doReturn(Optional.of(otherPeer.getEthPeer())).when(ethPeers).bestPeerWithHeightEstimate(); assertThat(syncState.isInSync()).isFalse(); assertThat(syncState.isInSync(0)).isFalse(); - assertThat(syncState.isInSync(TARGET_CHAIN_DELTA - 1)).isFalse(); - assertThat(syncState.isInSync(TARGET_CHAIN_DELTA)).isTrue(); - assertThat(syncState.isInSync(TARGET_CHAIN_DELTA + 1)).isTrue(); + assertThat(syncState.isInSync(heightDifference - 1)).isFalse(); + assertThat(syncState.isInSync(heightDifference)).isTrue(); + assertThat(syncState.isInSync(heightDifference + 1)).isTrue(); } @Test public void isInSync_inSyncWithTargetInSyncWithBestPeer() { - updateChainState( - syncTargetPeerChainState, OUR_CHAIN_HEAD_NUMBER - 1L, OUR_CHAIN_DIFFICULTY.minus(1L)); - syncState.setSyncTarget(syncTargetPeer, blockHeaderAt(0L)); - updateChainState( - otherPeerChainState, OUR_CHAIN_HEAD_NUMBER - 1L, OUR_CHAIN_DIFFICULTY.minus(1L)); - when(ethPeers.bestPeerWithHeightEstimate()).thenReturn(Optional.of(otherPeer)); - doReturn(false).when(otherPeerChainState).chainIsBetterThan(any()); + setupOutOfSyncState(); + advanceLocalChain(TARGET_CHAIN_HEIGHT); + updateChainState(otherPeer.getEthPeer(), TARGET_CHAIN_HEIGHT, TARGET_DIFFICULTY); + doReturn(Optional.of(otherPeer.getEthPeer())).when(ethPeers).bestPeerWithHeightEstimate(); assertThat(syncState.isInSync()).isTrue(); assertThat(syncState.isInSync(0)).isTrue(); } @Test - public void shouldSwitchToInSyncWhenSyncTargetCleared() { + public void shouldSwitchToInSyncWhenNoBetterPeersAreAvailable() { setupOutOfSyncState(); + otherPeer.disconnect(DisconnectReason.REQUESTED); + syncTargetPeer.disconnect(DisconnectReason.REQUESTED); syncState.clearSyncTarget(); - verify(inSyncListener).onSyncStatusChanged(true); + verify(inSyncListener).onInSyncStatusChange(true); + verify(inSyncListenerExact).onInSyncStatusChange(true); verifyNoMoreInteractions(inSyncListener); + verifyNoMoreInteractions(inSyncListenerExact); } @Test public void shouldBecomeInSyncWhenOurBlockchainCatchesUp() { setupOutOfSyncState(); - when(blockchain.getChainHeadBlockNumber()).thenReturn(TARGET_CHAIN_HEIGHT); - blockAddedObserver.onBlockAdded( - BlockAddedEvent.createForHeadAdvancement( - new Block( - targetBlockHeader(), - new BlockBody(Collections.emptyList(), Collections.emptyList()))), - blockchain); + // Update to just within the default sync threshold + advanceLocalChain(TARGET_CHAIN_HEIGHT - Synchronizer.DEFAULT_IN_SYNC_TOLERANCE); + // We should register as in-sync with default tolerance, out-of-sync with exact tolerance + assertThat(syncState.isInSync()).isTrue(); + assertThat(syncState.isInSync(0)).isFalse(); + verify(inSyncListener).onInSyncStatusChange(true); + verify(inSyncListenerExact, never()).onInSyncStatusChange(true); + // Advance one more block + advanceLocalChain(TARGET_CHAIN_HEIGHT - Synchronizer.DEFAULT_IN_SYNC_TOLERANCE + 1); + // We should register as in-sync with default tolerance, out-of-sync with exact tolerance assertThat(syncState.isInSync()).isTrue(); - verify(inSyncListener).onSyncStatusChanged(true); + assertThat(syncState.isInSync(0)).isFalse(); + verifyNoMoreInteractions(inSyncListener); + verify(inSyncListenerExact, never()).onInSyncStatusChange(true); + + // Catch all the way up + advanceLocalChain(TARGET_CHAIN_HEIGHT); + // We should register as in-sync + assertThat(syncState.isInSync()).isTrue(); + assertThat(syncState.isInSync(0)).isTrue(); + verifyNoMoreInteractions(inSyncListener); + verify(inSyncListenerExact).onInSyncStatusChange(true); } @Test - public void shouldSendSyncStatusWhenBlockIsAddedToTheChain() { - final SyncStatusListener syncStatusListener = mock(SyncStatusListener.class); - syncState.addSyncStatusListener(syncStatusListener); - - blockAddedObserver.onBlockAdded( - BlockAddedEvent.createForHeadAdvancement( - new Block( - targetBlockHeader(), - new BlockBody(Collections.emptyList(), Collections.emptyList()))), - blockchain); - - verify(syncStatusListener).onSyncStatusChanged(eq(syncState.syncStatus())); + public void addInSyncListener_whileOutOfSync() { + setupOutOfSyncState(); + + // Add listener + InSyncListener newListener = mock(InSyncListener.class); + syncState.subscribeInSync(newListener); + verify(newListener, never()).onInSyncStatusChange(false); + verify(newListener, never()).onInSyncStatusChange(true); + + // Catch all the way up + advanceLocalChain(TARGET_CHAIN_HEIGHT); + + // Fall out of sync + updateChainState( + syncTargetPeer.getEthPeer(), + TARGET_CHAIN_HEIGHT + Synchronizer.DEFAULT_IN_SYNC_TOLERANCE + 1L, + TARGET_DIFFICULTY.plus(10L)); + + final ArgumentCaptor inSyncEventCaptor = ArgumentCaptor.forClass(Boolean.class); + verify(newListener, times(3)).onInSyncStatusChange(inSyncEventCaptor.capture()); + + final List syncChanges = inSyncEventCaptor.getAllValues(); + assertThat(syncChanges.get(0)).isEqualTo(false); + assertThat(syncChanges.get(1)).isEqualTo(true); + assertThat(syncChanges.get(2)).isEqualTo(false); } @Test - public void shouldReportReorgEvents() { - when(blockchain.getChainHeadBlockNumber()).thenReturn(TARGET_CHAIN_HEIGHT); - - blockAddedObserver.onBlockAdded( - BlockAddedEvent.createForChainReorg( - new Block( - targetBlockHeader(), - new BlockBody(Collections.emptyList(), Collections.emptyList())), - Collections.emptyList(), - Collections.emptyList()), - blockchain); + public void addInSyncListener_whileOutOfSync_withDistinctSyncTolerance() { + setupOutOfSyncState(); - assertThat(syncState.isInSync()).isTrue(); - final ArgumentCaptor captor = ArgumentCaptor.forClass(SyncStatus.class); - verify(syncStatusListener, times(2)).onSyncStatusChanged(captor.capture()); - assertThat(captor.getAllValues().get(0).inSync()).isFalse(); - assertThat(captor.getAllValues().get(1).inSync()).isTrue(); + // Add listener + final long syncTolerance = Synchronizer.DEFAULT_IN_SYNC_TOLERANCE * 2; + InSyncListener newListener = mock(InSyncListener.class); + syncState.subscribeInSync(newListener, syncTolerance); + verify(newListener, never()).onInSyncStatusChange(false); + verify(newListener, never()).onInSyncStatusChange(true); + + // Catch all the way up + advanceLocalChain(TARGET_CHAIN_HEIGHT); + + // Fall out of sync + updateChainState( + syncTargetPeer.getEthPeer(), + TARGET_CHAIN_HEIGHT + syncTolerance + 1L, + TARGET_DIFFICULTY.plus(10L)); + + final ArgumentCaptor inSyncEventCaptor = ArgumentCaptor.forClass(Boolean.class); + verify(newListener, times(3)).onInSyncStatusChange(inSyncEventCaptor.capture()); + + final List syncChanges = inSyncEventCaptor.getAllValues(); + assertThat(syncChanges.get(0)).isEqualTo(false); + assertThat(syncChanges.get(1)).isEqualTo(true); + assertThat(syncChanges.get(2)).isEqualTo(false); + } + + @Test + public void addInSyncListener_whileInSync() { + setupOutOfSyncState(); + // Catch all the way up + advanceLocalChain(TARGET_CHAIN_HEIGHT); + + // Add listener + InSyncListener newListener = mock(InSyncListener.class); + syncState.subscribeInSync(newListener); + verify(newListener, never()).onInSyncStatusChange(false); + verify(newListener, never()).onInSyncStatusChange(true); + // Fall out of sync + updateChainState( + syncTargetPeer.getEthPeer(), + TARGET_CHAIN_HEIGHT + Synchronizer.DEFAULT_IN_SYNC_TOLERANCE + 1L, + TARGET_DIFFICULTY.plus(10L)); + verify(newListener).onInSyncStatusChange(false); + verify(newListener, never()).onInSyncStatusChange(true); + + // Catch up + advanceLocalChain(TARGET_CHAIN_HEIGHT + 1L); + verify(newListener).onInSyncStatusChange(false); + verify(newListener).onInSyncStatusChange(true); + } + + @Test + public void addInSyncListener_whileInSync_withDistinctSyncTolerance() { + final long syncTolerance = Synchronizer.DEFAULT_IN_SYNC_TOLERANCE * 2; + setupOutOfSyncState(); + + // Catch all the way up + advanceLocalChain(TARGET_CHAIN_HEIGHT); + + // Add listener + InSyncListener newListener = mock(InSyncListener.class); + syncState.subscribeInSync(newListener, syncTolerance); + verify(newListener, never()).onInSyncStatusChange(false); + verify(newListener, never()).onInSyncStatusChange(true); + + // Fall out of sync + updateChainState( + syncTargetPeer.getEthPeer(), + TARGET_CHAIN_HEIGHT + syncTolerance + 1L, + TARGET_DIFFICULTY.plus(10L)); + verify(newListener).onInSyncStatusChange(false); + verify(newListener, never()).onInSyncStatusChange(true); + + // Catch up + advanceLocalChain(TARGET_CHAIN_HEIGHT + 1L); + verify(newListener).onInSyncStatusChange(false); + verify(newListener).onInSyncStatusChange(true); + } + + @Test + public void removeInSyncListener_doesntReceiveSubsequentEvents() { + final long syncTolerance = Synchronizer.DEFAULT_IN_SYNC_TOLERANCE + 1L; + setupOutOfSyncState(); + + // Add listener + InSyncListener newListener = mock(InSyncListener.class); + final long subscriberId = syncState.subscribeInSync(newListener, syncTolerance); + verify(newListener, never()).onInSyncStatusChange(anyBoolean()); + + // Remove listener + syncState.unsubscribeInSync(subscriberId); + + // Catch all the way up + advanceLocalChain(TARGET_CHAIN_HEIGHT); + + // We should not register the in-sync event + verify(newListener, never()).onInSyncStatusChange(anyBoolean()); + + // Fall out of sync + updateChainState( + syncTargetPeer.getEthPeer(), + TARGET_CHAIN_HEIGHT + syncTolerance + 1L, + TARGET_DIFFICULTY.plus(10L)); + + // We should not register the sync event + verify(newListener, never()).onInSyncStatusChange(anyBoolean()); + + // Other listeners should keep running + verify(inSyncListenerExact, times(2)).onInSyncStatusChange(false); + verify(inSyncListenerExact).onInSyncStatusChange(true); + } + + @Test + public void removeInSyncListener_addAdditionalListenerBeforeRemoving() { + final long syncTolerance = Synchronizer.DEFAULT_IN_SYNC_TOLERANCE + 1L; + setupOutOfSyncState(); + + // Add listener + InSyncListener listenerToRemove = mock(InSyncListener.class); + InSyncListener otherListener = mock(InSyncListener.class); + final long subscriberId = syncState.subscribeInSync(listenerToRemove, syncTolerance); + syncState.subscribeInSync(otherListener, syncTolerance); + + // Remove listener + syncState.unsubscribeInSync(subscriberId); + + // Catch all the way up + advanceLocalChain(TARGET_CHAIN_HEIGHT); + + // We should not register the in-sync event + verify(listenerToRemove, never()).onInSyncStatusChange(anyBoolean()); + + // Fall out of sync + updateChainState( + syncTargetPeer.getEthPeer(), + TARGET_CHAIN_HEIGHT + syncTolerance + 1L, + TARGET_DIFFICULTY.plus(10L)); + + // We should not register the in-sync event + verify(listenerToRemove, never()).onInSyncStatusChange(anyBoolean()); + + final ArgumentCaptor inSyncEventCaptor = ArgumentCaptor.forClass(Boolean.class); + verify(otherListener, times(3)).onInSyncStatusChange(inSyncEventCaptor.capture()); + + final List syncChanges = inSyncEventCaptor.getAllValues(); + assertThat(syncChanges.get(0)).isEqualTo(false); + assertThat(syncChanges.get(1)).isEqualTo(true); + assertThat(syncChanges.get(2)).isEqualTo(false); + + // Other listeners should keep running + verify(inSyncListenerExact).onInSyncStatusChange(true); + verify(inSyncListenerExact, times(2)).onInSyncStatusChange(false); + } + + @Test + public void removeInSyncListener_addAdditionalListenerAfterRemoving() { + final long syncTolerance = Synchronizer.DEFAULT_IN_SYNC_TOLERANCE + 1L; + setupOutOfSyncState(); + + // Add listener + InSyncListener listenerToRemove = mock(InSyncListener.class); + InSyncListener otherListener = mock(InSyncListener.class); + final long subscriberId = syncState.subscribeInSync(listenerToRemove, syncTolerance); + + // Remove listener + syncState.unsubscribeInSync(subscriberId); + + // Add new listener + syncState.subscribeInSync(otherListener, syncTolerance); + + // Catch all the way up + advanceLocalChain(TARGET_CHAIN_HEIGHT); + + // We should not register the sync event + verify(listenerToRemove, never()).onInSyncStatusChange(anyBoolean()); + + // Fall out of sync + updateChainState( + syncTargetPeer.getEthPeer(), + TARGET_CHAIN_HEIGHT + syncTolerance + 1L, + TARGET_DIFFICULTY.plus(10L)); + + // We should not register the sync event + verify(listenerToRemove, never()).onInSyncStatusChange(anyBoolean()); + + final ArgumentCaptor inSyncEventCaptor = ArgumentCaptor.forClass(Boolean.class); + verify(otherListener, times(3)).onInSyncStatusChange(inSyncEventCaptor.capture()); + + final List syncChanges = inSyncEventCaptor.getAllValues(); + assertThat(syncChanges.get(0)).isEqualTo(false); + assertThat(syncChanges.get(1)).isEqualTo(true); + assertThat(syncChanges.get(2)).isEqualTo(false); + + // Other listeners should keep running + verify(inSyncListenerExact, times(2)).onInSyncStatusChange(false); + verify(inSyncListenerExact).onInSyncStatusChange(true); + } + + @Test + public void syncStatusListener_receivesEventWhenSyncTargetSet() { + syncState.setSyncTarget(syncTargetPeer.getEthPeer(), blockchain.getBlockHeader(3L).get()); + + verify(syncStatusListener).onSyncStatusChanged(syncStatusCaptor.capture()); + + assertThat(syncStatusCaptor.getAllValues()).hasSize(1); + final Optional syncStatus = syncStatusCaptor.getValue(); + + assertThat(syncStatus).isPresent(); + assertThat(syncStatus.get().getStartingBlock()).isEqualTo(3L); + assertThat(syncStatus.get().getCurrentBlock()).isEqualTo(OUR_CHAIN_HEAD_NUMBER); + assertThat(syncStatus.get().getHighestBlock()).isEqualTo(TARGET_CHAIN_HEIGHT); + } + + @Test + public void syncStatusListener_receivesEventWhenSyncTargetCleared() { + syncState.setSyncTarget(syncTargetPeer.getEthPeer(), blockchain.getBlockHeader(3L).get()); + syncState.clearSyncTarget(); + + verify(syncStatusListener, times(2)).onSyncStatusChanged(syncStatusCaptor.capture()); + + List> events = syncStatusCaptor.getAllValues(); + assertThat(events).hasSize(2); + + // Check first value + final Optional syncingEvent = events.get(0); + assertThat(syncingEvent).isPresent(); + assertThat(syncingEvent.get().getStartingBlock()).isEqualTo(3L); + assertThat(syncingEvent.get().getCurrentBlock()).isEqualTo(OUR_CHAIN_HEAD_NUMBER); + assertThat(syncingEvent.get().getHighestBlock()).isEqualTo(TARGET_CHAIN_HEIGHT); + + // Check second value + final Optional clearedEvent = events.get(1); + assertThat(clearedEvent).isEmpty(); + } + + @Test + public void syncStatusListener_ignoreNoopChangesToSyncTarget() { + syncState.clearSyncTarget(); + syncState.setSyncTarget(syncTargetPeer.getEthPeer(), blockchain.getBlockHeader(3L).get()); + syncState.setSyncTarget(syncTargetPeer.getEthPeer(), blockchain.getBlockHeader(3L).get()); + syncState.clearSyncTarget(); + syncState.clearSyncTarget(); + + verify(syncStatusListener, times(2)).onSyncStatusChanged(syncStatusCaptor.capture()); + + List> events = syncStatusCaptor.getAllValues(); + assertThat(events).hasSize(2); + + // Check first value + final Optional syncingEvent = events.get(0); + assertThat(syncingEvent).isPresent(); + assertThat(syncingEvent.get().getStartingBlock()).isEqualTo(3L); + assertThat(syncingEvent.get().getCurrentBlock()).isEqualTo(OUR_CHAIN_HEAD_NUMBER); + assertThat(syncingEvent.get().getHighestBlock()).isEqualTo(TARGET_CHAIN_HEIGHT); + + // Check second value + final Optional clearedEvent = events.get(1); + assertThat(clearedEvent).isEmpty(); + } + + private RespondingEthPeer createPeer(final UInt256 totalDifficulty, final long blockHeight) { + return EthProtocolManagerTestUtil.createPeer(ethProtocolManager, totalDifficulty, blockHeight); + } + + private EthPeer mockWorseChain(final EthPeer peer) { + return mockChainIsBetterThan(peer, false); + } + + private EthPeer mockBetterChain(final EthPeer peer) { + return mockChainIsBetterThan(peer, true); + } + + private EthPeer mockChainIsBetterThan(final EthPeer peer, final boolean isBetter) { + final ChainState chainState = spy(peer.chainState()); + final ChainHeadEstimate chainStateSnapshot = spy(peer.chainStateSnapshot()); + lenient().doReturn(isBetter).when(chainState).chainIsBetterThan(any()); + lenient().doReturn(isBetter).when(chainStateSnapshot).chainIsBetterThan(any()); + final EthPeer mockedPeer = spy(peer); + lenient().doReturn(chainStateSnapshot).when(chainState).getSnapshot(); + lenient().doReturn(chainStateSnapshot).when(mockedPeer).chainStateSnapshot(); + lenient().doReturn(chainState).when(mockedPeer).chainState(); + return mockedPeer; } private void setupOutOfSyncState() { - updateChainState(syncTargetPeerChainState, TARGET_CHAIN_HEIGHT, TARGET_DIFFICULTY); - syncState.setSyncTarget(syncTargetPeer, blockHeaderAt(0L)); - assertThat(syncState.isInSync()).isFalse(); - verify(inSyncListener).onSyncStatusChanged(false); + syncState.setSyncTarget(syncTargetPeer.getEthPeer(), blockchain.getGenesisBlock().getHeader()); + verify(inSyncListener).onInSyncStatusChange(false); + verify(inSyncListenerExact).onInSyncStatusChange(false); + } + + private void advanceLocalChain(final long newChainHeight) { + while (blockchain.getChainHeadBlockNumber() < newChainHeight) { + final BlockHeader parent = blockchain.getChainHeadHeader(); + final Block block = + gen.block( + BlockOptions.create() + .setDifficulty(standardDifficultyPerBlock) + .setParentHash(parent.getHash()) + .setBlockNumber(parent.getNumber() + 1L)); + final List receipts = gen.receipts(block); + blockchain.appendBlock(block, receipts); + } } /** * Updates the chain state, such that the peer will end up with an estimated height of {@code * blockHeight} and an estimated total difficulty of {@code totalDifficulty} * - * @param chainState The chain state to update + * @param peer The peer whose chain should be updated * @param blockHeight The target estimated block height * @param totalDifficulty The total difficulty */ private void updateChainState( - final ChainState chainState, final long blockHeight, final UInt256 totalDifficulty) { + final EthPeer peer, final long blockHeight, final UInt256 totalDifficulty) { // Chain state is updated based on the parent of the announced block // So, increment block number by 1 and set block difficulty to zero // in order to update to the values we want @@ -291,18 +622,10 @@ private void updateChainState( .number(blockHeight + 1L) .difficulty(UInt256.ZERO) .buildHeader(); - chainState.updateForAnnouncedBlock(header, totalDifficulty); + peer.chainState().updateForAnnouncedBlock(header, totalDifficulty); // Sanity check this logic still holds - assertThat(chainState.getEstimatedHeight()).isEqualTo(blockHeight); - assertThat(chainState.getEstimatedTotalDifficulty()).isEqualTo(totalDifficulty); - } - - private BlockHeader targetBlockHeader() { - return blockHeaderAt(TARGET_CHAIN_HEIGHT); - } - - private BlockHeader blockHeaderAt(final long blockNumber) { - return new BlockHeaderTestFixture().number(blockNumber).buildHeader(); + assertThat(peer.chainState().getEstimatedHeight()).isEqualTo(blockHeight); + assertThat(peer.chainState().getEstimatedTotalDifficulty()).isEqualTo(totalDifficulty); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionsTest.java index 7d7cf42c948..87350e0e5cd 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionsTest.java @@ -276,6 +276,24 @@ public void selectTransactionsUntilPendingIsEmpty() { assertThat(parsedTransactions.get(1)).isEqualTo(transaction1); } + @Test + public void shouldNotSelectReplacedTransaction() { + final Transaction transaction1 = transactionWithNonceSenderAndGasPrice(1, KEYS1, 1); + final Transaction transaction2 = transactionWithNonceSenderAndGasPrice(1, KEYS1, 2); + + transactions.addRemoteTransaction(transaction1); + transactions.addRemoteTransaction(transaction2); + + final List parsedTransactions = Lists.newArrayList(); + transactions.selectTransactions( + transaction -> { + parsedTransactions.add(transaction); + return PendingTransactions.TransactionSelectionResult.CONTINUE; + }); + + assertThat(parsedTransactions).containsExactly(transaction2); + } + @Test public void invalidTransactionIsDeletedFromPendingTransactions() { transactions.addRemoteTransaction(transaction1); @@ -325,6 +343,71 @@ public void shouldReplaceTransactionWithSameSenderAndNonce() { assertThat(metricsSystem.getCounterValue(REMOVED_COUNTER, REMOTE, DROPPED)).isEqualTo(1); } + @Test + public void shouldReplaceTransactionWithSameSenderAndNonce_multipleReplacements() { + final int replacedTxCount = 5; + final List replacedTransactions = new ArrayList<>(); + for (int i = 0; i < replacedTxCount; i++) { + final Transaction duplicateTx = transactionWithNonceSenderAndGasPrice(1, KEYS1, i + 1); + replacedTransactions.add(duplicateTx); + transactions.addRemoteTransaction(duplicateTx); + } + final Transaction finalReplacingTx = transactionWithNonceSenderAndGasPrice(1, KEYS1, 100); + final Transaction independentTx = transactionWithNonceSenderAndGasPrice(2, KEYS1, 1); + assertThat(transactions.addRemoteTransaction(independentTx)).isTrue(); + assertThat(transactions.addRemoteTransaction(finalReplacingTx)).isTrue(); + + // All tx's except the last duplicate should be removed + replacedTransactions.forEach(this::assertTransactionNotPending); + assertTransactionPending(finalReplacingTx); + // Tx with distinct nonce should be maintained + assertTransactionPending(independentTx); + + assertThat(transactions.size()).isEqualTo(2); + assertThat(metricsSystem.getCounterValue(ADDED_COUNTER, REMOTE)).isEqualTo(replacedTxCount + 2); + assertThat(metricsSystem.getCounterValue(REMOVED_COUNTER, REMOTE, DROPPED)) + .isEqualTo(replacedTxCount); + } + + @Test + public void + shouldReplaceTransactionWithSameSenderAndNonce_multipleReplacementsAddedLocallyAndRemotely() { + final int replacedTxCount = 11; + final List replacedTransactions = new ArrayList<>(); + int remoteDuplicateCount = 0; + for (int i = 0; i < replacedTxCount; i++) { + final Transaction duplicateTx = transactionWithNonceSenderAndGasPrice(1, KEYS1, i + 1); + replacedTransactions.add(duplicateTx); + if (i % 2 == 0) { + transactions.addRemoteTransaction(duplicateTx); + remoteDuplicateCount++; + } else { + transactions.addLocalTransaction(duplicateTx); + } + } + final Transaction finalReplacingTx = transactionWithNonceSenderAndGasPrice(1, KEYS1, 100); + final Transaction independentTx = transactionWithNonceSenderAndGasPrice(2, KEYS1, 1); + assertThat(transactions.addLocalTransaction(finalReplacingTx)).isTrue(); + assertThat(transactions.addRemoteTransaction(independentTx)).isTrue(); + + // All tx's except the last duplicate should be removed + replacedTransactions.forEach(this::assertTransactionNotPending); + assertTransactionPending(finalReplacingTx); + // Tx with distinct nonce should be maintained + assertTransactionPending(independentTx); + + final int localDuplicateCount = replacedTxCount - remoteDuplicateCount; + assertThat(transactions.size()).isEqualTo(2); + assertThat(metricsSystem.getCounterValue(ADDED_COUNTER, REMOTE)) + .isEqualTo(remoteDuplicateCount + 1); + assertThat(metricsSystem.getCounterValue(ADDED_COUNTER, LOCAL)) + .isEqualTo(localDuplicateCount + 1); + assertThat(metricsSystem.getCounterValue(REMOVED_COUNTER, REMOTE, DROPPED)) + .isEqualTo(remoteDuplicateCount); + assertThat(metricsSystem.getCounterValue(REMOVED_COUNTER, LOCAL, DROPPED)) + .isEqualTo(localDuplicateCount); + } + @Test public void shouldReplaceOnlyTransactionFromSenderWhenItHasTheSameNonce() { final Transaction transaction1 = transactionWithNonceSenderAndGasPrice(1, KEYS1, 1); @@ -449,11 +532,11 @@ private Transaction transactionWithNonceSenderAndGasPrice( } private void assertTransactionPending(final Transaction t) { - assertThat(transactions.getTransactionByHash(t.hash())).contains(t); + assertThat(transactions.getTransactionByHash(t.getHash())).contains(t); } private void assertTransactionNotPending(final Transaction t) { - assertThat(transactions.getTransactionByHash(t.hash())).isEmpty(); + assertThat(transactions.getTransactionByHash(t.getHash())).isEmpty(); } private Transaction createTransaction(final int transactionNumber) { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNodeList.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNodeList.java index 856c5410c33..c6ce0197984 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNodeList.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNodeList.java @@ -28,6 +28,7 @@ import java.io.Closeable; import java.io.IOException; +import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -42,13 +43,12 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.awaitility.Awaitility; -import org.awaitility.Duration; import org.awaitility.core.ConditionTimeoutException; public class TestNodeList implements Closeable { private static final Logger LOG = LogManager.getLogger(); protected final List nodes = new ArrayList<>(); - private final Duration MSG_WAIT = new Duration(2, TimeUnit.SECONDS); + private final Duration MSG_WAIT = Duration.ofSeconds(2); public TestNode create( final Vertx vertx, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolTest.java index 5c9438d4078..844e8dcc309 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolTest.java @@ -384,11 +384,11 @@ public void shouldDiscardRemoteTransactionThatAlreadyExistsBeforeValidation() { Wei.ZERO, metricsSystem); - when(pendingTransactions.containsTransaction(transaction1.hash())).thenReturn(true); + when(pendingTransactions.containsTransaction(transaction1.getHash())).thenReturn(true); transactionPool.addRemoteTransactions(singletonList(transaction1)); - verify(pendingTransactions).containsTransaction(transaction1.hash()); + verify(pendingTransactions).containsTransaction(transaction1.getHash()); verifyZeroInteractions(transactionValidator); verifyNoMoreInteractions(pendingTransactions); } @@ -606,11 +606,11 @@ public void shouldCallValidatorWithExpectedValidationParameters() { } private void assertTransactionPending(final Transaction t) { - assertThat(transactions.getTransactionByHash(t.hash())).contains(t); + assertThat(transactions.getTransactionByHash(t.getHash())).contains(t); } private void assertTransactionNotPending(final Transaction transaction) { - assertThat(transactions.getTransactionByHash(transaction.hash())).isEmpty(); + assertThat(transactions.getTransactionByHash(transaction.getHash())).isEmpty(); } private void verifyChainHeadIs(final Block forkBlock2) { diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java index 19bbc5da034..db16fac3dee 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java @@ -87,7 +87,28 @@ public class DiscoveryConfiguration { "enode://efd48ad0879eeb7f9cb5e50f33f7bc21e805a72e90361f145baaa22dd75d111e7cd9c93f1b7060dcb30aa1b3e620269336dbf32339fea4c18925a4c15fe642df@18.205.66.229:30303", "enode://5fbfb426fbb46f8b8c1bd3dd140f5b511da558cd37d60844b525909ab82e13a25ee722293c829e52cb65c2305b1637fa9a2ea4d6634a224d5f400bfe244ac0de@162.243.55.45:30303", "enode://6dd3ac8147fa82e46837ec8c3223d69ac24bcdbab04b036a3705c14f3a02e968f7f1adfcdb002aacec2db46e625c04bf8b5a1f85bb2d40a479b3cc9d45a444af@104.237.131.102:30303", - "enode://b9e893ea9cb4537f4fed154233005ae61b441cd0ecd980136138c304fefac194c25a16b73dac05fc66a4198d0c15dd0f33af99b411882c68a019dfa6bb703b9d@18.130.93.66:30303") + "enode://b9e893ea9cb4537f4fed154233005ae61b441cd0ecd980136138c304fefac194c25a16b73dac05fc66a4198d0c15dd0f33af99b411882c68a019dfa6bb703b9d@18.130.93.66:30303", + "enode://3fe9705a02487baea45c1ffebfa4d84819f5f1e68a0dbc18031553242a6a08e39499b61e361a52c2a92f9553efd63763f6fdd34692be0d4ba6823bb2fc346009@178.62.238.75:30303", + "enode://d50facc65e46bda6ff594b6e95491efa16e067de41ae96571d9f3cb853d538c44864496fa5e4df10115f02bbbaf47853f932e110a44c89227da7c30e96840596@188.166.163.187:30303", + "enode://a0d5c589dc02d008fe4237da9877a5f1daedee0227ab612677eabe323520f003eb5e311af335de9f7964c2092bbc2b3b7ab1cce5a074d8346959f0868b4e366e@46.101.78.44:30303", + "enode://c071d96b0c0f13006feae3977fb1b3c2f62caedf643df9a3655bc1b60f777f05e69a4e58bf3547bb299210092764c56df1e08380e91265baa845dca8bc0a71da@68.183.99.5:30303", + "enode://83b33409349ffa25e150555f7b4f8deebc68f3d34d782129dc3c8ba07b880c209310a4191e1725f2f6bef59bce9452d821111eaa786deab08a7e6551fca41f4f@206.189.68.191:30303", + "enode://0daae2a30f2c73b0b257746587136efb8e3479496f7ea1e943eeb9a663b72dd04582f699f7010ee02c57fc45d1f09568c20a9050ff937f9139e2973ddd98b87b@159.89.169.103:30303", + "enode://50808461dd73b3d70537e4c1e5fafd1132b3a90f998399af9205f8889987d62096d4e853813562dd43e7270a71c9d9d4e4dd73a534fdb22fbac98c389c1a7362@178.128.55.119:30303", + "enode://5cd218959f8263bc3721d7789070806b0adff1a0ed3f95ec886fb469f9362c7507e3b32b256550b9a7964a23a938e8d42d45a0c34b332bfebc54b29081e83b93@35.187.57.94:30303", + "enode://66498ac935f3f54d873de4719bf2d6d61e0c74dd173b547531325bcef331480f9bedece91099810971c8567eeb1ae9f6954b013c47c6dc51355bbbbae65a8c16@54.148.165.1:30303", + "enode://73e74ce7426a17aa2d8b5bb64d796ec7dc4dcee2af9bbdd4434394d1e4e52e650b9e39202435fca29ce65c242fd6e59b93ed2cf37f04b645fb23e306273816ad@54.148.165.1:30304", + "enode://8809dadb6e6145bbbce832f8e3cb54f23c84db1c4957dac04be26157a16eceb91bb2567e3a2eb794bf8e7df937fd2de46d4214416d3c199f05d3b6fa76a5ef6d@51.141.115.3:30303") + .map(EnodeURL::fromString) + .collect(toList())); + + public static List KOTTI_BOOTSTRAP_NODES = + Collections.unmodifiableList( + Stream.of( + "enode://06333009fc9ef3c9e174768e495722a7f98fe7afd4660542e983005f85e556028410fd03278944f44cfe5437b1750b5e6bd1738f700fe7da3626d52010d2954c@51.141.15.254:30303", + "enode://93c94e999be5dd854c5d82a7cf5c14822973b5d9badb56ad4974586ec4d4f1995c815af795c20bb6e0a6226d3ee55808435c4dc89baf94ee581141b064d19dfc@80.187.116.161:25720", + "enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303", + "enode://b477ca6d507a3f57070783eb62ba838847635f8b1a0cbffb8b7f8173f5894cf550f0225a5c279341e2d862a606e778b57180a4f1db3db78c51eadcfa4fdc6963@40.68.240.160:30303") .map(EnodeURL::fromString) .collect(toList())); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java index 92fffe8b203..4efc1267520 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java @@ -189,12 +189,22 @@ public void start() { return; } + final int configuredDiscoveryPort = config.getDiscovery().getBindPort(); + final int configuredRlpxPort = config.getRlpx().getBindPort(); + + final int listeningPort = rlpxAgent.start().join(); + final int discoveryPort = + peerDiscoveryAgent + .start( + (configuredDiscoveryPort == 0 && configuredRlpxPort == 0) + ? listeningPort + : configuredDiscoveryPort) + .join(); + if (natManager.isPresent()) { - this.configureNatEnvironment(); + this.configureNatEnvironment(listeningPort, discoveryPort); } - final int listeningPort = rlpxAgent.start().join(); - final int discoveryPort = peerDiscoveryAgent.start(listeningPort).join(); setLocalNode(listeningPort, discoveryPort); peerBondedObserverId = @@ -255,6 +265,7 @@ public boolean addMaintainConnectionPeer(final Peer peer) { public boolean removeMaintainedConnectionPeer(final Peer peer) { final boolean wasRemoved = maintainedPeers.remove(peer); peerDiscoveryAgent.dropPeer(peer); + LOG.debug("Disconnect requested for peer {}.", peer); rlpxAgent.disconnect(peer.getId(), DisconnectReason.REQUESTED); return wasRemoved; } @@ -361,8 +372,9 @@ private void setLocalNode(final int listeningPort, final int discoveryPort) { localNode.setEnode(localEnode); } - private void configureNatEnvironment() { - CompletableFuture natQueryFuture = this.natManager.get().queryExternalIPAddress(); + private void configureNatEnvironment(final int listeningPort, final int discoveryPort) { + final CompletableFuture natQueryFuture = + this.natManager.orElseThrow().queryExternalIPAddress(); String externalAddress = null; try { final int timeoutSeconds = 60; @@ -378,19 +390,15 @@ private void configureNatEnvironment() { LOG.info("External IP detected: " + externalAddress); this.natManager .get() - .requestPortForward( - this.config.getDiscovery().getBindPort(), - UpnpNatManager.Protocol.UDP, - "besu-discovery"); + .requestPortForward(discoveryPort, UpnpNatManager.Protocol.UDP, "besu-discovery"); this.natManager .get() - .requestPortForward( - this.config.getRlpx().getBindPort(), UpnpNatManager.Protocol.TCP, "besu-rlpx"); + .requestPortForward(listeningPort, UpnpNatManager.Protocol.TCP, "besu-rlpx"); } else { LOG.info("No external IP detected within timeout."); } - } catch (Exception e) { + } catch (final Exception e) { LOG.error("Error configuring NAT environment", e); } natExternalAddress = Optional.ofNullable(externalAddress); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java index a8cef8a2a57..1c0e6a9b268 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java @@ -125,7 +125,19 @@ public CompletableFuture start() { } setupListeners(); - return connectionInitializer.start(); + return connectionInitializer + .start() + .thenApply( + (socketAddress) -> { + LOG.info("P2P RLPx agent started and listening on {}.", socketAddress); + return socketAddress.getPort(); + }) + .whenComplete( + (res, err) -> { + if (err != null) { + LOG.error("Failed to start P2P RLPx agent.", err); + } + }); } public CompletableFuture stop() { @@ -293,6 +305,9 @@ private void handlePermissionsUpdate( connection -> { if (!peerPermissions.allowOngoingConnection( connection.getPeer(), connection.initiatedRemotely())) { + LOG.debug( + "Disconnecting from peer that is not permitted to maintain ongoing connection: {}", + connection); connection.disconnect(DisconnectReason.REQUESTED); } }); @@ -320,21 +335,28 @@ private void handleIncomingConnection(final PeerConnection peerConnection) { final Peer peer = peerConnection.getPeer(); // Deny connection if our local node isn't ready if (!localNode.isReady()) { + LOG.debug("Node is not ready. Disconnect incoming connection: {}", peerConnection); peerConnection.disconnect(DisconnectReason.UNKNOWN); return; } // Disconnect if too many peers if (!peerPrivileges.canExceedConnectionLimits(peer) && getConnectionCount() >= maxConnections) { + LOG.debug("Too many peers. Disconnect incoming connection: {}", peerConnection); peerConnection.disconnect(DisconnectReason.TOO_MANY_PEERS); return; } // Disconnect if too many remotely-initiated connections if (!peerPrivileges.canExceedConnectionLimits(peer) && remoteConnectionLimitReached()) { + LOG.debug( + "Too many remotely-initiated connections. Disconnect incoming connection: {}", + peerConnection); peerConnection.disconnect(DisconnectReason.TOO_MANY_PEERS); return; } // Disconnect if not permitted if (!peerPermissions.allowNewInboundConnectionFrom(peer)) { + LOG.debug( + "Node is not permitted to connect. Disconnect incoming connection: {}", peerConnection); peerConnection.disconnect(DisconnectReason.UNKNOWN); return; } @@ -414,7 +436,13 @@ private void enforceRemoteConnectionLimits() { .filter(RlpxConnection::initiatedRemotely) .filter(conn -> !peerPrivileges.canExceedConnectionLimits(conn.getPeer())) .skip(maxRemotelyInitiatedConnections) - .forEach(c -> c.disconnect(DisconnectReason.TOO_MANY_PEERS)); + .forEach( + conn -> { + LOG.debug( + "Too many remotely initiated connections. Disconnect low-priority connection: {}", + conn); + conn.disconnect(DisconnectReason.TOO_MANY_PEERS); + }); } private void enforceConnectionLimits() { @@ -426,7 +454,11 @@ private void enforceConnectionLimits() { getActivePrioritizedConnections() .skip(maxConnections) .filter(c -> !peerPrivileges.canExceedConnectionLimits(c.getPeer())) - .forEach(c -> c.disconnect(DisconnectReason.TOO_MANY_PEERS)); + .forEach( + conn -> { + LOG.debug("Too many connections. Disconnect low-priority connection: {}", conn); + conn.disconnect(DisconnectReason.TOO_MANY_PEERS); + }); } private Stream getActivePrioritizedConnections() { diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnection.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnection.java index 813e35ac8ed..0d3084804b5 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnection.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnection.java @@ -200,8 +200,8 @@ public int hashCode() { @Override public String toString() { return MoreObjects.toStringHelper(this) - .add("clientId", peerInfo.getClientId()) .add("nodeId", peerInfo.getNodeId()) + .add("clientId", peerInfo.getClientId()) .add( "caps", agreedCapabilities.stream().map(Capability::toString).collect(Collectors.joining(", "))) diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/ConnectionInitializer.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/ConnectionInitializer.java index 3d4264149d3..3bc2370cc88 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/ConnectionInitializer.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/ConnectionInitializer.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.ethereum.p2p.peers.Peer; import org.hyperledger.besu.ethereum.p2p.rlpx.ConnectCallback; +import java.net.InetSocketAddress; import java.util.concurrent.CompletableFuture; public interface ConnectionInitializer { @@ -25,9 +26,9 @@ public interface ConnectionInitializer { * Start the connection initializer. Begins listening for incoming connections. Start allowing * outbound connections. * - * @return The port on which we're listening for incoming connections. + * @return The address on which we're listening for incoming connections. */ - CompletableFuture start(); + CompletableFuture start(); /** * Shutdown the connection initializer. Stop listening for incoming connections and stop diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/ApiHandler.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/ApiHandler.java index b61e0117480..0fa4b9924a9 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/ApiHandler.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/ApiHandler.java @@ -82,15 +82,14 @@ protected void channelRead0(final ChannelHandlerContext ctx, final MessageData o LOG.debug( "Received Wire DISCONNECT ({}) from peer: {}", reason.name(), - connection.getPeerInfo().getClientId()); + connection.getPeerInfo()); } catch (final RLPException e) { LOG.debug( - "Received Wire DISCONNECT with invalid RLP. Peer: {}", - connection.getPeerInfo().getClientId()); + "Received Wire DISCONNECT with invalid RLP. Peer: {}", connection.getPeerInfo()); } catch (final Exception e) { LOG.error( "Received Wire DISCONNECT, but unable to parse reason. Peer: {}", - connection.getPeerInfo().getClientId(), + connection.getPeerInfo(), e); } connection.terminateConnection(reason, true); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java index db906eceb8f..135cf44697b 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java @@ -142,13 +142,13 @@ protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final L String.format( "Expected id %s, but got %s", expectedPeer.get().getId(), peerInfo.getNodeId()); connectFuture.completeExceptionally(new UnexpectedPeerConnectionException(unexpectedMsg)); + LOG.debug("{}. Disconnecting.", unexpectedMsg); connection.disconnect(DisconnectMessage.DisconnectReason.UNEXPECTED_ID); } // Check that we have shared caps if (capabilityMultiplexer.getAgreedCapabilities().size() == 0) { - LOG.debug( - "Disconnecting from {} because no capabilities are shared.", peerInfo.getClientId()); + LOG.debug("Disconnecting because no capabilities are shared: {}", peerInfo); connectFuture.completeExceptionally( new IncompatiblePeerException("No shared capabilities")); connection.disconnect(DisconnectMessage.DisconnectReason.USELESS_PEER); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyConnectionInitializer.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyConnectionInitializer.java index d77ffed75fe..85eccdc6578 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyConnectionInitializer.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyConnectionInitializer.java @@ -14,8 +14,6 @@ */ package org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty; -import static com.google.common.base.Preconditions.checkState; - import org.hyperledger.besu.crypto.SECP256K1.KeyPair; import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration; import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer; @@ -48,12 +46,9 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.util.concurrent.SingleThreadEventExecutor; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; public class NettyConnectionInitializer implements ConnectionInitializer { - private static final Logger LOG = LogManager.getLogger(); private static final int TIMEOUT_SECONDS = 10; private final KeyPair keyPair; @@ -95,8 +90,8 @@ public NettyConnectionInitializer( } @Override - public CompletableFuture start() { - final CompletableFuture listeningPortFuture = new CompletableFuture<>(); + public CompletableFuture start() { + final CompletableFuture listeningPortFuture = new CompletableFuture<>(); if (!started.compareAndSet(false, true)) { listeningPortFuture.completeExceptionally( new IllegalStateException( @@ -114,19 +109,17 @@ public CompletableFuture start() { future -> { final InetSocketAddress socketAddress = (InetSocketAddress) server.channel().localAddress(); - final String message = - String.format( - "Unable start up P2P network on %s:%s. Check for port conflicts.", - config.getBindHost(), config.getBindPort()); - - if (!future.isSuccess()) { - LOG.error(message, future.cause()); + if (!future.isSuccess() || socketAddress == null) { + final String message = + String.format( + "Unable start listening on %s:%s. Check for port conflicts.", + config.getBindHost(), config.getBindPort()); + listeningPortFuture.completeExceptionally( + new IllegalStateException(message, future.cause())); + return; } - checkState(socketAddress != null, message); - LOG.info("P2P network started and listening on {}", socketAddress); - final int listeningPort = socketAddress.getPort(); - listeningPortFuture.complete(listeningPort); + listeningPortFuture.complete(socketAddress); }); return listeningPortFuture; diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/ECIESEncryptionEngine.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/ECIESEncryptionEngine.java index 88ce02390bb..56781f8ab0e 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/ECIESEncryptionEngine.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/handshake/ecies/ECIESEncryptionEngine.java @@ -81,9 +81,6 @@ public class ECIESEncryptionEngine { private final SECP256K1.PublicKey ephPubKey; private final byte[] iv; - // TODO: This V is possibly redundant. - private final byte[] V = new byte[0]; - private ECIESEncryptionEngine( final CipherParameters pubParam, final CipherParameters privParam, @@ -209,22 +206,16 @@ private byte[] encrypt(final byte[] in, final int inOff, final int inLen, final mac.update(P2, 0, P2.length); } - if (V.length != 0 && P2 != null) { - final byte[] L2 = Pack.intToBigEndian(P2.length * 8); - mac.update(L2, 0, L2.length); - } - if (macData != null) { mac.update(macData, 0, macData.length); } mac.doFinal(T, 0); - // Output the triple (V,C,T). - final byte[] Output = new byte[V.length + len + T.length]; - System.arraycopy(V, 0, Output, 0, V.length); - System.arraycopy(C, 0, Output, V.length, len); - System.arraycopy(T, 0, Output, V.length + len, T.length); + final byte[] Output = new byte[len + T.length]; + System.arraycopy(C, 0, Output, 0, len); + System.arraycopy(T, 0, Output, len, T.length); + return Output; } @@ -271,8 +262,8 @@ private byte[] decrypt( // Use IV to initialize cipher. cipher.init(false, new ParametersWithIV(new KeyParameter(K1), iv)); - M = new byte[cipher.getOutputSize(inLen - V.length - mac.getMacSize())]; - len = cipher.processBytes(inEnc, inOff + V.length, inLen - V.length - mac.getMacSize(), M, 0); + M = new byte[cipher.getOutputSize(inLen - mac.getMacSize())]; + len = cipher.processBytes(inEnc, inOff, inLen - mac.getMacSize(), M, 0); len += cipher.doFinal(M, len); // Convert the length of the encoding vector into a byte array. @@ -290,17 +281,12 @@ private byte[] decrypt( mac.init(new KeyParameter(K2hash)); mac.update(iv, 0, iv.length); - mac.update(inEnc, inOff + V.length, inLen - V.length - T2.length); + mac.update(inEnc, inOff, inLen - T2.length); if (P2 != null) { mac.update(P2, 0, P2.length); } - if (V.length != 0 && P2 != null) { - final byte[] L2 = Pack.intToBigEndian(P2.length * 8); - mac.update(L2, 0, L2.length); - } - if (commonMac != null) { mac.update(commonMac, 0, commonMac.length); } diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java index 4dc6098dc38..92aed4f54e7 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java @@ -90,7 +90,9 @@ public void before() { lenient().when(rlpxAgent.stop()).thenReturn(CompletableFuture.completedFuture(null)); lenient() .when(discoveryAgent.start(anyInt())) - .thenReturn(CompletableFuture.completedFuture(30303)); + .thenAnswer( + invocation -> + CompletableFuture.completedFuture(invocation.getArgument(0, Integer.class))); lenient().when(discoveryAgent.stop()).thenReturn(CompletableFuture.completedFuture(null)); lenient() .when(discoveryAgent.observePeerBondedEvents(discoverySubscriberCaptor.capture())) diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/MockConnectionInitializer.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/MockConnectionInitializer.java index a41f59365c9..f3a33afb6d1 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/MockConnectionInitializer.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/MockConnectionInitializer.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.ConnectCallback; import org.hyperledger.besu.util.Subscribers; +import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -52,8 +53,10 @@ public void simulateIncomingConnection(final PeerConnection incomingConnection) } @Override - public CompletableFuture start() { - return CompletableFuture.completedFuture(NEXT_PORT.incrementAndGet()); + public CompletableFuture start() { + InetSocketAddress socketAddress = + new InetSocketAddress("127.0.0.1", NEXT_PORT.incrementAndGet()); + return CompletableFuture.completedFuture(socketAddress); } @Override diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java index e6f19a27cf5..34574ff522a 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java @@ -235,7 +235,7 @@ private List normalizeAccounts(final List accounts) { @Override public boolean isPermitted(final Transaction transaction) { - final Hash transactionHash = transaction.hash(); + final Hash transactionHash = transaction.getHash(); final Address sender = transaction.getSender(); LOG.trace("Account permissioning - Local Config: Checking transaction {}", transactionHash); diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningController.java index 0e80ed37c0a..54995659f33 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningController.java @@ -109,7 +109,7 @@ public TransactionSmartContractPermissioningController( */ @Override public boolean isPermitted(final Transaction transaction) { - final org.hyperledger.besu.ethereum.core.Hash transactionHash = transaction.hash(); + final org.hyperledger.besu.ethereum.core.Hash transactionHash = transaction.getHash(); final Address sender = transaction.getSender(); LOG.trace("Account permissioning - Smart Contract : Checking transaction {}", transactionHash); diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java index d61d2008aad..ad56d4f662a 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java @@ -46,7 +46,7 @@ public AccountPermissioningController( } public boolean isPermitted(final Transaction transaction, final boolean includeOnChainCheck) { - final Hash transactionHash = transaction.hash(); + final Hash transactionHash = transaction.getHash(); final Address sender = transaction.getSender(); LOG.trace("Account permissioning: Checking transaction {}", transactionHash); diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProvider.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProvider.java index d5db7827af9..ed07c6d550b 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProvider.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProvider.java @@ -20,14 +20,13 @@ import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; import org.hyperledger.besu.ethereum.permissioning.node.NodePermissioningProvider; import org.hyperledger.besu.metrics.BesuMetricCategory; -import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; import java.net.URI; import java.util.Collection; -import java.util.OptionalLong; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; public class SyncStatusNodePermissioningProvider implements NodePermissioningProvider { @@ -37,8 +36,8 @@ public class SyncStatusNodePermissioningProvider implements NodePermissioningPro private final Counter checkCounter; private final Counter checkCounterPermitted; private final Counter checkCounterUnpermitted; - private OptionalLong syncStatusObserverId; - private boolean hasReachedSync = false; + private final long inSyncSubscriberId; + private final AtomicBoolean hasReachedSync = new AtomicBoolean(false); public SyncStatusNodePermissioningProvider( final Synchronizer synchronizer, @@ -46,8 +45,7 @@ public SyncStatusNodePermissioningProvider( final MetricsSystem metricsSystem) { checkNotNull(synchronizer); this.synchronizer = synchronizer; - long id = this.synchronizer.observeSyncStatus(this::handleSyncStatusUpdate); - this.syncStatusObserverId = OptionalLong.of(id); + this.inSyncSubscriberId = this.synchronizer.subscribeInSync(this::handleInSyncEvent, 0); this.fixedNodes = fixedNodes.stream().map(EnodeURL::toURIWithoutDiscoveryPort).collect(Collectors.toSet()); @@ -55,7 +53,7 @@ public SyncStatusNodePermissioningProvider( BesuMetricCategory.PERMISSIONING, "sync_status_node_sync_reached", "Whether the sync status permissioning provider has realised sync yet", - () -> hasReachedSync ? 1 : 0); + () -> hasReachedSync.get() ? 1 : 0); this.checkCounter = metricsSystem.createCounter( BesuMetricCategory.PERMISSIONING, @@ -73,20 +71,10 @@ public SyncStatusNodePermissioningProvider( "Number of times the sync status permissioning provider has been checked and returned unpermitted"); } - private void handleSyncStatusUpdate(final SyncStatus syncStatus) { - if (syncStatus != null) { - long blocksBehind = syncStatus.getHighestBlock() - syncStatus.getCurrentBlock(); - if (blocksBehind <= 0) { - synchronized (this) { - if (!hasReachedSync) { - syncStatusObserverId.ifPresent( - id -> { - synchronizer.removeObserver(id); - syncStatusObserverId = OptionalLong.empty(); - }); - hasReachedSync = true; - } - } + private void handleInSyncEvent(final boolean isInSync) { + if (isInSync) { + if (hasReachedSync.compareAndSet(false, true)) { + synchronizer.unsubscribeInSync(inSyncSubscriberId); } } } @@ -104,7 +92,7 @@ private void handleSyncStatusUpdate(final SyncStatus syncStatus) { */ @Override public boolean isPermitted(final EnodeURL sourceEnode, final EnodeURL destinationEnode) { - if (hasReachedSync) { + if (hasReachedSync.get()) { return true; } else { checkCounter.inc(); @@ -119,6 +107,6 @@ public boolean isPermitted(final EnodeURL sourceEnode, final EnodeURL destinatio } public boolean hasReachedSync() { - return hasReachedSync; + return hasReachedSync.get(); } } diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProviderTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProviderTest.java index 10a708584fc..4ccd4e15365 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProviderTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProviderTest.java @@ -21,11 +21,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.hyperledger.besu.ethereum.core.SyncStatus; import org.hyperledger.besu.ethereum.core.Synchronizer; +import org.hyperledger.besu.ethereum.core.Synchronizer.InSyncListener; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; import org.hyperledger.besu.metrics.BesuMetricCategory; -import org.hyperledger.besu.plugin.services.BesuEvents.SyncStatusListener; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; @@ -62,14 +61,16 @@ public class SyncStatusNodePermissioningProviderTest { @Mock private Synchronizer synchronizer; private Collection bootnodes = new ArrayList<>(); private SyncStatusNodePermissioningProvider provider; - private SyncStatusListener syncStatusListener; - private long syncStatusObserverId = 1L; + private InSyncListener inSyncListener; @Before public void before() { - final ArgumentCaptor captor = - ArgumentCaptor.forClass(SyncStatusListener.class); - when(synchronizer.observeSyncStatus(captor.capture())).thenReturn(syncStatusObserverId); + final ArgumentCaptor inSyncSubscriberCaptor = + ArgumentCaptor.forClass(InSyncListener.class); + final ArgumentCaptor syncToleranceCaptor = ArgumentCaptor.forClass(Long.class); + when(synchronizer.subscribeInSync( + inSyncSubscriberCaptor.capture(), syncToleranceCaptor.capture())) + .thenReturn(1L); bootnodes.add(bootnode); @SuppressWarnings("unchecked") @@ -92,7 +93,8 @@ public void before() { "Number of times the sync status permissioning provider has been checked and returned unpermitted")) .thenReturn(checkUnpermittedCounter); this.provider = new SyncStatusNodePermissioningProvider(synchronizer, bootnodes, metricsSystem); - this.syncStatusListener = captor.getValue(); + this.inSyncListener = inSyncSubscriberCaptor.getValue(); + assertThat(syncToleranceCaptor.getValue()).isEqualTo(0); verify(metricsSystem) .createIntegerGauge( eq(BesuMetricCategory.PERMISSIONING), @@ -101,12 +103,12 @@ public void before() { syncGaugeCallbackCaptor.capture()); this.syncGauge = syncGaugeCallbackCaptor.getValue(); - verify(synchronizer).observeSyncStatus(any()); + verify(synchronizer).subscribeInSync(any(), eq(0L)); } @Test public void whenIsNotInSyncHasReachedSyncShouldReturnFalse() { - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 1, 2)); + inSyncListener.onInSyncStatusChange(false); assertThat(provider.hasReachedSync()).isFalse(); assertThat(syncGauge.getAsInt()).isEqualTo(0); @@ -114,7 +116,7 @@ public void whenIsNotInSyncHasReachedSyncShouldReturnFalse() { @Test public void whenInSyncHasReachedSyncShouldReturnTrue() { - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 1, 1)); + inSyncListener.onInSyncStatusChange(true); assertThat(provider.hasReachedSync()).isTrue(); assertThat(syncGauge.getAsInt()).isEqualTo(1); @@ -122,22 +124,21 @@ public void whenInSyncHasReachedSyncShouldReturnTrue() { @Test public void whenInSyncChangesFromTrueToFalseHasReachedSyncShouldReturnTrue() { - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 1, 2)); + inSyncListener.onInSyncStatusChange(false); assertThat(provider.hasReachedSync()).isFalse(); assertThat(syncGauge.getAsInt()).isEqualTo(0); - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 2, 1)); + inSyncListener.onInSyncStatusChange(true); assertThat(provider.hasReachedSync()).isTrue(); assertThat(syncGauge.getAsInt()).isEqualTo(1); - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 2, 3)); + inSyncListener.onInSyncStatusChange(false); assertThat(provider.hasReachedSync()).isTrue(); assertThat(syncGauge.getAsInt()).isEqualTo(1); } @Test public void whenHasNotSyncedNonBootnodeShouldNotBePermitted() { - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 1, 2)); assertThat(provider.hasReachedSync()).isFalse(); assertThat(syncGauge.getAsInt()).isEqualTo(0); @@ -151,7 +152,6 @@ public void whenHasNotSyncedNonBootnodeShouldNotBePermitted() { @Test public void whenHasNotSyncedBootnodeIncomingConnectionShouldNotBePermitted() { - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 1, 2)); assertThat(provider.hasReachedSync()).isFalse(); assertThat(syncGauge.getAsInt()).isEqualTo(0); @@ -165,7 +165,48 @@ public void whenHasNotSyncedBootnodeIncomingConnectionShouldNotBePermitted() { @Test public void whenHasNotSyncedBootnodeOutgoingConnectionShouldBePermitted() { - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 1, 2)); + assertThat(provider.hasReachedSync()).isFalse(); + assertThat(syncGauge.getAsInt()).isEqualTo(0); + + boolean isPermitted = provider.isPermitted(enode1, bootnode); + + assertThat(isPermitted).isTrue(); + verify(checkCounter, times(1)).inc(); + verify(checkPermittedCounter, times(1)).inc(); + verify(checkUnpermittedCounter, times(0)).inc(); + } + + @Test + public void whenOutOfSyncNonBootnodeShouldNotBePermitted() { + inSyncListener.onInSyncStatusChange(false); + assertThat(provider.hasReachedSync()).isFalse(); + assertThat(syncGauge.getAsInt()).isEqualTo(0); + + boolean isPermitted = provider.isPermitted(enode1, enode2); + + assertThat(isPermitted).isFalse(); + verify(checkCounter, times(1)).inc(); + verify(checkPermittedCounter, times(0)).inc(); + verify(checkUnpermittedCounter, times(1)).inc(); + } + + @Test + public void whenOutOfSyncBootnodeIncomingConnectionShouldNotBePermitted() { + inSyncListener.onInSyncStatusChange(false); + assertThat(provider.hasReachedSync()).isFalse(); + assertThat(syncGauge.getAsInt()).isEqualTo(0); + + boolean isPermitted = provider.isPermitted(bootnode, enode1); + + assertThat(isPermitted).isFalse(); + verify(checkCounter, times(1)).inc(); + verify(checkPermittedCounter, times(0)).inc(); + verify(checkUnpermittedCounter, times(1)).inc(); + } + + @Test + public void whenOutOfSyncBootnodeOutgoingConnectionShouldBePermitted() { + inSyncListener.onInSyncStatusChange(false); assertThat(provider.hasReachedSync()).isFalse(); assertThat(syncGauge.getAsInt()).isEqualTo(0); @@ -179,7 +220,7 @@ public void whenHasNotSyncedBootnodeOutgoingConnectionShouldBePermitted() { @Test public void whenHasSyncedIsPermittedShouldReturnTrue() { - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 1, 1)); + inSyncListener.onInSyncStatusChange(true); assertThat(provider.hasReachedSync()).isTrue(); assertThat(syncGauge.getAsInt()).isEqualTo(1); @@ -193,7 +234,7 @@ public void whenHasSyncedIsPermittedShouldReturnTrue() { @Test public void syncStatusPermissioningCheckShouldIgnoreEnodeURLDiscoveryPort() { - syncStatusListener.onSyncStatusChanged(new SyncStatus(0, 1, 2)); + inSyncListener.onInSyncStatusChange(false); assertThat(provider.hasReachedSync()).isFalse(); final EnodeURL bootnode = diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index 8e6be71ee3c..9d6875ff588 100644 --- a/ethereum/referencetests/build.gradle +++ b/ethereum/referencetests/build.gradle @@ -13,11 +13,18 @@ * SPDX-License-Identifier: Apache-2.0 */ -spotless { groovyGradle { paddedCell() - } } +spotless { + groovyGradle { + paddedCell() + } +} sourceSets { - test { resources { include '*Tests/**/*.json' } } + test { + resources { + include '*Tests/**/*.json' + } + } } configurations { testOutput } diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java index 510c1436927..420bb2a6fb9 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.config.JsonUtil; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.BlockchainQueries; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.IncrementingNonceGenerator; import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; import org.hyperledger.besu.ethereum.chain.GenesisState; diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java index d2d051c0426..37096c5eb6e 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java @@ -16,7 +16,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcHttpService; -import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcMethodsFactory; import org.hyperledger.besu.ethereum.api.jsonrpc.health.HealthService; import org.hyperledger.besu.ethereum.api.jsonrpc.health.LivenessCheck; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugAccountRange; @@ -39,9 +38,10 @@ import org.hyperledger.besu.ethereum.retesteth.methods.TestSetChainParams; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import java.util.HashMap; +import java.util.Arrays; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import io.vertx.core.Vertx; @@ -61,33 +61,32 @@ public RetestethService( final JsonRpcParameter parameters = new JsonRpcParameter(); final BlockResultFactory blockResult = new BlockResultFactory(); - final Map jsonRpcMethods = new HashMap<>(); - JsonRpcMethodsFactory.addMethods( - jsonRpcMethods, - new Web3ClientVersion(clientVersion), - new TestSetChainParams(retestethContext), - new TestImportRawBlock(retestethContext, parameters), - new EthBlockNumber(retestethContext::getBlockchainQueries, true), - new EthGetBlockByNumber( - retestethContext::getBlockchainQueries, blockResult, parameters, true), - new DebugAccountRange(parameters, retestethContext::getBlockchainQueries), - new EthGetBalance(retestethContext::getBlockchainQueries, parameters), - new EthGetCode(retestethContext::getBlockchainQueries, parameters), - new EthGetTransactionCount( - retestethContext::getBlockchainQueries, - retestethContext::getPendingTransactions, - parameters, - true), - new DebugStorageRangeAt( - parameters, - retestethContext::getBlockchainQueries, - retestethContext::getBlockReplay, - true), - new TestModifyTimestamp(retestethContext, parameters), - new EthSendRawTransaction(retestethContext::getTransactionPool, parameters, true), - new TestMineBlocks(retestethContext, parameters), - new TestGetLogHash(retestethContext, parameters), - new TestRewindToBlock(retestethContext, parameters)); + final Map jsonRpcMethods = + mapOf( + new Web3ClientVersion(clientVersion), + new TestSetChainParams(retestethContext), + new TestImportRawBlock(retestethContext, parameters), + new EthBlockNumber(retestethContext::getBlockchainQueries, true), + new EthGetBlockByNumber( + retestethContext::getBlockchainQueries, blockResult, parameters, true), + new DebugAccountRange(parameters, retestethContext::getBlockchainQueries), + new EthGetBalance(retestethContext::getBlockchainQueries, parameters), + new EthGetCode(retestethContext::getBlockchainQueries, parameters), + new EthGetTransactionCount( + retestethContext::getBlockchainQueries, + retestethContext::getPendingTransactions, + parameters, + true), + new DebugStorageRangeAt( + parameters, + retestethContext::getBlockchainQueries, + retestethContext::getBlockReplay, + true), + new TestModifyTimestamp(retestethContext, parameters), + new EthSendRawTransaction(retestethContext::getTransactionPool, parameters, true), + new TestMineBlocks(retestethContext, parameters), + new TestGetLogHash(retestethContext, parameters), + new TestRewindToBlock(retestethContext, parameters)); jsonRpcHttpService = new JsonRpcHttpService( @@ -112,4 +111,9 @@ public void close() { public void stop() { jsonRpcHttpService.stop(); } + + private static Map mapOf(final JsonRpcMethod... rpcMethods) { + return Arrays.stream(rpcMethods) + .collect(Collectors.toMap(JsonRpcMethod::getName, rpcMethod -> rpcMethod)); + } } diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java index baf10de7ad3..5071f7659bc 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java @@ -17,9 +17,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.queries.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.LogSeries; import org.hyperledger.besu.ethereum.retesteth.RetestethContext; diff --git a/gradle.properties b/gradle.properties index 535d3308046..02d3c8cfdef 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ org.gradle.jvmargs=-Xmx1g -version=1.3.1-SNAPSHOT +version=1.3.3-SNAPSHOT diff --git a/gradle/check-licenses.gradle b/gradle/check-licenses.gradle index d3c25e078a1..dce64499f73 100644 --- a/gradle/check-licenses.gradle +++ b/gradle/check-licenses.gradle @@ -160,7 +160,7 @@ task checkLicenses { def bads = "" doLast { - def xml = new XmlParser().parse('build/reports/license/license-dependency.xml') + def xml = new XmlParser().parse("${rootProject.buildDir}/reports/license/license-dependency.xml") xml.each { license -> if (!acceptedLicenses.contains((license.@name).toLowerCase())) { def depStrings = [] diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 193403b2750..48ced91d3e8 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -15,25 +15,24 @@ dependencyManagement { dependencies { - dependency 'com.fasterxml.jackson.core:jackson-databind:2.9.9.1' + dependency 'com.fasterxml.jackson.core:jackson-databind:2.10.0' dependency 'com.github.docker-java:docker-java:3.0.14' - dependency 'com.github.tomakehurst:wiremock-jre8:2.24.1' + dependency 'com.github.tomakehurst:wiremock-jre8:2.25.0' - dependency 'com.google.auto.service:auto-service:1.0-rc5' + dependency 'com.google.auto.service:auto-service:1.0-rc6' dependency 'com.google.errorprone:error_prone_check_api:2.3.3' dependency 'com.google.errorprone:error_prone_core:2.3.3' dependency 'com.google.errorprone:error_prone_annotation:2.3.3' dependency 'com.google.errorprone:error_prone_test_helpers:2.3.3' - dependency 'com.graphql-java:graphql-java:13.0' + dependency 'com.google.guava:guava:28.1-jre' - dependency 'com.google.guava:guava:28.0-jre' - dependency 'com.google.auto.service:auto-service:1.0-rc4' + dependency 'com.graphql-java:graphql-java:13.0' - dependency 'com.squareup.okhttp3:okhttp:3.14.2' + dependency 'com.squareup.okhttp3:okhttp:4.2.2' dependency 'commons-cli:commons-cli:1.4' @@ -41,12 +40,12 @@ dependencyManagement { dependency 'io.pkts:pkts-core:3.0.5' - dependency 'io.prometheus:simpleclient:0.6.0' - dependency 'io.prometheus:simpleclient_common:0.6.0' - dependency 'io.prometheus:simpleclient_hotspot:0.6.0' - dependency 'io.prometheus:simpleclient_pushgateway:0.6.0' + dependency 'io.prometheus:simpleclient:0.7.0' + dependency 'io.prometheus:simpleclient_common:0.7.0' + dependency 'io.prometheus:simpleclient_hotspot:0.7.0' + dependency 'io.prometheus:simpleclient_pushgateway:0.7.0' - dependency 'io.reactivex.rxjava2:rxjava:2.2.10' + dependency 'io.reactivex.rxjava2:rxjava:2.2.13' dependency 'io.vertx:vertx-auth-jwt:3.8.0' dependency 'io.vertx:vertx-codegen:3.8.0' @@ -56,34 +55,32 @@ dependencyManagement { dependency 'junit:junit:4.12' - dependencySet(group: 'org.apache.tuweni', version: '0.9.0-20190709195335') { - entry 'tuweni-bytes' - entry 'tuweni-io' - entry 'tuweni-config' - entry 'tuweni-crypto' - entry 'tuweni-toml' - } + dependency 'org.apache.tuweni:tuweni-bytes:0.9.0-20190709195335' + dependency 'org.apache.tuweni:tuweni-io:0.9.0-20190709195335' + dependency 'org.apache.tuweni:tuweni-config:0.9.0-20190709195335' + dependency 'org.apache.tuweni:tuweni-crypto:0.9.0-20190709195335' + dependency 'org.apache.tuweni:tuweni-toml:0.9.0-20190709195335' dependency 'net.consensys:orion:1.3.2' - dependency 'org.apache.commons:commons-text:1.7' + dependency 'org.apache.commons:commons-text:1.8' - dependency 'org.apache.logging.log4j:log4j-api:2.12.0' - dependency 'org.apache.logging.log4j:log4j-core:2.12.0' - dependency 'org.apache.logging.log4j:log4j-slf4j-impl:2.12.0' + dependency 'org.apache.logging.log4j:log4j-api:2.12.1' + dependency 'org.apache.logging.log4j:log4j-core:2.12.1' + dependency 'org.apache.logging.log4j:log4j-slf4j-impl:2.12.1' - dependency 'org.assertj:assertj-core:3.12.2' + dependency 'org.assertj:assertj-core:3.13.2' - dependency 'org.awaitility:awaitility:3.1.6' + dependency 'org.awaitility:awaitility:4.0.1' - dependency 'org.bouncycastle:bcprov-jdk15on:1.62' + dependency 'org.bouncycastle:bcprov-jdk15on:1.64' dependency 'org.java-websocket:Java-WebSocket:1.4.0' dependency 'org.jupnp:org.jupnp:2.5.2' dependency 'org.jupnp:org.jupnp.support:2.5.2' - dependency 'org.mockito:mockito-core:2.28.2' + dependency 'org.mockito:mockito-core:3.1.0' dependency 'org.openjdk.jmh:jmh-core:1.21' dependency 'org.openjdk.jmh:jmh-generator-annprocess:1.21' @@ -92,7 +89,7 @@ dependencyManagement { dependency 'org.slf4j:slf4j-log4j12:1.7.26' - dependency 'org.springframework.security:spring-security-crypto:5.1.5.RELEASE' + dependency 'org.springframework.security:spring-security-crypto:5.2.0.RELEASE' dependency 'org.web3j:abi:4.5.1' dependency 'org.web3j:core:4.5.1' diff --git a/nat/src/main/java/org/hyperledger/besu/nat/upnp/UpnpNatManager.java b/nat/src/main/java/org/hyperledger/besu/nat/upnp/UpnpNatManager.java index 4c6da4305c3..e7c8db8b062 100644 --- a/nat/src/main/java/org/hyperledger/besu/nat/upnp/UpnpNatManager.java +++ b/nat/src/main/java/org/hyperledger/besu/nat/upnp/UpnpNatManager.java @@ -14,6 +14,9 @@ */ package org.hyperledger.besu.nat.upnp; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -38,10 +41,8 @@ import org.jupnp.registry.Registry; import org.jupnp.registry.RegistryListener; import org.jupnp.support.igd.callback.GetExternalIP; -import org.jupnp.support.igd.callback.GetStatusInfo; import org.jupnp.support.igd.callback.PortMappingAdd; import org.jupnp.support.igd.callback.PortMappingDelete; -import org.jupnp.support.model.Connection; import org.jupnp.support.model.PortMapping; /** @@ -178,23 +179,6 @@ synchronized CompletableFuture getWANIPConnectionService() { return getService(SERVICE_TYPE_WAN_IP_CONNECTION); } - /** - * Get the local address on which we discovered our external IP address. - * - *

This can be useful to distinguish which network interface the external address was - * discovered on. - * - * @return the local address on which our GetExternalIP was discovered on, or an empty value if no - * GetExternalIP query has been performed successfully. - */ - public Optional getDiscoveredOnLocalAddress() { - if (!started) { - throw new IllegalStateException( - "Cannot call getDiscoveredOnLocalAddress() when in stopped state"); - } - return this.discoveredOnLocalAddress; - } - /** * Returns a CompletableFuture that will wait for the given service type to be discovered. No new * query will be performed, and if the service has already been discovered, the future will @@ -225,8 +209,6 @@ public synchronized CompletableFuture queryExternalIPAddress() { * *

Note that this is not synchronized, as it is expected to be called within an * already-synchronized context ({@link #start()}). - * - * @return A CompletableFuture that can be used to query the result (or error). */ private void initiateExternalIpQuery() { discoverService(SERVICE_TYPE_WAN_IP_CONNECTION) @@ -285,46 +267,6 @@ public void failure( }); } - /** - * Sends a UPnP request to the discovered IGD to request status info. - * - * @return A CompletableFuture that can be used to query the result (or error). - */ - public CompletableFuture queryStatusInfo() { - if (!started) { - throw new IllegalStateException("Cannot call queryStatusInfo() when in stopped state"); - } - final CompletableFuture upnpQueryFuture = new CompletableFuture<>(); - - return discoverService(SERVICE_TYPE_WAN_IP_CONNECTION) - .thenCompose( - service -> { - GetStatusInfo callback = - new GetStatusInfo(service) { - @Override - public void success(final Connection.StatusInfo statusInfo) { - upnpQueryFuture.complete(statusInfo); - } - - /** - * Because the underlying jupnp library omits generics info in this method - * signature, we must too when we override it. - */ - @Override - @SuppressWarnings("rawtypes") - public void failure( - final ActionInvocation invocation, - final UpnpResponse operation, - final String msg) { - upnpQueryFuture.completeExceptionally(new Exception(msg)); - } - }; - upnpService.getControlPoint().execute(callback); - - return upnpQueryFuture; - }); - } - /** * Convenience function to call {@link #requestPortForward(PortMapping)} with the following * defaults: @@ -337,12 +279,11 @@ public void failure( * @param port is the port to be used for both internal and external port values * @param protocol is either UDP or TCP * @param description is a free-form description, often displayed in router UIs - * @return A CompletableFuture which will provide the results of the request */ - public CompletableFuture requestPortForward( + public void requestPortForward( final int port, final Protocol protocol, final String description) { - return this.requestPortForward( + this.requestPortForward( new PortMapping( true, new UnsignedIntegerFourBytes(0), @@ -354,45 +295,6 @@ public CompletableFuture requestPortForward( description)); } - /** - * Convenience function to avoid use of PortMapping object. Takes the same arguments as are in a - * PortMapping object and constructs such an object for the caller. - * - *

This method chains to the {@link #requestPortForward(PortMapping)} method. - * - * @param enabled specifies whether or not the PortMapping is enabled - * @param leaseDurationSeconds is the duration of the PortMapping, in seconds - * @param remoteHost is a domain name or IP address used to filter which remote source this - * forwarding can apply to - * @param externalPort is the source port (the port visible to the Internet) - * @param internalPort is the destination port (the port to be forwarded to) - * @param internalClient is the destination host on the local LAN - * @param protocol is either UDP or TCP - * @param description is a free-form description, often displayed in router UIs - * @return A CompletableFuture which will provide the results of the request - */ - public CompletableFuture requestPortForward( - final boolean enabled, - final int leaseDurationSeconds, - final String remoteHost, - final int externalPort, - final int internalPort, - final String internalClient, - final Protocol protocol, - final String description) { - - return this.requestPortForward( - new PortMapping( - enabled, - new UnsignedIntegerFourBytes(leaseDurationSeconds), - remoteHost, - new UnsignedIntegerTwoBytes(externalPort), - new UnsignedIntegerTwoBytes(internalPort), - internalClient, - toJupnpProtocol(protocol), - description)); - } - /** * Sends a UPnP request to the discovered IGD to request a port forward. * @@ -400,9 +302,9 @@ public CompletableFuture requestPortForward( * @return A CompletableFuture that can be used to query the result (or error). */ private CompletableFuture requestPortForward(final PortMapping portMapping) { - if (!started) { - throw new IllegalStateException("Cannot call requestPortForward() when in stopped state"); - } + checkArgument( + portMapping.getInternalPort().getValue() != 0, "Cannot map to internal port zero."); + checkState(started, "Cannot call requestPortForward() when in stopped state"); CompletableFuture upnpQueryFuture = new CompletableFuture<>(); diff --git a/nat/src/test/java/org/hyperledger/besu/nat/upnp/UpnpNatManagerTest.java b/nat/src/test/java/org/hyperledger/besu/nat/upnp/UpnpNatManagerTest.java index 7843d2381cf..f39940c28ee 100644 --- a/nat/src/test/java/org/hyperledger/besu/nat/upnp/UpnpNatManagerTest.java +++ b/nat/src/test/java/org/hyperledger/besu/nat/upnp/UpnpNatManagerTest.java @@ -100,33 +100,21 @@ public void startDoesNothingWhenAlreadyStarted() throws Exception { } @Test - public void getDiscoveredOnLocalAddressThrowsWhenCalledBeforeStart() throws Exception { - - assertThatThrownBy( - () -> { - upnpManager.getDiscoveredOnLocalAddress(); - }) - .isInstanceOf(IllegalStateException.class); - } - - @Test - public void queryStatusInfoThrowsWhenCalledBeforeStart() throws Exception { + public void requestPortForwardThrowsWhenCalledBeforeStart() throws Exception { assertThatThrownBy( () -> { - upnpManager.queryStatusInfo(); + upnpManager.requestPortForward(80, UpnpNatManager.Protocol.TCP, ""); }) .isInstanceOf(IllegalStateException.class); } @Test - public void requestPortForwardThrowsWhenCalledBeforeStart() throws Exception { + public void requestPortForwardThrowsWhenPortIsZero() { + upnpManager.start(); - assertThatThrownBy( - () -> { - upnpManager.requestPortForward(0, UpnpNatManager.Protocol.TCP, ""); - }) - .isInstanceOf(IllegalStateException.class); + assertThatThrownBy(() -> upnpManager.requestPortForward(0, UpnpNatManager.Protocol.TCP, "")) + .isInstanceOf(IllegalArgumentException.class); } @Test diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 880d22cb10b..29266569caa 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -56,7 +56,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'b8BCiNvy9vSYsTtS1NfszsVT0EMV8tiNc7igzXzTrak=' + knownHash = 'EzyP5PAUCOxCe4TLjOD8igvg7LejQp/727hnvjBMlwY=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/PropagatedBlockContext.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/PropagatedBlockContext.java new file mode 100644 index 00000000000..518776b4955 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/PropagatedBlockContext.java @@ -0,0 +1,36 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.plugin.data; + +import org.hyperledger.besu.plugin.Unstable; + +/** The minimum set of data for a PropagatedBlockContext. */ +@Unstable +public interface PropagatedBlockContext { + + /** + * A {@link BlockHeader} object. + * + * @return A {@link BlockHeader} + */ + BlockHeader getBlockHeader(); + + /** + * A scalar value corresponding to the total difficulty. + * + * @return A scalar value corresponding to the total difficulty. + */ + Quantity getTotalDifficulty(); +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/SyncStatus.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/SyncStatus.java index 7cb406f7f5d..2bad5ad44a4 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/SyncStatus.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/SyncStatus.java @@ -39,11 +39,4 @@ public interface SyncStatus { * @return the height of the highest known block. */ long getHighestBlock(); - - /** - * Checks if the synchronizer is within a default sync tolerance of the highest known block - * - * @return true if it is within the tolerance, false otherwise - */ - boolean inSync(); } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/Transaction.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/Transaction.java index 1c022831a03..9c4b63a8afa 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/Transaction.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/Transaction.java @@ -32,6 +32,13 @@ @Unstable public interface Transaction { + /** + * The Keccak 256-bit hash of this transaction. + * + * @return The Keccak 256-bit hash of this transaction. + */ + Hash getHash(); + /** * A scalar value equal to the number of transactions sent by the sender. * @@ -129,4 +136,16 @@ public interface Transaction { * @return if present, the message call data */ Optional getData(); + + /** + * The data payload of this transaction. + * + *

If this transaction is a message-call to an account (the {@link #getTo} field is present), + * this same value will be exposed by {@link #getData}. If instead this is a contract-creation + * transaction (the {@link #getTo} field is absent), the payload is also exposed by {@link + * #getInit}. + * + * @return the transaction payload + */ + UnformattedData getPayload(); } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java index 930a9755ab5..62ef32ae3f5 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java @@ -15,10 +15,12 @@ package org.hyperledger.besu.plugin.services; import org.hyperledger.besu.plugin.Unstable; -import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.PropagatedBlockContext; import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.plugin.data.Transaction; +import java.util.Optional; + /** * This service allows plugins to attach to various events during the normal operation of Besu. * @@ -109,9 +111,9 @@ interface BlockPropagatedListener { *

The block may not have been imported to the local chain yet and may fail later * validations. * - * @param blockHeader the new block header. + * @param propagatedBlockContext block being propagated. */ - void onBlockPropagated(BlockHeader blockHeader); + void onBlockPropagated(PropagatedBlockContext propagatedBlockContext); } /** The listener interface for receiving new transaction added events. */ @@ -144,6 +146,6 @@ interface SyncStatusListener { * * @param syncStatus the sync status */ - void onSyncStatusChanged(SyncStatus syncStatus); + void onSyncStatusChanged(Optional syncStatus); } } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/PoAMetricsService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/PoAMetricsService.java index 96bfcc4501f..2e19254a058 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/PoAMetricsService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/PoAMetricsService.java @@ -21,7 +21,11 @@ /** * Provides relevant data for producing metrics on the status of a Proof of Authority (PoA) node. + * + * @deprecated This interface has been replaced by {@link + * org.hyperledger.besu.plugin.services.query.PoaQueryService} */ +@Deprecated public interface PoAMetricsService { /** diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/query/IbftQueryService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/query/IbftQueryService.java new file mode 100644 index 00000000000..e8f5f0e8e39 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/query/IbftQueryService.java @@ -0,0 +1,41 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.plugin.services.query; + +import org.hyperledger.besu.plugin.data.Address; +import org.hyperledger.besu.plugin.data.BlockHeader; + +import java.util.Collection; + +/** Allows for the IBFT 2.0 specific aspects of the block chain to be queried. */ +public interface IbftQueryService extends PoaQueryService { + + /** + * Extracts the round number from the supplied header and returns it to the caller. + * + * @param header the block header from which the round number is to be extracted + * @return The number of failed rounds executed prior to adding the block to the chain. + */ + int getRoundNumberFrom(final BlockHeader header); + + /** + * Extracts the collection of signers from the supplied block header and returns them to the + * caller. + * + * @param header the block header from which a list of signers is to be extracted + * @return The addresses of + */ + Collection

getSignersFrom(final BlockHeader header); +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/query/PoaQueryService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/query/PoaQueryService.java new file mode 100644 index 00000000000..1404ba8aae2 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/query/PoaQueryService.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.plugin.services.query; + +import org.hyperledger.besu.plugin.data.Address; +import org.hyperledger.besu.plugin.data.BlockHeader; + +import java.util.Collection; + +/** Provides methods to query the status of a Proof of Authority (PoA) network. */ +public interface PoaQueryService { + + /** + * Retrieves the validators specified in the latest block from the canonical chain. + * + * @return Addresses of all validators in the latest canonical block. + */ + Collection
getValidatorsForLatestBlock(); + + /** + * Retrieves the {@link Address} for the proposer of a block on the canonical chain. + * + * @param header The {@link BlockHeader} for which the proposer will be found. + * @return The identity of the proposer for the given block. + */ + Address getProposerOfBlock(final BlockHeader header); +} diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/RocksDBCLIOptions.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/RocksDBCLIOptions.java index 679a47c2279..68c37ca473f 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/RocksDBCLIOptions.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/RocksDBCLIOptions.java @@ -24,11 +24,12 @@ public class RocksDBCLIOptions { public static final int DEFAULT_MAX_BACKGROUND_COMPACTIONS = 4; public static final int DEFAULT_BACKGROUND_THREAD_COUNT = 4; - private static final String MAX_OPEN_FILES_FLAG = "--Xrocksdb-max-open-files"; - private static final String CACHE_CAPACITY_FLAG = "--Xrocksdb-cache-capacity"; + private static final String MAX_OPEN_FILES_FLAG = "--Xplugin-rocksdb-max-open-files"; + private static final String CACHE_CAPACITY_FLAG = "--Xplugin-rocksdb-cache-capacity"; private static final String MAX_BACKGROUND_COMPACTIONS_FLAG = - "--Xrocksdb-max-background-compactions"; - private static final String BACKGROUND_THREAD_COUNT_FLAG = "--Xrocksdb-background-thread-count"; + "--Xplugin-rocksdb-max-background-compactions"; + private static final String BACKGROUND_THREAD_COUNT_FLAG = + "--Xplugin-rocksdb-background-thread-count"; @CommandLine.Option( names = {MAX_OPEN_FILES_FLAG}, diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBCLIOptionsTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBCLIOptionsTest.java index 752283980ba..d9a256328d9 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBCLIOptionsTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBCLIOptionsTest.java @@ -28,11 +28,12 @@ public class RocksDBCLIOptionsTest { - private static final String MAX_OPEN_FILES_FLAG = "--Xrocksdb-max-open-files"; - private static final String CACHE_CAPACITY_FLAG = "--Xrocksdb-cache-capacity"; + private static final String MAX_OPEN_FILES_FLAG = "--Xplugin-rocksdb-max-open-files"; + private static final String CACHE_CAPACITY_FLAG = "--Xplugin-rocksdb-cache-capacity"; private static final String MAX_BACKGROUND_COMPACTIONS_FLAG = - "--Xrocksdb-max-background-compactions"; - private static final String BACKGROUND_THREAD_COUNT_FLAG = "--Xrocksdb-background-thread-count"; + "--Xplugin-rocksdb-max-background-compactions"; + private static final String BACKGROUND_THREAD_COUNT_FLAG = + "--Xplugin-rocksdb-background-thread-count"; @Test public void defaultValues() { diff --git a/scripts/dco_check.sh b/scripts/dco_check.sh new file mode 100755 index 00000000000..86716237f71 --- /dev/null +++ b/scripts/dco_check.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +status=0 +while IFS= read -r -a line; do + my_array+=( "$line" ) + done < <( git branch -r | grep -v origin/HEAD ) +for branch in "${my_array[@]}" +do + branch=$(echo "$branch" | xargs) + echo "Checking commits in branch $branch for commits missing DCO..." + while read -r results; do + status=1 + commit_hash="$(echo "$results" | cut -d' ' -f1)" + >&2 echo "$commit_hash is missing Signed-off-by line." + done < <(git log "$branch" --no-merges --pretty="%H %ae" --grep 'Signed-off-by' --invert-grep -- ) +done + +exit $status