Merge branch 'main' into zkbesu

# Conflicts:
#	.github/workflows/acceptance-tests.yml
#	.github/workflows/pre-review.yml
#	build.gradle
This commit is contained in:
Fabio Di Fabio
2024-09-06 16:30:57 +02:00
153 changed files with 6623 additions and 3475 deletions

View File

@@ -7,9 +7,14 @@
### Breaking Changes
### Additions and Improvements
- Include current chain head block when computing `eth_maxPriorityFeePerGas` [#7485](https://github.com/hyperledger/besu/pull/7485)
- Update Java and Gradle dependecies [#7571](https://github.com/hyperledger/besu/pull/7571)
- Layered txpool: new options `--tx-pool-min-score` to remove a tx from pool when its score is lower than the specified value [#7576](https://github.com/hyperledger/besu/pull/7576)
- Add `engine_getBlobsV1` method to the Engine API [#7553](https://github.com/hyperledger/besu/pull/7553)
### Bug fixes
- Layered txpool: do not send notifications when moving tx between layers [#7539](https://github.com/hyperledger/besu/pull/7539)
- Layered txpool: fix for unsent drop notifications on remove [#7538](https://github.com/hyperledger/besu/pull/7538)
- Honor block number or tag parameter in eth_estimateGas and eth_createAccessList [#7502](https://github.com/hyperledger/besu/pull/7502)
## 24.9.0
@@ -25,6 +30,8 @@
- Implement engine_getClientVersionV1 [#7512](https://github.com/hyperledger/besu/pull/7512)
- Performance optimzation for ECMUL (1 of 2) [#7509](https://github.com/hyperledger/besu/pull/7509)
- Performance optimzation for ECMUL (2 of 2) [#7543](https://github.com/hyperledger/besu/pull/7543)
- Include current chain head block when computing `eth_maxPriorityFeePerGas` [#7485](https://github.com/hyperledger/besu/pull/7485)
- Remove (old) documentation updates from the changelog [#7562](https://github.com/hyperledger/besu/pull/7562)
### Bug fixes
- Fix tracing in precompiled contracts when halting for out of gas [#7318](https://github.com/hyperledger/besu/issues/7318)
@@ -33,6 +40,8 @@
- Correctly drops messages that exceeds local message size limit [#5455](https://github.com/hyperledger/besu/pull/7507)
- **DebugMetrics**: Fixed a `ClassCastException` occurring in `DebugMetrics` when handling nested metric structures. Previously, `Double` values within these structures were incorrectly cast to `Map` objects, leading to errors. This update allows for proper handling of both direct values and nested structures at the same level. Issue# [#7383](https://github.com/hyperledger/besu/pull/7383)
- `evmtool` was not respecting the `--genesis` setting, resulting in unexpected trace results. [#7433](https://github.com/hyperledger/besu/pull/7433)
- The genesis config override `contractSizeLimit`q was not wired into code size limits [#7557](https://github.com/hyperledger/besu/pull/7557)
- Fix incorrect key filtering in LayeredKeyValueStorage stream [#7535](https://github.com/hyperledger/besu/pull/7557)
## 24.8.0
@@ -3005,10 +3014,7 @@ For compatibility with ETC Agharta upgrade, use 1.3.7 or later.
- Performance improvements:
* Multithread Websockets to increase throughput [\#231](https://github.com/hyperledger/besu/pull/231)
* NewBlockHeaders performance improvement [\#230](https://github.com/hyperledger/besu/pull/230)
- EIP2384 - Ice Age Adustment around Istanbul [\#211](https://github.com/hyperledger/besu/pull/211)
- Documentation updates include:
* [Configuring mining using the Stratum protocol](https://besu.hyperledger.org/en/latest/HowTo/Configure/Configure-Mining/)
* [ETC network command line options](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Syntax/#network)
- EIP2384 - Ice Age Adjustment around Istanbul [\#211](https://github.com/hyperledger/besu/pull/211)
- Hard Fork Support:
* MuirGlacier for Ethereum Mainnet and Ropsten Testnet
* Agharta for Kotti and Mordor Testnets
@@ -3134,16 +3140,6 @@ For compatibility with ETC Agharta upgrade, use 1.3.7 or later.
- 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)
- Documentation updates include:
- Added [sample load balancer configurations](https://besu.hyperledger.org/en/latest/HowTo/Configure/Configure-HA/Sample-Configuration/)
- Added [`retesteth`](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Subcommands/#retesteth) subcommand
- Added [`debug_accountRange`](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#debug_accountrange) JSON-RPC API method
- Clarified purpose of [static nodes](https://besu.hyperledger.org/en/latest/HowTo/Find-and-Connect/Managing-Peers/#static-nodes)
- Added links [Kubernetes reference implementations](https://besu.hyperledger.org/en/latest/HowTo/Deploy/Kubernetes/)
- Added content about [access between private and public states](https://besu.hyperledger.org/en/latest/Concepts/Privacy/Privacy-Groups/#access-between-states)
- Added restriction that [account permissioning cannot be used with random key signing](https://besu.hyperledger.org/en/latest/HowTo/Use-Privacy/Sign-Privacy-Marker-Transactions/).
- Added high availability requirement for [private transaction manager](https://besu.hyperledger.org/en/latest/Concepts/Privacy/Privacy-Overview/#availability) (ie, Orion)
- Added [genesis file reference](https://besu.hyperledger.org/en/latest/Reference/Config-Items/)
### Technical Improvements
@@ -3213,11 +3209,6 @@ For compatibility with ETC Agharta upgrade, use 1.3.7 or later.
- Added eea\_getTransactionCount Json Rpc [\#1861](https://github.com/PegaSysEng/pantheon/pull/1861)
- PrivacyMarkerTransaction to be signed with a randomly generated key [\#1844](https://github.com/PegaSysEng/pantheon/pull/1844)
- Implement eth\_getproof JSON RPC API [\#1824](https://github.com/PegaSysEng/pantheon/pull/1824) (thanks to [matkt](https://github.com/matkt))
- Documentation updates include:
- [Improved navigation](https://docs.pantheon.pegasys.tech/en/latest/)
- [Added permissioning diagram](https://docs.pantheon.pegasys.tech/en/latest/Concepts/Permissioning/Permissioning-Overview/#onchain)
- [Added Responsible Disclosure policy](https://docs.pantheon.pegasys.tech/en/latest/Reference/Responsible-Disclosure/)
- [Added `blocks export` subcommand](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Subcommands/#export)
### Technical Improvements
- Update the `pantheon blocks export` command usage [\#1887](https://github.com/PegaSysEng/pantheon/pull/1887) (thanks to [matkt](https://github.com/matkt))
@@ -3325,18 +3316,10 @@ For compatibility with ETC Agharta upgrade, use 1.3.7 or later.
- Added JSON-RPC API to report validator block production information [#1687](https://github.com/PegaSysEng/pantheon/pull/1687) (thanks to [matkt](https://github.com/matkt))
- Added Mark Sweep Pruner [#1638](https://github.com/PegaSysEng/pantheon/pull/1638)
- Added the Blake2b F compression function as a precompile in Besu [#1614](https://github.com/PegaSysEng/pantheon/pull/1614) (thanks to [iikirilov](https://github.com/iikirilov))
- Documentation updates include:
- Added CPU requirements [#1734](https://github.com/PegaSysEng/pantheon/pull/1734)
- Added reference to Ansible role [#1733](https://github.com/PegaSysEng/pantheon/pull/1733)
- Updated revert reason example [#1754](https://github.com/PegaSysEng/pantheon/pull/1754)
- Added content on deploying for production [#1774](https://github.com/PegaSysEng/pantheon/pull/1774)
- Updated docker docs for location of data path [#1790](https://github.com/PegaSysEng/pantheon/pull/1790)
- Updated permissiong documentation
[#1792](https://github.com/PegaSysEng/pantheon/pull/1792)
[#1652](https://github.com/PegaSysEng/pantheon/pull/1652)
- Added permissioning webinar in the resources [#1717](https://github.com/PegaSysEng/pantheon/pull/1717)
- Add web3.js-eea reference doc [#1617](https://github.com/PegaSysEng/pantheon/pull/1617)
- Updated privacy documentation
[#1650](https://github.com/PegaSysEng/pantheon/pull/1650)
[#1721](https://github.com/PegaSysEng/pantheon/pull/1721)
[#1722](https://github.com/PegaSysEng/pantheon/pull/1722)
@@ -3359,9 +3342,7 @@ For compatibility with ETC Agharta upgrade, use 1.3.7 or later.
[#1803](https://github.com/PegaSysEng/pantheon/pull/1803)
[#1810](https://github.com/PegaSysEng/pantheon/pull/1810)
[#1817](https://github.com/PegaSysEng/pantheon/pull/1817)
- Added documentation for getSignerMetrics [#1723](https://github.com/PegaSysEng/pantheon/pull/1723) (thanks to [matkt](https://github.com/matkt))
- Added Java 11+ as a prerequisite for installing Besu using Homebrew. [#1755](https://github.com/PegaSysEng/pantheon/pull/1755)
- Fixed documentation formatting and typos [#1718](https://github.com/PegaSysEng/pantheon/pull/1718)
[#1742](https://github.com/PegaSysEng/pantheon/pull/1742)
[#1763](https://github.com/PegaSysEng/pantheon/pull/1763)
[#1779](https://github.com/PegaSysEng/pantheon/pull/1779)
@@ -3391,25 +3372,6 @@ For compatibility with ETC Agharta upgrade, use 1.3.7 or later.
- Add eea\_findPrivacyGroup endpoint to Besu [\#1635](https://github.com/PegaSysEng/pantheon/pull/1635) (thanks to [Puneetha17](https://github.com/Puneetha17))
- Updated eea send raw transaction with privacy group ID [\#1611](https://github.com/PegaSysEng/pantheon/pull/1611) (thanks to [iikirilov](https://github.com/iikirilov))
- Added Revert Reason [\#1603](https://github.com/PegaSysEng/pantheon/pull/1603)
- Documentation updates include:
- Added [UPnP content](https://besu.hyperledger.org/en/latest/HowTo/Find-and-Connect/Using-UPnP/)
- Added [load balancer image](https://besu.hyperledger.org/en/stable/)
- Added [revert reason](https://besu.hyperledger.org/en/latest/HowTo/Send-Transactions/Revert-Reason/)
- Added [admin\_changeLogLevel](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#admin_changeloglevel) JSON RPC API (thanks to [matkt](https://github.com/matkt))
- Updated for [new Docker image](https://besu.hyperledger.org/en/stable/)
- Added [Docker image migration content](https://besu.hyperledger.org/en/latest/HowTo/Get-Started/Migration-Docker/)
- Added [transaction validation content](https://besu.hyperledger.org/en/latest/Concepts/Transactions/Transaction-Validation/)
- Updated [permissioning overview](https://besu.hyperledger.org/en/stable/) for onchain account permissioning
- Updated [quickstart](https://besu.hyperledger.org/en/latest/HowTo/Deploy/Monitoring-Performance/#monitor-node-performance-using-prometheus) to include Prometheus and Grafana
- Added [remote connections limits options](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Syntax/#remote-connections-limit-enabled)
- Updated [web3.js-eea reference](https://docs.pantheon.pegasys.tech/en/latest/Reference/web3js-eea-Methods/) to include privacy group methods
- Updated [onchain permissioning to include account permissioning](hhttps://besu.hyperledger.org/en/latest/Concepts/Permissioning/Onchain-Permissioning/) and [Permissioning Management Dapp](https://besu.hyperledger.org/en/latest/Tutorials/Permissioning/Getting-Started-Onchain-Permissioning/#start-the-development-server-for-the-permissioning-management-dapp)
- Added [deployment procedure for Permissioning Management Dapp](https://besu.hyperledger.org/en/stable/)
- Added privacy content for [EEA-compliant and Besu-extended privacy](https://besu.hyperledger.org/en/latest/Concepts/Privacy/Privacy-Groups/)
- Added content on [creating and managing privacy groups](https://besu.hyperledger.org/en/latest/Reference/web3js-eea-Methods/#createprivacygroup)
- Added content on [accessing private and privacy marker transactions](https://besu.hyperledger.org/en/latest/HowTo/Use-Privacy/Access-Private-Transactions/)
- Added content on [system requirements](https://besu.hyperledger.org/en/latest/HowTo/Get-Started/System-Requirements/)
- Added reference to [Besu role on Galaxy to deploy using Ansible](https://besu.hyperledger.org/en/latest/HowTo/Deploy/Ansible/).
### Technical Improvements
@@ -3478,12 +3440,6 @@ For compatibility with ETC Agharta upgrade, use 1.3.7 or later.
- Print Besu version when starting [\#1593](https://github.com/PegaSysEng/pantheon/pull/1593)
- \[PAN-2746\] Add eea\_createPrivacyGroup & eea\_deletePrivacyGroup endpoint [\#1560](https://github.com/PegaSysEng/pantheon/pull/1560) (thanks to [Puneetha17](https://github.com/Puneetha17))
Documentation updates include:
- Added [readiness and liveness endpoints](https://besu.hyperledger.org/en/latest/HowTo/Interact/APIs/Using-JSON-RPC-API/#readiness-and-liveness-endpoints)
- Added [high availability content](https://besu.hyperledger.org/en/latest/HowTo/Configure/Configure-HA/High-Availability/)
- Added [web3js-eea client library](https://besu.hyperledger.org/en/latest/Tutorials/Quickstarts/Privacy-Quickstart/#clone-eeajs-libraries)
- Added content on [setting CLI options using environment variables](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Syntax/#specifying-options)
### Technical Improvements
- Read config from env vars when no config file specified [\#1639](https://github.com/PegaSysEng/pantheon/pull/1639)
@@ -3532,16 +3488,6 @@ Documentation updates include:
- Add subscribe and unsubscribe count metrics [\#1541](https://github.com/PegaSysEng/pantheon/pull/1541)
- Add pivot block metrics [\#1537](https://github.com/PegaSysEng/pantheon/pull/1537)
Documentation updates include:
- Updated [IBFT 2.0 tutorial](https://besu.hyperledger.org/en/latest/Tutorials/Private-Network/Create-IBFT-Network/) to use network configuration tool
- Added [debug\_traceBlock\* methods](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#debug_traceblock)
- Reorganised [monitoring documentation](https://besu.hyperledger.org/en/latest/HowTo/Deploy/Monitoring-Performance/)
- Added [link to sample Grafana dashboard](https://besu.hyperledger.org/en/latest/HowTo/Deploy/Monitoring-Performance/#monitor-node-performance-using-prometheus)
- Added [note about replacing transactions in transaction pool](https://besu.hyperledger.org/en/latest/Concepts/Transactions/Transaction-Pool/#replacing-transactions-with-same-nonce)
- Updated [example transaction scripts](https://besu.hyperledger.org/en/latest/HowTo/Send-Transactions/Transactions/#example-javascript-scripts)
- Updated [Alethio Ethstats and Explorer documentation](https://besu.hyperledger.org/en/latest/Concepts/AlethioOverview/)
### Technical Improvements
- PAN-2816: Hiding experimental account permissioning cli options [\#1584](https://github.com/PegaSysEng/pantheon/pull/1584)
@@ -3577,14 +3523,6 @@ Documentation updates include:
### Additions and Improvements
Documentation updates include:
- Added [GraphQL options](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Syntax/#graphql-http-cors-origins)
- Added [troubleshooting point about illegal reflective access error](https://besu.hyperledger.org/en/latest/HowTo/Troubleshoot/Troubleshooting/#illegal-reflective-access-error-on-startup)
- Added [trusted bootnode behaviour for permissioning](https://besu.hyperledger.org/en/latest/Concepts/Permissioning/Onchain-Permissioning/#bootnodes)
- Added [how to obtain a WS authentication token](https://besu.hyperledger.org/en/latest/HowTo/Interact/APIs/Authentication/#obtaining-an-authentication-token)
- Updated [example scripts and added package.json file for creating signed transactions](https://besu.hyperledger.org/en/latest/HowTo/Send-Transactions/Transactions/)
### Technical Improvements
- Replaced Void datatype with void [\#1530](https://github.com/PegaSysEng/pantheon/pull/1530)
@@ -3633,12 +3571,6 @@ Documentation updates include:
- Added [`--tx-pool-retention-hours`](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Syntax/#tx-pool-retention-hours) [\#1333](https://github.com/PegaSysEng/pantheon/pull/1333)
- Added Genesis file support for specifying the maximum stack size. [\#1431](https://github.com/PegaSysEng/pantheon/pull/1431)
- Included transaction details when subscribed to Pending transactions [\#1410](https://github.com/PegaSysEng/pantheon/pull/1410)
- Documentation updates include:
- [Added configuration items specified in the genesis file](https://besu.hyperledger.org/en/latest/Reference/Config-Items/#configuration-items)
- [Added pending transaction details subscription](https://besu.hyperledger.org/en/latest/HowTo/Interact/APIs/RPC-PubSub/#pending-transactionss)
- [Added Troubleshooting content](https://besu.hyperledger.org/en/latest/HowTo/Troubleshoot/Troubleshooting/)
- [Added Privacy Quickstart](https://besu.hyperledger.org/en/latest/Tutorials/Quickstarts/Privacy-Quickstart/)
- [Added privacy roadmap](https://github.com/hyperledger/besu/blob/master/ROADMAP.md)
### Technical Improvements
@@ -3746,12 +3678,6 @@ Documentation updates include:
- [Privacy](https://besu.hyperledger.org/en/latest/Concepts/Privacy/Privacy-Overview/)
- [Onchain Permissioning](https://besu.hyperledger.org/en/latest/Concepts/Permissioning/Permissioning-Overview/#onchain)
- [Fastsync](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Syntax/#fast-sync-min-peers)
- Documentation updates include:
- Added JSON-RPC methods:
- [`txpool_pantheonStatistics`](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#txpool_besustatistics)
- [`net_services`](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#net_services)
- [Updated to indicate Docker image doesn't run on Windows](https://besu.hyperledger.org/en/latest/HowTo/Get-Started/Run-Docker-Image/)
- [Added how to configure a free gas network](https://besu.hyperledger.org/en/latest/HowTo/Configure/FreeGas/)
### Technical Improvements
@@ -3805,17 +3731,6 @@ Documentation updates include:
### Additions and Improvements
- Notify of dropped messages [\#1156](https://github.com/PegaSysEng/pantheon/pull/1156)
- Documentation updates include:
- Added [Permissioning Overview](https://besu.hyperledger.org/en/latest/Concepts/Permissioning/Permissioning-Overview/)
- Added content on [Network vs Node Configuration](https://besu.hyperledger.org/en/latest/HowTo/Configure/Using-Configuration-File/)
- Updated [RAM requirements](https://besu.hyperledger.org/en/latest/HowTo/Get-Started/System-Requirements/#ram)
- Added [Privacy Overview](https://besu.hyperledger.org/en/latest/Concepts/Privacy/Privacy-Overview/) and [Processing Private Transactions](https://besu.hyperledger.org/en/latest/Concepts/Privacy/Private-Transaction-Processing/)
- Renaming of Ethstats Lite Explorer to [Ethereum Lite Explorer](https://besu.hyperledger.org/en/latest/HowTo/Deploy/Lite-Block-Explorer/#lite-block-explorer-documentation) (thanks to [tzapu](https://github.com/tzapu))
- Added content on using [Truffle with Besu](https://besu.hyperledger.org/en/latest/HowTo/Develop-Dapps/Truffle/)
- Added [`droppedPendingTransactions` RPC Pub/Sub subscription](https://besu.hyperledger.org/en/latest/HowTo/Interact/APIs/RPC-PubSub/#dropped-transactions)
- Added [`eea_*` JSON-RPC API methods](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#eea-methods)
- Added [architecture diagram](https://besu.hyperledger.org/en/latest/Concepts/ArchitectureOverview/)
- Updated [permissioning CLI options](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Syntax/#permissions-accounts-config-file-enabled) and [permissioned network tutorial](https://besu.hyperledger.org/en/stable/)
### Technical Improvements
@@ -3870,31 +3785,6 @@ Documentation updates include:
- Added PendingTransactions JSON-RPC [\#1043](https://github.com/PegaSysEng/pantheon/pull/1043) (thanks to [EdwinLeeGreene](https://github.com/EdwinLeeGreene))
- Added `admin_nodeInfo` JSON-RPC [\#1012](https://github.com/PegaSysEng/pantheon/pull/1012)
- Added `--metrics-category` CLI to only enable select metrics [\#969](https://github.com/PegaSysEng/pantheon/pull/969)
- Documentation updates include:
- Updated endpoints in [Private Network Quickstart](https://besu.hyperledger.org/en/latest/Tutorials/Quickstarts/Private-Network-Quickstart/) (thanks to [laubai](https://github.com/laubai))
- Updated [documentation contribution guidelines](https://besu.hyperledger.org/en/stable/)
- Added [`admin_removePeer`](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#admin_removepeer)
- Updated [tutorials](https://besu.hyperledger.org/en/latest/Tutorials/Private-Network/Create-Private-Clique-Network/) for printing of enode on startup
- Added [`txpool_pantheonTransactions`](https://besu.hyperledger.org/en/stable/Reference/API-Methods/#txpool_besutransactions)
- Added [Transaction Pool content](https://besu.hyperledger.org/en/latest/Concepts/Transactions/Transaction-Pool/)
- Added [`tx-pool-max-size` CLI option](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Syntax/#tx-pool-max-size)
- Updated [developer build instructions to use installDist](https://besu.hyperledger.org/en/stable/)
- Added [Azure quickstart tutorial](https://besu.hyperledger.org/en/latest/Tutorials/Quickstarts/Azure-Private-Network-Quickstart/)
- Enabled copy button in code blocks
- Added [IBFT 1.0](https://besu.hyperledger.org/en/latest/HowTo/Configure/Consensus-Protocols/QuorumIBFT/)
- Added section on using [Geth attach with Besu](https://besu.hyperledger.org/en/latest/HowTo/Interact/APIs/Using-JSON-RPC-API/#geth-console)
- Enabled the edit link doc site to ease external doc contributions
- Added [EthStats docs](https://besu.hyperledger.org/HowTo/Deploy/Lite-Network-Monitor/) (thanks to [baxy](https://github.com/baxy))
- Updated [Postman collection](https://besu.hyperledger.org/en/latest/HowTo/Interact/APIs/Authentication/#postman)
- Added [`metrics-category` CLI option](https://besu.hyperledger.org/en/latest/Reference/CLI/CLI-Syntax/#metrics-category)
- Added information on [block time and timeout settings](https://besu.hyperledger.org/en/latest/HowTo/Configure/Consensus-Protocols/IBFT/#block-time) for IBFT 2.0
- Added [`admin_nodeInfo`](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#admin_nodeinfo)
- Added [permissions images](https://besu.hyperledger.org/en/latest/Concepts/Permissioning/Permissioning-Overview/)
- Added permissioning blog to [Resources](https://besu.hyperledger.org/en/latest/Reference/Resources/)
- Updated [Create Permissioned Network](https://besu.hyperledger.org/en/latest/Tutorials/Permissioning/Create-Permissioned-Network/) tutorial to use `export-address`
- Updated [Clique](https://besu.hyperledger.org/en/latest/HowTo/Configure/Consensus-Protocols/Clique/) and [IBFT 2.0](https://besu.hyperledger.org/en/latest/HowTo/Configure/Consensus-Protocols/IBFT/) docs to include complete genesis file
- Updated [Clique tutorial](https://besu.hyperledger.org/en/latest/Tutorials/Private-Network/Create-Private-Clique-Network/) to use `export-address` subcommand
- Added IBFT 2.0 [future message configuration options](https://besu.hyperledger.org/en/latest/HowTo/Configure/Consensus-Protocols/IBFT/#optional-configuration-options)
### Technical Improvements
- Fixed so self persists to the whitelist [\#1176](https://github.com/PegaSysEng/pantheon/pull/1176)
@@ -4039,8 +3929,6 @@ Public key address export subcommand was missing in 1.0 release.
### Additions and Improvements
- Added `public-key export-address` subcommand [\#888](https://github.com/PegaSysEng/pantheon/pull/888)
- Documentation update for the [`public-key export-address`](https://besu.hyperledger.org/en/stable/) subcommand.
- Updated [IBFT 2.0 overview](https://besu.hyperledger.org/en/stable/) to include use of `rlp encode` command and information on setting IBFT 2.0 properties to achieve your desired block time.
## 1.0
@@ -4051,16 +3939,7 @@ Public key address export subcommand was missing in 1.0 release.
- Added `rlp encode` subcommand [\#965](https://github.com/PegaSysEng/pantheon/pull/965)
- Method to reload permissions file [\#834](https://github.com/PegaSysEng/pantheon/pull/834)
- Added rebind mitigation for Websockets. [\#905](https://github.com/PegaSysEng/pantheon/pull/905)
- Support genesis contract code [\#749](https://github.com/PegaSysEng/pantheon/pull/749) (thanks to [kziemianek](https://github.com/kziemianek)).
- Documentation updates include:
- Added details on [port configuration](https://besu.hyperledger.org/en/latest/HowTo/Find-and-Connect/Configuring-Ports/)
- Added [Resources page](https://besu.hyperledger.org/en/latest/Reference/Resources/) linking to Besu blog posts and webinars
- Added [JSON-RPC Authentication](https://besu.hyperledger.org/en/latest/HowTo/Interact/APIs/Authentication/)
- Added [tutorial to create permissioned network](https://besu.hyperledger.org/en/latest/Tutorials/Permissioning/Create-Permissioned-Network/)
- Added [Permissioning](https://besu.hyperledger.org/en/latest/Concepts/Permissioning/Permissioning-Overview/) content
- Added [Permissioning API methods](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#permissioning-methods)
- Added [tutorial to create Clique private network](https://besu.hyperledger.org/en/latest/Tutorials/Private-Network/Create-Private-Clique-Network/)
- Added [tutorial to create IBFT 2.0 private network](https://besu.hyperledger.org/en/latest/Tutorials/Private-Network/Create-IBFT-Network/)
- Support genesis contract code [\#749](https://github.com/PegaSysEng/pantheon/pull/749) (thanks to [kziemianek](https://github.com/kziemianek))
### Technical Improvements
- RoundChangeCertificateValidator requires unique authors [\#997](https://github.com/PegaSysEng/pantheon/pull/997)
@@ -4204,7 +4083,7 @@ Public key address export subcommand was missing in 1.0 release.
- Updated IbftRound and RoundState APIs to use wrapped messages [\#740](https://github.com/PegaSysEng/pantheon/pull/740)
- Exception handling [\#739](https://github.com/PegaSysEng/pantheon/pull/739)
- Upgrade dependency versions and build cleanup [\#738](https://github.com/PegaSysEng/pantheon/pull/738)
- Update IbftBlockHeigntManager to accept new message types. [\#737](https://github.com/PegaSysEng/pantheon/pull/737)
- Update IbftBlockHeightManager to accept new message types. [\#737](https://github.com/PegaSysEng/pantheon/pull/737)
- Error response handling for permissions APIs [\#736](https://github.com/PegaSysEng/pantheon/pull/736)
- IPV6 bootnodes don't work [\#735](https://github.com/PegaSysEng/pantheon/pull/735)
- Updated to use tags of pantheon build rather than another repo [\#734](https://github.com/PegaSysEng/pantheon/pull/734)
@@ -4218,7 +4097,7 @@ Public key address export subcommand was missing in 1.0 release.
## 0.9.1
Built and compatible with with JDK8.
Built and compatible with JDK8.
## 0.9
@@ -4281,13 +4160,6 @@ has been updated to use the moved quickstart.
- Implement Petersburg hardfork [\#601](https://github.com/PegaSysEng/pantheon/pull/601)
- Added private transaction abstraction [\#592](https://github.com/PegaSysEng/pantheon/pull/592) (thanks to [iikirilov](https://github.com/iikirilov))
- Added privacy command line commands [\#584](https://github.com/PegaSysEng/pantheon/pull/584) (thanks to [Puneetha17](https://github.com/Puneetha17))
- Documentation updates include:
- Updated [Private Network Quickstart tutorial](https://besu.hyperledger.org/en/latest/Tutorials/Quickstarts/Private-Network-Quickstart/)
to use quickstart in `pantheon-quickstart` repository and indicate that the quickstart is not supported on Windows.
- Added IBFT 2.0 [content](https://besu.hyperledger.org/en/latest/HowTo/Configure/Consensus-Protocols/IBFT/) and [JSON RPC API methods](https://besu.hyperledger.org/en/latest/Reference/API-Methods/#ibft-20-methods).
- Added [consensus protocols content](https://besu.hyperledger.org/en/latest/Concepts/Consensus-Protocols/Comparing-PoA/).
- Added content on [events and logs](https://besu.hyperledger.org/en/latest/Concepts/Events-and-Logs/), and [using filters](https://besu.hyperledger.org/en/latest/HowTo/Interact/Filters/Accessing-Logs-Using-JSON-RPC/).
- Added content on integrating with [Prometheus Push Gateway](https://besu.hyperledger.org/en/latest/HowTo/Deploy/Monitoring-Performance/#running-prometheus-with-besu-in-push-mode)
### Technical Improvements
@@ -4409,11 +4281,6 @@ When restarting your node with the v0.8.4 Docker image:
- Added account whitelisting [\#460](https://github.com/PegaSysEng/pantheon/pull/460)
- Added configurable refresh delay for SyncingSubscriptionService on start up [\#383](https://github.com/PegaSysEng/pantheon/pull/383)
- Added the Command Line Style Guide [\#530](https://github.com/PegaSysEng/pantheon/pull/530)
- Documentation updates include:
* Migrated to new [documentation site](https://docs.pantheon.pegasys.tech/en/latest/)
* Added [configuration file content](https://besu.hyperledger.org/en/stable/)
* Added [tutorial to create private network](https://besu.hyperledger.org/en/latest/Tutorials/Private-Network/Create-Private-Network/)
* Added content on [enabling non-default APIs](https://besu.hyperledger.org/en/latest/Reference/API-Methods/)
## Technical Improvements
@@ -4497,11 +4364,6 @@ Specify `*` or `all` for `--host-whitelist` to effectively disable host protecti
- IBFT block mining [\#169](https://github.com/PegaSysEng/pantheon/pull/169)
- Added `--goerli` CLI option [\#370](https://github.com/PegaSysEng/pantheon/pull/370) (Thanks to [@Nashatyrev](https://github.com/Nashatyrev))
- Begin capturing metrics to better understand Besu's behaviour [\#326](https://github.com/PegaSysEng/pantheon/pull/326)
- Documentation updates include:
* Added Coding Conventions [\#342](https://github.com/PegaSysEng/pantheon/pull/342)
* Reorganised [Installation documentation](https://github.com/PegaSysEng/pantheon/wiki/Installation) and added [Chocolatey installation](https://github.com/PegaSysEng/pantheon/wiki/Install-Binaries#windows-with-chocolatey) for Windows
* Reorganised [JSON-RPC API documentation](https://github.com/PegaSysEng/pantheon/wiki/JSON-RPC-API)
* Updated [RPC Pub/Sub API documentation](https://github.com/PegaSysEng/pantheon/wiki/RPC-PubSub)
### Technical Improvements
@@ -4578,15 +4440,6 @@ Specify `*` or `all` for `--host-whitelist` to effectively disable host protecti
- Added `--banned-nodeids` option to prevent connection to specific nodes (PR [#254](https://github.com/PegaSysEng/pantheon/pull/254))
- Send client quitting disconnect message to peers on shutdown (PR [#253](https://github.com/PegaSysEng/pantheon/pull/253))
- Improved error message for port conflict error (PR [#232](https://github.com/PegaSysEng/pantheon/pull/232))
- Improved documentation by adding the following pages:
* [Getting Started](https://github.com/PegaSysEng/pantheon/wiki/Getting-Started)
* [Network ID and Chain ID](https://github.com/PegaSysEng/pantheon/wiki/NetworkID-And-ChainID)
* [Node Keys](https://github.com/PegaSysEng/pantheon/wiki/Node-Keys)
* [Networking](https://github.com/PegaSysEng/pantheon/wiki/Networking)
* [Accounts for Testing](https://github.com/PegaSysEng/pantheon/wiki/Accounts-for-Testing)
* [Logging](https://github.com/PegaSysEng/pantheon/wiki/Logging)
* [Proof of Authority](https://github.com/PegaSysEng/pantheon/wiki/Proof-of-Authority)
* [Passing JVM Options](https://github.com/PegaSysEng/pantheon/wiki/Passing-JVM-Options)
### Technical Improvements

View File

@@ -24,11 +24,16 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import java.nio.file.Path;
import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AllowListContainsKeyAndValue implements Condition {
private final ALLOWLIST_TYPE allowlistType;
private final Collection<String> allowlistValues;
private final Path configFilePath;
private static final Logger LOG = LoggerFactory.getLogger(AllowListContainsKeyAndValue.class);
public AllowListContainsKeyAndValue(
final ALLOWLIST_TYPE allowlistType,
final Collection<String> allowlistValues,
@@ -47,6 +52,7 @@ public class AllowListContainsKeyAndValue implements Condition {
allowlistType, allowlistValues, configFilePath);
} catch (final Exception e) {
result = false;
LOG.error("Error verifying allowlist contains key and value", e);
}
assertThat(result).isTrue();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright ConsenSys AG.
* Copyright contributors to Hyperledger Besu.
*
* 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
@@ -18,8 +18,13 @@ import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH;
import org.hyperledger.besu.Runner;
import org.hyperledger.besu.RunnerBuilder;
import org.hyperledger.besu.chainexport.RlpBlockExporter;
import org.hyperledger.besu.chainimport.JsonBlockImporter;
import org.hyperledger.besu.chainimport.RlpBlockImporter;
import org.hyperledger.besu.cli.BesuCommand;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.controller.BesuControllerBuilder;
@@ -30,23 +35,32 @@ import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.InProcessRpcConfiguration;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.plugins.PluginConfiguration;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCacheModule;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoaderModule;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.MetricsSystemFactory;
import org.hyperledger.besu.metrics.MetricsSystemModule;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.plugin.services.BesuConfiguration;
import org.hyperledger.besu.plugin.services.BesuEvents;
import org.hyperledger.besu.plugin.services.BlockchainService;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.PermissioningService;
import org.hyperledger.besu.plugin.services.PicoCLIOptions;
import org.hyperledger.besu.plugin.services.PrivacyPluginService;
@@ -70,6 +84,7 @@ import org.hyperledger.besu.services.StorageServiceImpl;
import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl;
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin;
import java.io.File;
import java.nio.file.Path;
@@ -79,8 +94,13 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Component;
import dagger.Module;
import dagger.Provides;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.vertx.core.Vertx;
import org.slf4j.Logger;
@@ -96,60 +116,6 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
private final Map<Node, BesuPluginContextImpl> besuPluginContextMap = new ConcurrentHashMap<>();
private BesuPluginContextImpl buildPluginContext(
final BesuNode node,
final StorageServiceImpl storageService,
final SecurityModuleServiceImpl securityModuleService,
final TransactionSimulationServiceImpl transactionSimulationServiceImpl,
final TransactionSelectionServiceImpl transactionSelectionServiceImpl,
final TransactionPoolValidatorServiceImpl transactionPoolValidatorServiceImpl,
final BlockchainServiceImpl blockchainServiceImpl,
final RpcEndpointServiceImpl rpcEndpointServiceImpl,
final BesuConfiguration commonPluginConfiguration,
final PermissioningServiceImpl permissioningService) {
final CommandLine commandLine = new CommandLine(CommandSpec.create());
final BesuPluginContextImpl besuPluginContext = new BesuPluginContextImpl();
besuPluginContext.addService(StorageService.class, storageService);
besuPluginContext.addService(SecurityModuleService.class, securityModuleService);
besuPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine));
besuPluginContext.addService(RpcEndpointService.class, rpcEndpointServiceImpl);
besuPluginContext.addService(
TransactionSelectionService.class, transactionSelectionServiceImpl);
besuPluginContext.addService(
TransactionPoolValidatorService.class, transactionPoolValidatorServiceImpl);
besuPluginContext.addService(
TransactionSimulationService.class, transactionSimulationServiceImpl);
besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl);
besuPluginContext.addService(BesuConfiguration.class, commonPluginConfiguration);
final Path pluginsPath;
final String pluginDir = System.getProperty("besu.plugins.dir");
if (pluginDir == null || pluginDir.isEmpty()) {
pluginsPath = node.homeDirectory().resolve("plugins");
final File pluginsDirFile = pluginsPath.toFile();
if (!pluginsDirFile.isDirectory()) {
pluginsDirFile.mkdirs();
pluginsDirFile.deleteOnExit();
}
System.setProperty("besu.plugins.dir", pluginsPath.toString());
} else {
pluginsPath = Path.of(pluginDir);
}
besuPluginContext.addService(BesuConfiguration.class, commonPluginConfiguration);
besuPluginContext.addService(PermissioningService.class, permissioningService);
besuPluginContext.addService(PrivacyPluginService.class, new PrivacyPluginServiceImpl());
besuPluginContext.registerPlugins(
new PluginConfiguration.Builder().pluginsDir(pluginsPath).build());
commandLine.parseArgs(node.getConfiguration().getExtraCLIOptions().toArray(new String[0]));
// register built-in plugins
new RocksDBPlugin().register(besuPluginContext);
return besuPluginContext;
}
@Override
public void startNode(final BesuNode node) {
@@ -162,114 +128,45 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
throw new UnsupportedOperationException("commands are not supported with thread runner");
}
final StorageServiceImpl storageService = new StorageServiceImpl();
final SecurityModuleServiceImpl securityModuleService = new SecurityModuleServiceImpl();
final TransactionSimulationServiceImpl transactionSimulationServiceImpl =
new TransactionSimulationServiceImpl();
final TransactionSelectionServiceImpl transactionSelectionServiceImpl =
new TransactionSelectionServiceImpl();
final TransactionPoolValidatorServiceImpl transactionPoolValidatorServiceImpl =
new TransactionPoolValidatorServiceImpl();
final BlockchainServiceImpl blockchainServiceImpl = new BlockchainServiceImpl();
final RpcEndpointServiceImpl rpcEndpointServiceImpl = new RpcEndpointServiceImpl();
BesuNodeProviderModule module = new BesuNodeProviderModule(node);
AcceptanceTestBesuComponent component =
DaggerThreadBesuNodeRunner_AcceptanceTestBesuComponent.builder()
.besuNodeProviderModule(module)
.build();
final Path dataDir = node.homeDirectory();
final BesuConfigurationImpl commonPluginConfiguration = new BesuConfigurationImpl();
final PermissioningServiceImpl permissioningService = new PermissioningServiceImpl();
final var miningParameters =
ImmutableMiningParameters.builder()
.from(node.getMiningParameters())
.transactionSelectionService(transactionSelectionServiceImpl)
.build();
commonPluginConfiguration
.init(dataDir, dataDir.resolve(DATABASE_PATH), node.getDataStorageConfiguration())
.withMiningParameters(miningParameters);
final BesuPluginContextImpl besuPluginContext =
besuPluginContextMap.computeIfAbsent(
node,
n ->
buildPluginContext(
node,
storageService,
securityModuleService,
transactionSimulationServiceImpl,
transactionSelectionServiceImpl,
transactionPoolValidatorServiceImpl,
blockchainServiceImpl,
rpcEndpointServiceImpl,
commonPluginConfiguration,
permissioningService));
GlobalOpenTelemetry.resetForTest();
final ObservableMetricsSystem metricsSystem =
MetricsSystemFactory.create(node.getMetricsConfiguration());
final ObservableMetricsSystem metricsSystem = component.getObservableMetricsSystem();
final List<EnodeURL> bootnodes =
node.getConfiguration().getBootnodes().stream()
.map(EnodeURLImpl::fromURI)
.collect(Collectors.toList());
final NetworkName network = node.getNetwork() == null ? NetworkName.DEV : node.getNetwork();
final EthNetworkConfig.Builder networkConfigBuilder =
new EthNetworkConfig.Builder(EthNetworkConfig.getNetworkConfig(network))
.setBootNodes(bootnodes);
node.getConfiguration().getBootnodes().stream().map(EnodeURLImpl::fromURI).toList();
final EthNetworkConfig.Builder networkConfigBuilder = component.ethNetworkConfigBuilder();
networkConfigBuilder.setBootNodes(bootnodes);
node.getConfiguration()
.getGenesisConfig()
.map(GenesisConfigFile::fromConfig)
.ifPresent(networkConfigBuilder::setGenesisConfigFile);
final EthNetworkConfig ethNetworkConfig = networkConfigBuilder.build();
final SynchronizerConfiguration synchronizerConfiguration =
new SynchronizerConfiguration.Builder().build();
final BesuControllerBuilder builder =
new BesuController.Builder()
.fromEthNetworkConfig(ethNetworkConfig, synchronizerConfiguration.getSyncMode());
final BesuControllerBuilder builder = component.besuControllerBuilder();
builder.isRevertReasonEnabled(node.isRevertReasonEnabled());
builder.networkConfiguration(node.getNetworkingConfiguration());
final KeyValueStorageProvider storageProvider =
new KeyValueStorageProviderBuilder()
.withStorageFactory(storageService.getByName("rocksdb").get())
.withCommonConfiguration(commonPluginConfiguration)
.withMetricsSystem(metricsSystem)
.build();
final TransactionPoolConfiguration txPoolConfig =
ImmutableTransactionPoolConfiguration.builder()
.from(node.getTransactionPoolConfiguration())
.strictTransactionReplayProtectionEnabled(node.isStrictTxReplayProtectionEnabled())
.transactionPoolValidatorService(transactionPoolValidatorServiceImpl)
.build();
final InProcessRpcConfiguration inProcessRpcConfiguration = node.inProcessRpcConfiguration();
final int maxPeers = 25;
builder
.synchronizerConfiguration(new SynchronizerConfiguration.Builder().build())
.dataDirectory(node.homeDirectory())
.miningParameters(miningParameters)
.privacyParameters(node.getPrivacyParameters())
.nodeKey(new NodeKey(new KeyPairSecurityModule(KeyPairUtil.loadKeyPair(dataDir))))
.metricsSystem(metricsSystem)
.transactionPoolConfiguration(txPoolConfig)
.dataStorageConfiguration(node.getDataStorageConfiguration())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.clock(Clock.systemUTC())
.isRevertReasonEnabled(node.isRevertReasonEnabled())
.storageProvider(storageProvider)
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.maxPeers(maxPeers)
.maxRemotelyInitiatedPeers(15)
.networkConfiguration(node.getNetworkingConfiguration())
.randomPeerPriority(false);
builder.dataDirectory(dataDir);
builder.nodeKey(new NodeKey(new KeyPairSecurityModule(KeyPairUtil.loadKeyPair(dataDir))));
builder.privacyParameters(node.getPrivacyParameters());
node.getGenesisConfig()
.map(GenesisConfigFile::fromConfig)
.ifPresent(builder::genesisConfigFile);
final BesuController besuController = builder.build();
final BesuController besuController = component.besuController();
initTransactionSimulationService(
transactionSimulationServiceImpl, besuController, node.getApiConfiguration());
initBlockchainService(blockchainServiceImpl, besuController);
InProcessRpcConfiguration inProcessRpcConfiguration = node.inProcessRpcConfiguration();
final BesuPluginContextImpl besuPluginContext =
besuPluginContextMap.computeIfAbsent(node, n -> component.getBesuPluginContext());
final RunnerBuilder runnerBuilder = new RunnerBuilder();
runnerBuilder.permissioningConfiguration(node.getPermissioningConfiguration());
@@ -293,17 +190,13 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
.p2pEnabled(node.isP2pEnabled())
.p2pTLSConfiguration(node.getTLSConfiguration())
.graphQLConfiguration(GraphQLConfiguration.createDefault())
.staticNodes(
node.getStaticNodes().stream()
.map(EnodeURLImpl::fromString)
.collect(Collectors.toList()))
.staticNodes(node.getStaticNodes().stream().map(EnodeURLImpl::fromString).toList())
.besuPluginContext(besuPluginContext)
.autoLogBloomCaching(false)
.storageProvider(storageProvider)
.rpcEndpointService(rpcEndpointServiceImpl)
.storageProvider(besuController.getStorageProvider())
.rpcEndpointService(component.rpcEndpointService())
.inProcessRpcConfiguration(inProcessRpcConfiguration);
node.engineRpcConfiguration().ifPresent(runnerBuilder::engineJsonRpcConfiguration);
besuPluginContext.beforeExternalServices();
final Runner runner = runnerBuilder.build();
@@ -318,7 +211,7 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
besuController.getSyncState(),
besuController.getProtocolContext().getBadBlockManager()));
rpcEndpointServiceImpl.init(runner.getInProcessRpcMethods());
component.rpcEndpointService().init(runner.getInProcessRpcMethods());
besuPluginContext.startPlugins();
@@ -328,25 +221,6 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
MDC.remove("node");
}
private void initBlockchainService(
final BlockchainServiceImpl blockchainServiceImpl, final BesuController besuController) {
blockchainServiceImpl.init(
besuController.getProtocolContext(), besuController.getProtocolSchedule());
}
private void initTransactionSimulationService(
final TransactionSimulationServiceImpl transactionSimulationService,
final BesuController besuController,
final ApiConfiguration apiConfiguration) {
transactionSimulationService.init(
besuController.getProtocolContext().getBlockchain(),
new TransactionSimulator(
besuController.getProtocolContext().getBlockchain(),
besuController.getProtocolContext().getWorldStateArchive(),
besuController.getProtocolSchedule(),
apiConfiguration.getGasCap()));
}
@Override
public void stopNode(final BesuNode node) {
final BesuPluginContextImpl pluginContext = besuPluginContextMap.remove(node);
@@ -396,4 +270,331 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
public String getConsoleContents() {
throw new RuntimeException("Console contents can only be captured in process execution");
}
@Module
static class BesuNodeProviderModule {
private final BesuNode toProvide;
public BesuNodeProviderModule(final BesuNode toProvide) {
this.toProvide = toProvide;
}
@Provides
public BesuNode provideBesuNodeRunner() {
return toProvide;
}
@Provides
@Named("ExtraCLIOptions")
public List<String> provideExtraCLIOptions() {
return toProvide.getExtraCLIOptions();
}
@Provides
Path provideDataDir() {
return toProvide.homeDirectory();
}
@Provides
@Singleton
RpcEndpointServiceImpl provideRpcEndpointService() {
return new RpcEndpointServiceImpl();
}
@Provides
@Singleton
BlockchainServiceImpl provideBlockchainService(final BesuController besuController) {
BlockchainServiceImpl retval = new BlockchainServiceImpl();
retval.init(besuController.getProtocolContext(), besuController.getProtocolSchedule());
return retval;
}
@Provides
@Singleton
Blockchain provideBlockchain(final BesuController besuController) {
return besuController.getProtocolContext().getBlockchain();
}
@Provides
@SuppressWarnings("CloseableProvides")
WorldStateArchive provideWorldStateArchive(final BesuController besuController) {
return besuController.getProtocolContext().getWorldStateArchive();
}
@Provides
ProtocolSchedule provideProtocolSchedule(final BesuController besuController) {
return besuController.getProtocolSchedule();
}
@Provides
ApiConfiguration provideApiConfiguration(final BesuNode node) {
return node.getApiConfiguration();
}
@Provides
@Singleton
TransactionPoolValidatorServiceImpl provideTransactionPoolValidatorService() {
return new TransactionPoolValidatorServiceImpl();
}
@Provides
@Singleton
TransactionSelectionServiceImpl provideTransactionSelectionService() {
return new TransactionSelectionServiceImpl();
}
@Provides
@Singleton
TransactionPoolConfiguration provideTransactionPoolConfiguration(
final BesuNode node,
final TransactionPoolValidatorServiceImpl transactionPoolValidatorServiceImpl) {
TransactionPoolConfiguration txPoolConfig =
ImmutableTransactionPoolConfiguration.builder()
.from(node.getTransactionPoolConfiguration())
.strictTransactionReplayProtectionEnabled(node.isStrictTxReplayProtectionEnabled())
.transactionPoolValidatorService(transactionPoolValidatorServiceImpl)
.build();
return txPoolConfig;
}
@Provides
@Singleton
TransactionSimulator provideTransactionSimulator(
final Blockchain blockchain,
final WorldStateArchive worldStateArchive,
final ProtocolSchedule protocolSchedule,
final ApiConfiguration apiConfiguration) {
return new TransactionSimulator(
blockchain, worldStateArchive, protocolSchedule, apiConfiguration.getGasCap());
}
@Provides
@Singleton
TransactionSimulationServiceImpl provideTransactionSimulationService(
final Blockchain blockchain, final TransactionSimulator transactionSimulator) {
TransactionSimulationServiceImpl retval = new TransactionSimulationServiceImpl();
retval.init(blockchain, transactionSimulator);
return retval;
}
}
@Module
@SuppressWarnings("CloseableProvides")
static class BesuControllerModule {
@Provides
@Singleton
public SynchronizerConfiguration provideSynchronizationConfiguration() {
final SynchronizerConfiguration synchronizerConfiguration =
SynchronizerConfiguration.builder().build();
return synchronizerConfiguration;
}
@Singleton
@Provides
public BesuControllerBuilder provideBesuControllerBuilder(
final EthNetworkConfig ethNetworkConfig,
final SynchronizerConfiguration synchronizerConfiguration,
final TransactionPoolConfiguration transactionPoolConfiguration) {
final BesuControllerBuilder builder =
new BesuController.Builder()
.fromEthNetworkConfig(ethNetworkConfig, synchronizerConfiguration.getSyncMode());
builder.transactionPoolConfiguration(transactionPoolConfiguration);
return builder;
}
@Provides
@Singleton
public BesuController provideBesuController(
final SynchronizerConfiguration synchronizerConfiguration,
final BesuControllerBuilder builder,
final ObservableMetricsSystem metricsSystem,
final KeyValueStorageProvider storageProvider,
final MiningParameters miningParameters) {
builder
.synchronizerConfiguration(synchronizerConfiguration)
.metricsSystem(metricsSystem)
.dataStorageConfiguration(DataStorageConfiguration.DEFAULT_FOREST_CONFIG)
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.clock(Clock.systemUTC())
.storageProvider(storageProvider)
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.maxPeers(25)
.maxRemotelyInitiatedPeers(15)
.miningParameters(miningParameters)
.randomPeerPriority(false)
.besuComponent(null);
return builder.build();
}
@Provides
@Singleton
public EthNetworkConfig.Builder provideEthNetworkConfigBuilder() {
final EthNetworkConfig.Builder networkConfigBuilder =
new EthNetworkConfig.Builder(EthNetworkConfig.getNetworkConfig(NetworkName.DEV));
return networkConfigBuilder;
}
@Provides
public EthNetworkConfig provideEthNetworkConfig(
final EthNetworkConfig.Builder networkConfigBuilder) {
final EthNetworkConfig ethNetworkConfig = networkConfigBuilder.build();
return ethNetworkConfig;
}
@Provides
public BesuPluginContextImpl providePluginContext(
final StorageServiceImpl storageService,
final SecurityModuleServiceImpl securityModuleService,
final TransactionSimulationServiceImpl transactionSimulationServiceImpl,
final TransactionSelectionServiceImpl transactionSelectionServiceImpl,
final TransactionPoolValidatorServiceImpl transactionPoolValidatorServiceImpl,
final BlockchainServiceImpl blockchainServiceImpl,
final RpcEndpointServiceImpl rpcEndpointServiceImpl,
final BesuConfiguration commonPluginConfiguration,
final PermissioningServiceImpl permissioningService,
final @Named("ExtraCLIOptions") List<String> extraCLIOptions) {
final CommandLine commandLine = new CommandLine(CommandSpec.create());
final BesuPluginContextImpl besuPluginContext = new BesuPluginContextImpl();
besuPluginContext.addService(StorageService.class, storageService);
besuPluginContext.addService(SecurityModuleService.class, securityModuleService);
besuPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine));
besuPluginContext.addService(RpcEndpointService.class, rpcEndpointServiceImpl);
besuPluginContext.addService(
TransactionSelectionService.class, transactionSelectionServiceImpl);
besuPluginContext.addService(
TransactionPoolValidatorService.class, transactionPoolValidatorServiceImpl);
besuPluginContext.addService(
TransactionSimulationService.class, transactionSimulationServiceImpl);
besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl);
besuPluginContext.addService(BesuConfiguration.class, commonPluginConfiguration);
final Path pluginsPath;
final String pluginDir = System.getProperty("besu.plugins.dir");
if (pluginDir == null || pluginDir.isEmpty()) {
pluginsPath = commonPluginConfiguration.getDataPath().resolve("plugins");
final File pluginsDirFile = pluginsPath.toFile();
if (!pluginsDirFile.isDirectory()) {
pluginsDirFile.mkdirs();
pluginsDirFile.deleteOnExit();
}
System.setProperty("besu.plugins.dir", pluginsPath.toString());
} else {
pluginsPath = Path.of(pluginDir);
}
besuPluginContext.addService(BesuConfiguration.class, commonPluginConfiguration);
besuPluginContext.addService(PermissioningService.class, permissioningService);
besuPluginContext.addService(PrivacyPluginService.class, new PrivacyPluginServiceImpl());
besuPluginContext.registerPlugins(
new PluginConfiguration.Builder().pluginsDir(pluginsPath).build());
commandLine.parseArgs(extraCLIOptions.toArray(new String[0]));
// register built-in plugins
new RocksDBPlugin().register(besuPluginContext);
return besuPluginContext;
}
@Provides
public KeyValueStorageProvider provideKeyValueStorageProvider(
final BesuConfiguration commonPluginConfiguration, final MetricsSystem metricsSystem) {
final StorageServiceImpl storageService = new StorageServiceImpl();
storageService.registerKeyValueStorage(
new InMemoryStoragePlugin.InMemoryKeyValueStorageFactory("memory"));
final KeyValueStorageProvider storageProvider =
new KeyValueStorageProviderBuilder()
.withStorageFactory(storageService.getByName("memory").get())
.withCommonConfiguration(commonPluginConfiguration)
.withMetricsSystem(metricsSystem)
.build();
return storageProvider;
}
@Provides
public MiningParameters provideMiningParameters(
final TransactionSelectionServiceImpl transactionSelectionServiceImpl,
final BesuNode node) {
final var miningParameters =
ImmutableMiningParameters.builder()
.from(node.getMiningParameters())
.transactionSelectionService(transactionSelectionServiceImpl)
.build();
return miningParameters;
}
@Provides
@Inject
BesuConfiguration provideBesuConfiguration(
final Path dataDir, final MiningParameters miningParameters, final BesuNode node) {
final BesuConfigurationImpl commonPluginConfiguration = new BesuConfigurationImpl();
commonPluginConfiguration.init(
dataDir, dataDir.resolve(DATABASE_PATH), node.getDataStorageConfiguration());
commonPluginConfiguration.withMiningParameters(miningParameters);
return commonPluginConfiguration;
}
}
@Module
static class MockBesuCommandModule {
@Provides
BesuCommand provideBesuCommand(final BesuPluginContextImpl pluginContext) {
final BesuCommand besuCommand =
new BesuCommand(
RlpBlockImporter::new,
JsonBlockImporter::new,
RlpBlockExporter::new,
new RunnerBuilder(),
new BesuController.Builder(),
pluginContext,
System.getenv(),
LoggerFactory.getLogger(MockBesuCommandModule.class));
besuCommand.toCommandLine();
return besuCommand;
}
@Provides
@Singleton
MetricsConfiguration provideMetricsConfiguration() {
return MetricsConfiguration.builder().build();
}
@Provides
@Named("besuCommandLogger")
@Singleton
Logger provideBesuCommandLogger() {
return LoggerFactory.getLogger(MockBesuCommandModule.class);
}
}
@Singleton
@Component(
modules = {
ThreadBesuNodeRunner.BesuControllerModule.class,
ThreadBesuNodeRunner.MockBesuCommandModule.class,
BonsaiCachedMerkleTrieLoaderModule.class,
MetricsSystemModule.class,
ThreadBesuNodeRunner.BesuNodeProviderModule.class,
BlobCacheModule.class
})
public interface AcceptanceTestBesuComponent extends BesuComponent {
BesuController besuController();
BesuControllerBuilder besuControllerBuilder(); // TODO: needing this sucks
EthNetworkConfig.Builder ethNetworkConfigBuilder();
RpcEndpointServiceImpl rpcEndpointService();
BlockchainServiceImpl blockchainService();
}
}

View File

@@ -511,31 +511,6 @@ public class BesuNodeFactory {
return create(builder.build());
}
public BesuNode createQbftNodeWithTLS(final String name, final String type) throws IOException {
return create(
new BesuNodeConfigurationBuilder()
.name(name)
.miningEnabled()
.p2pTLSEnabled(name, type)
.jsonRpcConfiguration(node.createJsonRpcWithQbftEnabledConfig(false))
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.devMode(false)
.genesisConfigProvider(GenesisConfigurationFactory::createQbftGenesisConfig)
.build());
}
public BesuNode createQbftNodeWithTLSJKS(final String name) throws IOException {
return createQbftNodeWithTLS(name, KeyStoreWrapper.KEYSTORE_TYPE_JKS);
}
public BesuNode createQbftNodeWithTLSPKCS12(final String name) throws IOException {
return createQbftNodeWithTLS(name, KeyStoreWrapper.KEYSTORE_TYPE_PKCS12);
}
public BesuNode createQbftNodeWithTLSPKCS11(final String name) throws IOException {
return createQbftNodeWithTLS(name, KeyStoreWrapper.KEYSTORE_TYPE_PKCS11);
}
public BesuNode createQbftNode(
final String name, final boolean fixedPort, final DataStorageFormat storageFormat)
throws IOException {

View File

@@ -276,7 +276,7 @@ public class PrivacyNode implements AutoCloseable {
final Path dataLocation, final Path dbLocation) {
final var besuConfiguration = new BesuConfigurationImpl();
besuConfiguration
.init(dataLocation, dbLocation, null)
.init(dataLocation, dbLocation, besuConfig.getDataStorageConfiguration())
.withMiningParameters(besuConfig.getMiningParameters());
return new PrivacyKeyValueStorageProviderBuilder()
.withStorageFactory(

View File

@@ -38,7 +38,7 @@ public class ClusterThreadNodeRunnerAcceptanceTest extends AcceptanceTestBase {
final BesuNodeRunner besuNodeRunner = new ThreadBesuNodeRunner();
noDiscoveryCluster = new Cluster(clusterConfiguration, net, besuNodeRunner);
final BesuNode noDiscoveryNode = besu.createNodeWithNoDiscovery("noDiscovery");
fullNode = besu.createArchiveNode("node2");
fullNode = besu.createArchiveNode("archive");
noDiscoveryCluster.start(noDiscoveryNode, fullNode);
}

View File

@@ -18,9 +18,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.SetCodeAuthorization;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
@@ -39,7 +39,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
public class SetCodeTransactionAcceptanceTest extends AcceptanceTestBase {
public class CodeDelegationTransactionAcceptanceTest extends AcceptanceTestBase {
private static final String GENESIS_FILE = "/dev/dev_prague.json";
private static final SECP256K1 secp256k1 = new SECP256K1();
@@ -74,7 +74,6 @@ public class SetCodeTransactionAcceptanceTest extends AcceptanceTestBase {
@AfterEach
void tearDown() {
besuNode.close();
cluster.close();
}
/**
@@ -88,17 +87,18 @@ public class SetCodeTransactionAcceptanceTest extends AcceptanceTestBase {
public void shouldTransferAllEthOfAuthorizerToSponsor() throws IOException {
// 7702 transaction
final org.hyperledger.besu.datatypes.SetCodeAuthorization authorization =
SetCodeAuthorization.builder()
final CodeDelegation authorization =
org.hyperledger.besu.ethereum.core.CodeDelegation.builder()
.chainId(BigInteger.valueOf(20211))
.address(SEND_ALL_ETH_CONTRACT_ADDRESS)
.nonce(0)
.signAndBuild(
secp256k1.createKeyPair(
secp256k1.createPrivateKey(AUTHORIZER_PRIVATE_KEY.toUnsignedBigInteger())));
final Transaction tx =
Transaction.builder()
.type(TransactionType.SET_CODE)
.type(TransactionType.DELEGATE_CODE)
.chainId(BigInteger.valueOf(20211))
.nonce(0)
.maxPriorityFeePerGas(Wei.of(1000000000))
@@ -108,7 +108,7 @@ public class SetCodeTransactionAcceptanceTest extends AcceptanceTestBase {
.value(Wei.ZERO)
.payload(Bytes32.leftPad(Bytes.fromHexString(transactionSponsor.getAddress())))
.accessList(List.of())
.setCodeTransactionPayloads(List.of(authorization))
.codeDelegations(List.of(authorization))
.signAndBuild(
secp256k1.createKeyPair(
secp256k1.createPrivateKey(
@@ -134,22 +134,21 @@ public class SetCodeTransactionAcceptanceTest extends AcceptanceTestBase {
/**
* The authorizer creates an authorization for a contract that sends all its ETH to any given
* address. But the nonce is 1 and the authorization list is processed before the nonce increase
* of the sender. Therefore, the authorization should be invalid and will be ignored. No balance
* change, except for a decrease for paying the transaction cost should occur.
* address. The nonce is 1 and the authorization list is processed after the nonce increase of the
* sender. Therefore, the authorization should be valid. The authorizer balance should be 0 and
* the transaction sponsor's * balance should be 180000 ETH minus the transaction costs.
*/
@Test
public void shouldCheckNonceBeforeNonceIncreaseOfSender() throws IOException {
public void shouldCheckNonceAfterNonceIncreaseOfSender() throws IOException {
final long GAS_LIMIT = 1000000L;
cluster.verify(authorizer.balanceEquals(Amount.ether(90000)));
final org.hyperledger.besu.datatypes.SetCodeAuthorization authorization =
SetCodeAuthorization.builder()
final CodeDelegation authorization =
org.hyperledger.besu.ethereum.core.CodeDelegation.builder()
.chainId(BigInteger.valueOf(20211))
.nonces(
Optional.of(
1L)) // nonce is 1, but because it is validated before the nonce increase, it
// should be 0
.nonce(
1L) // nonce is 1, but because it is validated before the nonce increase, it should
// be 0
.address(SEND_ALL_ETH_CONTRACT_ADDRESS)
.signAndBuild(
secp256k1.createKeyPair(
@@ -157,17 +156,17 @@ public class SetCodeTransactionAcceptanceTest extends AcceptanceTestBase {
final Transaction tx =
Transaction.builder()
.type(TransactionType.SET_CODE)
.type(TransactionType.DELEGATE_CODE)
.chainId(BigInteger.valueOf(20211))
.nonce(0)
.maxPriorityFeePerGas(Wei.of(1000000000))
.maxFeePerGas(Wei.fromHexString("0x02540BE400"))
.gasLimit(1000000)
.gasLimit(GAS_LIMIT)
.to(Address.fromHexStringStrict(authorizer.getAddress()))
.value(Wei.ZERO)
.payload(Bytes32.leftPad(Bytes.fromHexString(otherAccount.getAddress())))
.accessList(List.of())
.setCodeTransactionPayloads(List.of(authorization))
.codeDelegations(List.of(authorization))
.signAndBuild(
secp256k1.createKeyPair(
secp256k1.createPrivateKey(AUTHORIZER_PRIVATE_KEY.toUnsignedBigInteger())));
@@ -180,14 +179,25 @@ public class SetCodeTransactionAcceptanceTest extends AcceptanceTestBase {
besuNode.execute(ethTransactions.getTransactionReceipt(txHash));
assertThat(maybeTransactionReceipt).isPresent();
// verify that the balance of the other account has not changed
cluster.verify(otherAccount.balanceEquals(0));
final String gasPriceWithout0x =
maybeTransactionReceipt.get().getEffectiveGasPrice().substring(2);
final BigInteger txCost =
maybeTransactionReceipt.get().getGasUsed().multiply(new BigInteger(gasPriceWithout0x, 16));
BigInteger expectedSenderBalance = new BigInteger("90000000000000000000000").subtract(txCost);
cluster.verify(authorizer.balanceEquals(Amount.wei(expectedSenderBalance)));
final BigInteger gasPrice = new BigInteger(gasPriceWithout0x, 16);
final BigInteger txCost = maybeTransactionReceipt.get().getGasUsed().multiply(gasPrice);
final BigInteger authorizerBalance = besuNode.execute(ethTransactions.getBalance(authorizer));
// The remaining balance of the authorizer should the gas limit multiplied by the gas price
// minus the transaction cost.
// The following executes this calculation in reverse.
assertThat(GAS_LIMIT).isEqualTo(authorizerBalance.add(txCost).divide(gasPrice).longValue());
// The other accounts balance should be the initial 9000 ETH balance from the authorizer minus
// the remaining balance of the authorizer and minus the transaction cost
cluster.verify(
otherAccount.balanceEquals(
Amount.wei(
new BigInteger("90000000000000000000000")
.subtract(authorizerBalance)
.subtract(txCost))));
}
}

View File

@@ -40,8 +40,8 @@
"consolidationRequests": [
{
"sourceAddress": "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f",
"sourcePubKey": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"targetPubKey": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
"sourcePubkey": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"targetPubkey": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
}
],
"blockNumber": "0x4",

View File

@@ -105,6 +105,8 @@ dependencies {
testImplementation 'org.mockito:mockito-core'
testImplementation 'org.testcontainers:testcontainers'
testImplementation 'tech.pegasys.discovery:discovery'
testImplementation 'com.google.dagger:dagger'
annotationProcessor 'com.google.dagger:dagger-compiler'
testAnnotationProcessor 'com.google.dagger:dagger-compiler'
}

View File

@@ -84,7 +84,6 @@ import org.hyperledger.besu.cli.util.BesuCommandCustomFactory;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.cli.util.ConfigDefaultValueProviderStrategy;
import org.hyperledger.besu.cli.util.VersionProvider;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.CheckpointConfigOptions;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
@@ -865,13 +864,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private BesuController besuController;
private BesuConfigurationImpl pluginCommonConfiguration;
private BesuComponent besuComponent;
private final Supplier<ObservableMetricsSystem> metricsSystem =
Suppliers.memoize(
() ->
besuComponent == null || besuComponent.getObservableMetricsSystem() == null
? MetricsSystemFactory.create(metricsConfiguration())
: besuComponent.getObservableMetricsSystem());
Suppliers.memoize(() -> MetricsSystemFactory.create(metricsConfiguration()));
private Vertx vertx;
private EnodeDnsConfiguration enodeDnsConfiguration;
private KeyValueStorageProvider keyValueStorageProvider;
@@ -879,7 +874,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
/**
* Besu command constructor.
*
* @param besuComponent BesuComponent which acts as our application context
* @param rlpBlockImporter RlpBlockImporter supplier
* @param jsonBlockImporterFactory instance of {@code Function<BesuController, JsonBlockImporter>}
* @param rlpBlockExporterFactory instance of {@code Function<Blockchain, RlpBlockExporter>}
@@ -887,18 +881,18 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
* @param controllerBuilder instance of BesuController.Builder
* @param besuPluginContext instance of BesuPluginContextImpl
* @param environment Environment variables map
* @param commandLogger instance of Logger for outputting to the CLI
*/
public BesuCommand(
final BesuComponent besuComponent,
final Supplier<RlpBlockImporter> rlpBlockImporter,
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
final RunnerBuilder runnerBuilder,
final BesuController.Builder controllerBuilder,
final BesuPluginContextImpl besuPluginContext,
final Map<String, String> environment) {
final Map<String, String> environment,
final Logger commandLogger) {
this(
besuComponent,
rlpBlockImporter,
jsonBlockImporterFactory,
rlpBlockExporterFactory,
@@ -914,13 +908,13 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
new TransactionSelectionServiceImpl(),
new TransactionPoolValidatorServiceImpl(),
new TransactionSimulationServiceImpl(),
new BlockchainServiceImpl());
new BlockchainServiceImpl(),
commandLogger);
}
/**
* Overloaded Besu command constructor visible for testing.
*
* @param besuComponent BesuComponent which acts as our application context
* @param rlpBlockImporter RlpBlockImporter supplier
* @param jsonBlockImporterFactory instance of {@code Function<BesuController, JsonBlockImporter>}
* @param rlpBlockExporterFactory instance of {@code Function<Blockchain, RlpBlockExporter>}
@@ -937,10 +931,10 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
* @param transactionValidatorServiceImpl instance of TransactionValidatorServiceImpl
* @param transactionSimulationServiceImpl instance of TransactionSimulationServiceImpl
* @param blockchainServiceImpl instance of BlockchainServiceImpl
* @param commandLogger instance of Logger for outputting to the CLI
*/
@VisibleForTesting
protected BesuCommand(
final BesuComponent besuComponent,
final Supplier<RlpBlockImporter> rlpBlockImporter,
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
@@ -956,9 +950,10 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
final TransactionSelectionServiceImpl transactionSelectionServiceImpl,
final TransactionPoolValidatorServiceImpl transactionValidatorServiceImpl,
final TransactionSimulationServiceImpl transactionSimulationServiceImpl,
final BlockchainServiceImpl blockchainServiceImpl) {
this.besuComponent = besuComponent;
this.logger = besuComponent.getBesuCommandLogger();
final BlockchainServiceImpl blockchainServiceImpl,
final Logger commandLogger) {
this.logger = commandLogger;
this.rlpBlockImporter = rlpBlockImporter;
this.rlpBlockExporterFactory = rlpBlockExporterFactory;
this.jsonBlockImporterFactory = jsonBlockImporterFactory;
@@ -970,8 +965,13 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
this.securityModuleService = securityModuleService;
this.permissioningService = permissioningService;
this.privacyPluginService = privacyPluginService;
this.pluginCommonConfiguration = new BesuConfigurationImpl();
besuPluginContext.addService(BesuConfiguration.class, pluginCommonConfiguration);
if (besuPluginContext.getService(BesuConfigurationImpl.class).isPresent()) {
this.pluginCommonConfiguration =
besuPluginContext.getService(BesuConfigurationImpl.class).get();
} else {
this.pluginCommonConfiguration = new BesuConfigurationImpl();
besuPluginContext.addService(BesuConfiguration.class, this.pluginCommonConfiguration);
}
this.rpcEndpointServiceImpl = rpcEndpointServiceImpl;
this.transactionSelectionServiceImpl = transactionSelectionServiceImpl;
this.transactionValidatorServiceImpl = transactionValidatorServiceImpl;
@@ -1821,9 +1821,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
*/
public BesuController buildController() {
try {
return this.besuComponent == null
? getControllerBuilder().build()
: getControllerBuilder().besuComponent(this.besuComponent).build();
return setupControllerBuilder().build();
} catch (final Exception e) {
throw new ExecutionException(this.commandLine, e.getMessage(), e);
}
@@ -1834,7 +1832,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
*
* @return instance of BesuControllerBuilder
*/
public BesuControllerBuilder getControllerBuilder() {
public BesuControllerBuilder setupControllerBuilder() {
pluginCommonConfiguration
.init(dataDir(), dataDir().resolve(DATABASE_PATH), getDataStorageConfiguration())
.withMiningParameters(miningParametersSupplier.get())
@@ -2800,7 +2798,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
builder.setTxPoolImplementation(buildTransactionPoolConfiguration().getTxPoolImplementation());
builder.setWorldStateUpdateMode(unstableEvmOptions.toDomainObject().worldUpdaterMode());
builder.setPluginContext(besuComponent.getBesuPluginContext());
builder.setPluginContext(this.besuPluginContext);
return builder.build();
}

View File

@@ -160,6 +160,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
private static final String TX_POOL_MAX_PRIORITIZED_BY_TYPE =
"--tx-pool-max-prioritized-by-type";
private static final String TX_POOL_MAX_FUTURE_BY_SENDER = "--tx-pool-max-future-by-sender";
private static final String TX_POOL_MIN_SCORE = "--tx-pool-min-score";
@CommandLine.Option(
names = {TX_POOL_LAYER_MAX_CAPACITY},
@@ -196,6 +197,15 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
"Max number of future pending transactions allowed for a single sender (default: ${DEFAULT-VALUE})",
arity = "1")
Integer txPoolMaxFutureBySender = TransactionPoolConfiguration.DEFAULT_MAX_FUTURE_BY_SENDER;
@CommandLine.Option(
names = {TX_POOL_MIN_SCORE},
paramLabel = "<Byte>",
description =
"Remove a pending transaction from the txpool if its score is lower than this value."
+ "Accepts values between -128 and 127 (default: ${DEFAULT-VALUE})",
arity = "1")
Byte minScore = TransactionPoolConfiguration.DEFAULT_TX_POOL_MIN_SCORE;
}
@CommandLine.ArgGroup(
@@ -314,6 +324,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
options.layeredOptions.txPoolMaxPrioritizedByType =
config.getMaxPrioritizedTransactionsByType();
options.layeredOptions.txPoolMaxFutureBySender = config.getMaxFutureBySender();
options.layeredOptions.minScore = config.getMinScore();
options.sequencedOptions.txPoolLimitByAccountPercentage =
config.getTxPoolLimitByAccountPercentage();
options.sequencedOptions.txPoolMaxSize = config.getTxPoolMaxSize();
@@ -372,6 +383,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
.maxPrioritizedTransactions(layeredOptions.txPoolMaxPrioritized)
.maxPrioritizedTransactionsByType(layeredOptions.txPoolMaxPrioritizedByType)
.maxFutureBySender(layeredOptions.txPoolMaxFutureBySender)
.minScore(layeredOptions.minScore)
.txPoolLimitByAccountPercentage(sequencedOptions.txPoolLimitByAccountPercentage)
.txPoolMaxSize(sequencedOptions.txPoolMaxSize)
.pendingTxRetentionPeriod(sequencedOptions.pendingTxRetentionPeriod)

View File

@@ -254,7 +254,7 @@ public class BlocksSubCommand implements Runnable {
// Set some defaults
return parentCommand
.parentCommand
.getControllerBuilder()
.setupControllerBuilder()
// set to mainnet genesis block so validation rules won't reject it.
.clock(Clock.fixed(Instant.ofEpochSecond(startTime), ZoneOffset.UTC))
.miningParameters(getMiningParameters())
@@ -374,7 +374,7 @@ public class BlocksSubCommand implements Runnable {
private BesuController createBesuController() {
return parentCommand
.parentCommand
.getControllerBuilder()
.setupControllerBuilder()
.miningParameters(MiningParameters.newDefault())
.build();
}

View File

@@ -87,7 +87,7 @@ public class TrieLogSubCommand implements Runnable {
// disable limit trie logs to avoid preloading during subcommand execution
return parentCommand
.besuCommand
.getControllerBuilder()
.setupControllerBuilder()
.dataStorageConfiguration(
ImmutableDataStorageConfiguration.copyOf(config).withBonsaiLimitTrieLogsEnabled(false))
.build();

View File

@@ -22,8 +22,8 @@ import org.hyperledger.besu.chainimport.RlpBlockImporter;
import org.hyperledger.besu.cli.BesuCommand;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.services.BesuPluginContextImpl;
import java.util.Optional;
import javax.inject.Named;
import javax.inject.Singleton;
@@ -42,17 +42,19 @@ public class BesuCommandModule {
@Provides
@Singleton
BesuCommand provideBesuCommand(final BesuComponent besuComponent) {
BesuCommand provideBesuCommand(
final BesuPluginContextImpl pluginContext,
final @Named("besuCommandLogger") Logger commandLogger) {
final BesuCommand besuCommand =
new BesuCommand(
besuComponent,
RlpBlockImporter::new,
JsonBlockImporter::new,
RlpBlockExporter::new,
new RunnerBuilder(),
new BesuController.Builder(),
Optional.ofNullable(besuComponent.getBesuPluginContext()).orElse(null),
System.getenv());
pluginContext,
System.getenv(),
commandLogger);
besuCommand.toCommandLine();
return besuCommand;
}

View File

@@ -75,7 +75,6 @@ public interface BesuComponent {
*
* @return BesuPluginContextImpl
*/
@Named("besuPluginContext")
BesuPluginContextImpl getBesuPluginContext();
/**

View File

@@ -14,9 +14,10 @@
*/
package org.hyperledger.besu.components;
import org.hyperledger.besu.plugin.services.BesuConfiguration;
import org.hyperledger.besu.services.BesuConfigurationImpl;
import org.hyperledger.besu.services.BesuPluginContextImpl;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Module;
@@ -29,15 +30,23 @@ public class BesuPluginContextModule {
/** Default constructor. */
public BesuPluginContextModule() {}
@Provides
@Singleton
BesuConfigurationImpl provideBesuPluginConfig() {
return new BesuConfigurationImpl();
}
/**
* Creates a BesuPluginContextImpl, used for plugin service discovery.
*
* @param pluginConfig the BesuConfigurationImpl
* @return the BesuPluginContext
*/
@Provides
@Named("besuPluginContext")
@Singleton
public BesuPluginContextImpl provideBesuPluginContext() {
return new BesuPluginContextImpl();
public BesuPluginContextImpl provideBesuPluginContext(final BesuConfigurationImpl pluginConfig) {
BesuPluginContextImpl retval = new BesuPluginContextImpl();
retval.addService(BesuConfiguration.class, pluginConfig);
return retval;
}
}

View File

@@ -552,6 +552,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
checkNotNull(evmConfiguration, "Missing evm config");
checkNotNull(networkingConfiguration, "Missing network configuration");
checkNotNull(dataStorageConfiguration, "Missing data storage configuration");
prepForBuild();
final ProtocolSchedule protocolSchedule = createProtocolSchedule();

View File

@@ -19,6 +19,7 @@ import org.hyperledger.besu.plugin.services.permissioning.NodeConnectionPermissi
import org.hyperledger.besu.plugin.services.permissioning.NodeMessagePermissioningProvider;
import java.util.List;
import javax.inject.Inject;
import com.google.common.collect.Lists;
@@ -29,6 +30,7 @@ public class PermissioningServiceImpl implements PermissioningService {
Lists.newArrayList();
/** Default Constructor. */
@Inject
public PermissioningServiceImpl() {}
@Override

View File

@@ -21,15 +21,18 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import javax.inject.Inject;
/** The Security module service implementation. */
public class SecurityModuleServiceImpl implements SecurityModuleService {
private final Map<String, Supplier<SecurityModule>> securityModuleSuppliers =
new ConcurrentHashMap<>();
/** Default Constructor. */
@Inject
public SecurityModuleServiceImpl() {}
private final Map<String, Supplier<SecurityModule>> securityModuleSuppliers =
new ConcurrentHashMap<>();
@Override
public void register(final String name, final Supplier<SecurityModule> securityModuleSupplier) {
securityModuleSuppliers.put(name, securityModuleSupplier);

View File

@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
/** The Storage service implementation. */
public class StorageServiceImpl implements StorageService {
@@ -31,6 +32,7 @@ public class StorageServiceImpl implements StorageService {
private final Map<String, KeyValueStorageFactory> factories;
/** Instantiates a new Storage service. */
@Inject
public StorageServiceImpl() {
this.segments = List.of(KeyValueSegmentIdentifier.values());
this.factories = new ConcurrentHashMap<>();

View File

@@ -23,11 +23,11 @@ import java.util.Optional;
/** The Transaction Selection service implementation. */
public class TransactionSelectionServiceImpl implements TransactionSelectionService {
private Optional<PluginTransactionSelectorFactory> factory = Optional.empty();
/** Default Constructor. */
public TransactionSelectionServiceImpl() {}
private Optional<PluginTransactionSelectorFactory> factory = Optional.empty();
@Override
public PluginTransactionSelector createPluginTransactionSelector() {
return factory

View File

@@ -0,0 +1,168 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.PrivacyParameters.FLEXIBLE_PRIVACY;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.components.BesuPluginContextModule;
import org.hyperledger.besu.components.MockBesuCommandModule;
import org.hyperledger.besu.components.NoOpMetricsSystemModule;
import org.hyperledger.besu.components.PrivacyTestModule;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.enclave.EnclaveFactory;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCacheModule;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyStorageProvider;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoaderModule;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.precompile.PrecompiledContract;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.testutil.TestClock;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Component;
import dagger.Module;
import dagger.Provides;
import io.vertx.core.Vertx;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
class FlexGroupPrivacyTest {
private final Vertx vertx = Vertx.vertx();
@AfterEach
public void cleanUp() {
vertx.close();
}
@Test
void flexibleEnabledPrivacy() {
final BesuController besuController =
DaggerFlexGroupPrivacyTest_FlexGroupPrivacyTestComponent.builder()
.build()
.getBesuController();
final PrecompiledContract flexiblePrecompiledContract =
getPrecompile(besuController, FLEXIBLE_PRIVACY);
assertThat(flexiblePrecompiledContract.getName()).isEqualTo("FlexiblePrivacy");
}
private PrecompiledContract getPrecompile(
final BesuController besuController, final Address defaultPrivacy) {
return besuController
.getProtocolSchedule()
.getByBlockHeader(blockHeader(0))
.getPrecompileContractRegistry()
.get(defaultPrivacy);
}
private BlockHeader blockHeader(final long number) {
return new BlockHeaderTestFixture().number(number).buildHeader();
}
@Singleton
@Component(
modules = {
FlexGroupPrivacyParametersModule.class,
FlexGroupPrivacyTest.PrivacyTestBesuControllerModule.class,
PrivacyTestModule.class,
MockBesuCommandModule.class,
BonsaiCachedMerkleTrieLoaderModule.class,
NoOpMetricsSystemModule.class,
BesuPluginContextModule.class,
BlobCacheModule.class
})
interface FlexGroupPrivacyTestComponent extends BesuComponent {
BesuController getBesuController();
}
@Module
static class FlexGroupPrivacyParametersModule {
@Provides
PrivacyParameters providePrivacyParameters(
final PrivacyStorageProvider storageProvider, final Vertx vertx) {
try {
return new PrivacyParameters.Builder()
.setEnabled(true)
.setEnclaveUrl(new URI("http://127.0.0.1:8000"))
.setStorageProvider(storageProvider)
.setEnclaveFactory(new EnclaveFactory(vertx))
.setFlexiblePrivacyGroupsEnabled(true)
.build();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}
@Module
static class PrivacyTestBesuControllerModule {
@Provides
@Singleton
@SuppressWarnings("CloseableProvides")
BesuController provideBesuController(
final PrivacyParameters privacyParameters,
final DataStorageConfiguration dataStorageConfiguration,
final FlexGroupPrivacyTestComponent context,
@Named("dataDir") final Path dataDir) {
return new BesuController.Builder()
.fromGenesisFile(GenesisConfigFile.mainnet(), SyncMode.FULL)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())
.networkId(BigInteger.ONE)
.miningParameters(MiningParameters.newDefault())
.dataStorageConfiguration(dataStorageConfiguration)
.nodeKey(NodeKeyUtils.generate())
.metricsSystem(new NoOpMetricsSystem())
.dataDirectory(dataDir)
.clock(TestClock.fixed())
.privacyParameters(privacyParameters)
.transactionPoolConfiguration(TransactionPoolConfiguration.DEFAULT)
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.besuComponent(context)
.build();
}
}
}

View File

@@ -21,6 +21,12 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.components.BesuPluginContextModule;
import org.hyperledger.besu.components.EnclaveModule;
import org.hyperledger.besu.components.MockBesuCommandModule;
import org.hyperledger.besu.components.NoOpMetricsSystemModule;
import org.hyperledger.besu.components.PrivacyTestModule;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.crypto.KeyPair;
@@ -47,7 +53,9 @@ import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCacheModule;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver;
@@ -56,6 +64,7 @@ import org.hyperledger.besu.ethereum.privacy.storage.PrivacyGroupHeadBlockMap;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyStorageProvider;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoaderModule;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.log.LogsBloomFilter;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
@@ -70,19 +79,21 @@ import java.nio.file.Path;
import java.util.Collections;
import java.util.Optional;
import java.util.function.Supplier;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.base.Suppliers;
import dagger.Component;
import dagger.Module;
import dagger.Provides;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@SuppressWarnings("rawtypes")
public class PrivacyReorgTest {
@TempDir private Path folder;
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
@@ -130,11 +141,15 @@ public class PrivacyReorgTest {
.signAndBuild(KEY_PAIR);
private final BlockDataGenerator gen = new BlockDataGenerator();
private BesuController besuController;
private PrivateStateRootResolver privateStateRootResolver;
private PrivacyParameters privacyParameters;
private Enclave mockEnclave;
private Transaction privacyMarkerTransaction;
private final PrivacyReorgTestComponent component =
DaggerPrivacyReorgTest_PrivacyReorgTestComponent.create();
private final BesuController besuController = component.getBesuController();
private final PrivateStateRootResolver privateStateRootResolver =
component.getPrivacyParameters().getPrivateStateRootResolver();
@BeforeEach
public void setUp() throws IOException {
@@ -174,29 +189,6 @@ public class PrivacyReorgTest {
.build();
privacyParameters.setPrivacyUserId(ENCLAVE_PUBLIC_KEY.toBase64String());
privateStateRootResolver =
new PrivateStateRootResolver(privacyParameters.getPrivateStateStorage());
besuController =
new BesuController.Builder()
.fromGenesisFile(
GenesisConfigFile.fromResource("/privacy_reorg_genesis.json"), SyncMode.FULL)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())
.networkId(BigInteger.ONE)
.miningParameters(MiningParameters.newDefault())
.nodeKey(NodeKeyUtils.generate())
.metricsSystem(new NoOpMetricsSystem())
.dataDirectory(folder)
.clock(TestClock.fixed())
.privacyParameters(privacyParameters)
.transactionPoolConfiguration(TransactionPoolConfiguration.DEFAULT)
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.build();
}
@Test
@@ -204,7 +196,8 @@ public class PrivacyReorgTest {
// Setup an initial blockchain with one private transaction
final ProtocolContext protocolContext = besuController.getProtocolContext();
final DefaultBlockchain blockchain = (DefaultBlockchain) protocolContext.getBlockchain();
final PrivateStateStorage privateStateStorage = privacyParameters.getPrivateStateStorage();
final PrivateStateStorage privateStateStorage =
component.getPrivacyParameters().getPrivateStateStorage();
final Block firstBlock =
gen.block(
@@ -244,7 +237,7 @@ public class PrivacyReorgTest {
// Setup an initial blockchain with one private transaction
final ProtocolContext protocolContext = besuController.getProtocolContext();
final DefaultBlockchain blockchain = (DefaultBlockchain) protocolContext.getBlockchain();
assertThat(blockchain.getChainHeadBlockNumber()).isEqualTo(0);
final Block firstBlock =
gen.block(
getBlockOptionsWithTransaction(
@@ -252,8 +245,9 @@ public class PrivacyReorgTest {
privacyMarkerTransaction,
FIRST_BLOCK_WITH_SINGLE_TRANSACTION_STATE_ROOT));
appendBlock(besuController, blockchain, protocolContext, firstBlock);
var importResult = appendBlock(besuController, blockchain, protocolContext, firstBlock);
assertThat(importResult.isImported()).isTrue();
assertThat(blockchain.getChainHeadBlockNumber()).isEqualTo(1);
// Check that the private state root is not the empty state
assertPrivateStateRoot(
privateStateRootResolver, blockchain, STATE_ROOT_AFTER_TRANSACTION_APPENDED_TO_EMPTY_STATE);
@@ -394,12 +388,12 @@ public class PrivacyReorgTest {
}
@SuppressWarnings("unchecked")
private void appendBlock(
private BlockImportResult appendBlock(
final BesuController besuController,
final DefaultBlockchain blockchain,
final ProtocolContext protocolContext,
final Block block) {
besuController
return besuController
.getProtocolSchedule()
.getByBlockHeader(blockchain.getChainHeadHeader())
.getBlockImporter()
@@ -487,4 +481,93 @@ public class PrivacyReorgTest {
.hasOmmers(false)
.setLogsBloom(LogsBloomFilter.empty());
}
@Singleton
@Component(
modules = {
PrivacyReorgTest.PrivacyReorgParametersModule.class,
PrivacyReorgTest.PrivacyReorgTestBesuControllerModule.class,
PrivacyReorgTest.PrivacyReorgTestGenesisConfigModule.class,
EnclaveModule.class,
PrivacyTestModule.class,
MockBesuCommandModule.class,
NoOpMetricsSystemModule.class,
BonsaiCachedMerkleTrieLoaderModule.class,
BlobCacheModule.class,
BesuPluginContextModule.class
})
interface PrivacyReorgTestComponent extends BesuComponent {
BesuController getBesuController();
PrivacyParameters getPrivacyParameters();
}
@Module
static class PrivacyReorgParametersModule {
// TODO: copypasta, get this from the enclave factory
private static final Bytes ENCLAVE_PUBLIC_KEY =
Bytes.fromBase64String("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=");
@Provides
PrivacyParameters providePrivacyReorgParameters(
final PrivacyStorageProvider storageProvider, final EnclaveFactory enclaveFactory) {
PrivacyParameters retval =
new PrivacyParameters.Builder()
.setEnabled(true)
.setStorageProvider(storageProvider)
.setEnclaveUrl(URI.create("http//1.1.1.1:1234"))
.setEnclaveFactory(enclaveFactory)
.build();
retval.setPrivacyUserId(ENCLAVE_PUBLIC_KEY.toBase64String());
return retval;
}
}
@Module
static class PrivacyReorgTestBesuControllerModule {
@Provides
@Singleton
@SuppressWarnings("CloseableProvides")
BesuController provideBesuController(
final PrivacyParameters privacyParameters,
final GenesisConfigFile genesisConfigFile,
final PrivacyReorgTestComponent context,
final @Named("dataDir") Path dataDir) {
// dataStorageConfiguration default
// named privacyReorgParams
BesuController retval =
new BesuController.Builder()
.fromGenesisFile(genesisConfigFile, SyncMode.FULL)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())
.networkId(BigInteger.ONE)
.miningParameters(MiningParameters.newDefault())
.nodeKey(NodeKeyUtils.generate())
.metricsSystem(new NoOpMetricsSystem())
.dataDirectory(dataDir)
.clock(TestClock.fixed())
.privacyParameters(privacyParameters)
.transactionPoolConfiguration(TransactionPoolConfiguration.DEFAULT)
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.besuComponent(context)
.build();
return retval;
}
}
@Module
static class PrivacyReorgTestGenesisConfigModule {
@Provides
GenesisConfigFile providePrivacyReorgGenesisConfigFile() {
return GenesisConfigFile.fromResource("/privacy_reorg_genesis.json");
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright ConsenSys AG.
* Copyright contributors to Hyperledger Besu.
*
* 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
@@ -16,18 +16,17 @@ package org.hyperledger.besu;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.PrivacyParameters.DEFAULT_PRIVACY;
import static org.hyperledger.besu.ethereum.core.PrivacyParameters.FLEXIBLE_PRIVACY;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_BACKGROUND_THREAD_COUNT;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_CACHE_CAPACITY;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_IS_HIGH_SPEC;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_MAX_OPEN_FILES;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.components.BesuPluginContextModule;
import org.hyperledger.besu.components.MockBesuCommandModule;
import org.hyperledger.besu.components.NoOpMetricsSystemModule;
import org.hyperledger.besu.components.PrivacyParametersModule;
import org.hyperledger.besu.components.PrivacyTestModule;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.enclave.EnclaveFactory;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
@@ -37,126 +36,47 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCacheModule;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyStorageProvider;
import org.hyperledger.besu.ethereum.privacy.storage.keyvalue.PrivacyKeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoaderModule;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.precompile.PrecompiledContract;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBKeyValuePrivacyStorageFactory;
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBKeyValueStorageFactory;
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory;
import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration;
import org.hyperledger.besu.services.BesuConfigurationImpl;
import org.hyperledger.besu.testutil.TestClock;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Component;
import dagger.Module;
import dagger.Provides;
import io.vertx.core.Vertx;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
public class PrivacyTest {
class PrivacyTest {
private final Vertx vertx = Vertx.vertx();
@TempDir private Path dataDir;
@AfterEach
public void cleanUp() {
vertx.close();
}
@Test
public void defaultPrivacy() throws IOException, URISyntaxException {
final BesuController besuController = setUpControllerWithPrivacyEnabled(false);
void defaultPrivacy() {
final BesuController besuController =
DaggerPrivacyTest_PrivacyTestComponent.builder().build().getBesuController();
final PrecompiledContract precompiledContract = getPrecompile(besuController, DEFAULT_PRIVACY);
assertThat(precompiledContract.getName()).isEqualTo("Privacy");
}
@Test
public void flexibleEnabledPrivacy() throws IOException, URISyntaxException {
final BesuController besuController = setUpControllerWithPrivacyEnabled(true);
final PrecompiledContract flexiblePrecompiledContract =
getPrecompile(besuController, FLEXIBLE_PRIVACY);
assertThat(flexiblePrecompiledContract.getName()).isEqualTo("FlexiblePrivacy");
}
private BesuController setUpControllerWithPrivacyEnabled(final boolean flexibleEnabled)
throws IOException, URISyntaxException {
final Path dbDir = Files.createTempDirectory(dataDir, "database");
final var miningParameters = MiningParameters.newDefault();
final var dataStorageConfiguration = DataStorageConfiguration.DEFAULT_FOREST_CONFIG;
final PrivacyParameters privacyParameters =
new PrivacyParameters.Builder()
.setEnabled(true)
.setEnclaveUrl(new URI("http://127.0.0.1:8000"))
.setStorageProvider(
createKeyValueStorageProvider(
dataDir, dbDir, dataStorageConfiguration, miningParameters))
.setEnclaveFactory(new EnclaveFactory(vertx))
.setFlexiblePrivacyGroupsEnabled(flexibleEnabled)
.build();
return new BesuController.Builder()
.fromEthNetworkConfig(EthNetworkConfig.getNetworkConfig(NetworkName.MAINNET), SyncMode.FULL)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())
.networkId(BigInteger.ONE)
.miningParameters(miningParameters)
.dataStorageConfiguration(dataStorageConfiguration)
.nodeKey(NodeKeyUtils.generate())
.metricsSystem(new NoOpMetricsSystem())
.dataDirectory(dataDir)
.clock(TestClock.fixed())
.privacyParameters(privacyParameters)
.transactionPoolConfiguration(TransactionPoolConfiguration.DEFAULT)
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.build();
}
private PrivacyStorageProvider createKeyValueStorageProvider(
final Path dataDir,
final Path dbDir,
final DataStorageConfiguration dataStorageConfiguration,
final MiningParameters miningParameters) {
final var besuConfiguration = new BesuConfigurationImpl();
besuConfiguration
.init(dataDir, dbDir, dataStorageConfiguration)
.withMiningParameters(miningParameters);
return new PrivacyKeyValueStorageProviderBuilder()
.withStorageFactory(
new RocksDBKeyValuePrivacyStorageFactory(
new RocksDBKeyValueStorageFactory(
() ->
new RocksDBFactoryConfiguration(
DEFAULT_MAX_OPEN_FILES,
DEFAULT_BACKGROUND_THREAD_COUNT,
DEFAULT_CACHE_CAPACITY,
DEFAULT_IS_HIGH_SPEC),
Arrays.asList(KeyValueSegmentIdentifier.values()),
RocksDBMetricsFactory.PRIVATE_ROCKS_DB_METRICS)))
.withCommonConfiguration(besuConfiguration)
.withMetricsSystem(new NoOpMetricsSystem())
.build();
}
private PrecompiledContract getPrecompile(
final BesuController besuController, final Address defaultPrivacy) {
return besuController
@@ -169,4 +89,55 @@ public class PrivacyTest {
private BlockHeader blockHeader(final long number) {
return new BlockHeaderTestFixture().number(number).buildHeader();
}
@Singleton
@Component(
modules = {
PrivacyParametersModule.class,
PrivacyTest.PrivacyTestBesuControllerModule.class,
PrivacyTestModule.class,
MockBesuCommandModule.class,
BonsaiCachedMerkleTrieLoaderModule.class,
NoOpMetricsSystemModule.class,
BesuPluginContextModule.class,
BlobCacheModule.class
})
interface PrivacyTestComponent extends BesuComponent {
BesuController getBesuController();
}
@Module
static class PrivacyTestBesuControllerModule {
@Provides
@Singleton
@SuppressWarnings("CloseableProvides")
BesuController provideBesuController(
final PrivacyParameters privacyParameters,
final DataStorageConfiguration dataStorageConfiguration,
final PrivacyTestComponent context,
@Named("dataDir") final Path dataDir) {
return new BesuController.Builder()
.fromGenesisFile(GenesisConfigFile.mainnet(), SyncMode.FULL)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())
.networkId(BigInteger.ONE)
.miningParameters(MiningParameters.newDefault())
.dataStorageConfiguration(dataStorageConfiguration)
.nodeKey(NodeKeyUtils.generate())
.metricsSystem(new NoOpMetricsSystem())
.dataDirectory(dataDir)
.clock(TestClock.fixed())
.privacyParameters(privacyParameters)
.transactionPoolConfiguration(TransactionPoolConfiguration.DEFAULT)
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.besuComponent(context)
.build();
}
}
}

View File

@@ -22,8 +22,10 @@ import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_CACHE_CAPACITY;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_IS_HIGH_SPEC;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_MAX_OPEN_FILES;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.JsonUtil;
import org.hyperledger.besu.config.MergeConfigOptions;
@@ -483,6 +485,7 @@ public final class RunnerTest {
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.randomPeerPriority(Boolean.FALSE)
.besuComponent(mock(BesuComponent.class))
.maxPeers(25)
.maxRemotelyInitiatedPeers(15)
.build();

View File

@@ -16,10 +16,12 @@ package org.hyperledger.besu.chainexport;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.chainimport.RlpBlockImporter;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
@@ -102,6 +104,7 @@ public final class RlpBlockExporterTest {
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.besuComponent(mock(BesuComponent.class))
.build();
}

View File

@@ -17,7 +17,9 @@ package org.hyperledger.besu.chainimport;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.JsonUtil;
import org.hyperledger.besu.controller.BesuController;
@@ -463,6 +465,7 @@ public abstract class JsonBlockImporterTest {
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.besuComponent(mock(BesuComponent.class))
.build();
}
}

View File

@@ -16,9 +16,11 @@ package org.hyperledger.besu.chainimport;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
@@ -77,6 +79,7 @@ public final class RlpBlockImporterTest {
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.besuComponent(mock(BesuComponent.class))
.build();
final RlpBlockImporter.ImportResult result =
rlpBlockImporter.importBlockchain(source, targetController, false);
@@ -110,6 +113,7 @@ public final class RlpBlockImporterTest {
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.besuComponent(mock(BesuComponent.class))
.build();
assertThatThrownBy(
@@ -140,6 +144,7 @@ public final class RlpBlockImporterTest {
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.besuComponent(mock(BesuComponent.class))
.build();
final RlpBlockImporter.ImportResult result =

View File

@@ -229,9 +229,6 @@ public abstract class CommandTestAbstract {
@Mock
protected Logger mockLogger;
@Mock(lenient = true)
protected BesuComponent mockBesuComponent;
@Captor protected ArgumentCaptor<Collection<Bytes>> bytesCollectionCollector;
@Captor protected ArgumentCaptor<Path> pathArgumentCaptor;
@Captor protected ArgumentCaptor<String> stringArgumentCaptor;
@@ -384,8 +381,6 @@ public abstract class CommandTestAbstract {
lenient()
.when(mockBesuPluginContext.getService(TransactionSelectionService.class))
.thenReturn(Optional.of(txSelectionService));
when(mockBesuComponent.getBesuCommandLogger()).thenReturn(mockLogger);
}
@BeforeEach
@@ -470,7 +465,6 @@ public abstract class CommandTestAbstract {
switch (testType) {
case REQUIRED_OPTION:
return new TestBesuCommandWithRequiredOption(
mockBesuComponent,
() -> rlpBlockImporter,
this::jsonBlockImporterFactory,
(blockchain) -> rlpBlockExporter,
@@ -480,10 +474,10 @@ public abstract class CommandTestAbstract {
environment,
storageService,
securityModuleService,
privacyPluginService);
privacyPluginService,
mockLogger);
case PORT_CHECK:
return new TestBesuCommand(
mockBesuComponent,
() -> rlpBlockImporter,
this::jsonBlockImporterFactory,
(blockchain) -> rlpBlockExporter,
@@ -493,10 +487,10 @@ public abstract class CommandTestAbstract {
environment,
storageService,
securityModuleService,
privacyPluginService);
privacyPluginService,
mockLogger);
default:
return new TestBesuCommandWithoutPortCheck(
mockBesuComponent,
() -> rlpBlockImporter,
this::jsonBlockImporterFactory,
(blockchain) -> rlpBlockExporter,
@@ -506,7 +500,8 @@ public abstract class CommandTestAbstract {
environment,
storageService,
securityModuleService,
privacyPluginService);
privacyPluginService,
mockLogger);
}
}
@@ -536,7 +531,6 @@ public abstract class CommandTestAbstract {
private Vertx vertx;
TestBesuCommand(
final BesuComponent besuComponent,
final Supplier<RlpBlockImporter> mockBlockImporter,
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
@@ -546,9 +540,9 @@ public abstract class CommandTestAbstract {
final Map<String, String> environment,
final StorageServiceImpl storageService,
final SecurityModuleServiceImpl securityModuleService,
final PrivacyPluginServiceImpl privacyPluginService) {
final PrivacyPluginServiceImpl privacyPluginService,
final Logger commandLogger) {
super(
besuComponent,
mockBlockImporter,
jsonBlockImporterFactory,
rlpBlockExporterFactory,
@@ -564,7 +558,8 @@ public abstract class CommandTestAbstract {
new TransactionSelectionServiceImpl(),
new TransactionPoolValidatorServiceImpl(),
new TransactionSimulationServiceImpl(),
new BlockchainServiceImpl());
new BlockchainServiceImpl(),
commandLogger);
}
@Override
@@ -635,7 +630,6 @@ public abstract class CommandTestAbstract {
private final Boolean acceptTermsAndConditions = false;
TestBesuCommandWithRequiredOption(
final BesuComponent besuComponent,
final Supplier<RlpBlockImporter> mockBlockImporter,
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
@@ -645,9 +639,9 @@ public abstract class CommandTestAbstract {
final Map<String, String> environment,
final StorageServiceImpl storageService,
final SecurityModuleServiceImpl securityModuleService,
final PrivacyPluginServiceImpl privacyPluginService) {
final PrivacyPluginServiceImpl privacyPluginService,
final Logger commandLogger) {
super(
besuComponent,
mockBlockImporter,
jsonBlockImporterFactory,
rlpBlockExporterFactory,
@@ -657,7 +651,8 @@ public abstract class CommandTestAbstract {
environment,
storageService,
securityModuleService,
privacyPluginService);
privacyPluginService,
commandLogger);
}
public Boolean getAcceptTermsAndConditions() {
@@ -669,7 +664,6 @@ public abstract class CommandTestAbstract {
public static class TestBesuCommandWithoutPortCheck extends TestBesuCommand {
TestBesuCommandWithoutPortCheck(
final BesuComponent context,
final Supplier<RlpBlockImporter> mockBlockImporter,
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
@@ -679,9 +673,9 @@ public abstract class CommandTestAbstract {
final Map<String, String> environment,
final StorageServiceImpl storageService,
final SecurityModuleServiceImpl securityModuleService,
final PrivacyPluginServiceImpl privacyPluginService) {
final PrivacyPluginServiceImpl privacyPluginService,
final Logger commandLogger) {
super(
context,
mockBlockImporter,
jsonBlockImporterFactory,
rlpBlockExporterFactory,
@@ -691,7 +685,8 @@ public abstract class CommandTestAbstract {
environment,
storageService,
securityModuleService,
privacyPluginService);
privacyPluginService,
commandLogger);
}
@Override

View File

@@ -413,11 +413,29 @@ public class TransactionPoolOptionsTest
@Test
public void maxPrioritizedTxsPerTypeWrongTxType() {
internalTestFailure(
"Invalid value for option '--tx-pool-max-prioritized-by-type' (MAP<TYPE,INTEGER>): expected one of [FRONTIER, ACCESS_LIST, EIP1559, BLOB, SET_CODE] (case-insensitive) but was 'WRONG_TYPE'",
"Invalid value for option '--tx-pool-max-prioritized-by-type' (MAP<TYPE,INTEGER>): expected one of [FRONTIER, ACCESS_LIST, EIP1559, BLOB, DELEGATE_CODE] (case-insensitive) but was 'WRONG_TYPE'",
"--tx-pool-max-prioritized-by-type",
"WRONG_TYPE=1");
}
@Test
public void minScoreWorks() {
final byte minScore = -10;
internalTestSuccess(
config -> assertThat(config.getMinScore()).isEqualTo(minScore),
"--tx-pool-min-score",
Byte.toString(minScore));
}
@Test
public void minScoreNonByteValueReturnError() {
final var overflowMinScore = Integer.toString(-300);
internalTestFailure(
"Invalid value for option '--tx-pool-min-score': '" + overflowMinScore + "' is not a byte",
"--tx-pool-min-score",
overflowMinScore);
}
@Override
protected TransactionPoolConfiguration createDefaultDomainObject() {
return TransactionPoolConfiguration.DEFAULT;

View File

@@ -0,0 +1,98 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.components;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveFactory;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.plugin.data.Restriction;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
import dagger.Module;
import dagger.Provides;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
@Module
public class EnclaveModule {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
private static final Bytes ENCLAVE_PUBLIC_KEY =
Bytes.fromBase64String("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=");
private static final Bytes32 PRIVACY_GROUP_BYTES32 =
Bytes32.fromHexString("0xf250d523ae9164722b06ca25cfa2a7f3c45df96b09e215236f886c876f715bfa");
private static final Bytes MOCK_PAYLOAD =
Bytes.fromHexString(
"0x608060405234801561001057600080fd5b5060008054600160a060020a03191633179055610199806100326000396000f3fe6080604052600436106100565763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416633fa4f245811461005b5780636057361d1461008257806367e404ce146100ae575b600080fd5b34801561006757600080fd5b506100706100ec565b60408051918252519081900360200190f35b34801561008e57600080fd5b506100ac600480360360208110156100a557600080fd5b50356100f2565b005b3480156100ba57600080fd5b506100c3610151565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b60025490565b604080513381526020810183905281517fc9db20adedc6cf2b5d25252b101ab03e124902a73fcb12b753f3d1aaa2d8f9f5929181900390910190a16002556001805473ffffffffffffffffffffffffffffffffffffffff191633179055565b60015473ffffffffffffffffffffffffffffffffffffffff169056fea165627a7a72305820c7f729cb24e05c221f5aa913700793994656f233fe2ce3b9fd9a505ea17e8d8a0029");
private static final KeyPair KEY_PAIR =
SIGNATURE_ALGORITHM
.get()
.createKeyPair(
SIGNATURE_ALGORITHM
.get()
.createPrivateKey(
new BigInteger(
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16)));
private static final PrivateTransaction PRIVATE_TRANSACTION =
PrivateTransaction.builder()
.chainId(BigInteger.valueOf(1337))
.gasLimit(1000)
.gasPrice(Wei.ZERO)
.nonce(0)
.payload(MOCK_PAYLOAD)
.to(null)
.privateFrom(ENCLAVE_PUBLIC_KEY)
.privateFor(Collections.singletonList(ENCLAVE_PUBLIC_KEY))
.restriction(Restriction.RESTRICTED)
.value(Wei.ZERO)
.signAndBuild(KEY_PAIR);
@Provides
EnclaveFactory provideMockableEnclaveFactory() {
Enclave mockEnclave = mock(Enclave.class);
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
PRIVATE_TRANSACTION.writeTo(rlpOutput);
when(mockEnclave.receive(any()))
.thenReturn(
new ReceiveResponse(
rlpOutput.encoded().toBase64String().getBytes(StandardCharsets.UTF_8),
PRIVACY_GROUP_BYTES32.toBase64String(),
ENCLAVE_PUBLIC_KEY.toBase64String()));
EnclaveFactory enclaveFactory = mock(EnclaveFactory.class);
when(enclaveFactory.createVertxEnclave(any())).thenReturn(mockEnclave);
return enclaveFactory;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.components;
import org.hyperledger.besu.config.GenesisConfigFile;
import javax.inject.Named;
import dagger.Module;
import dagger.Provides;
@Module
public class GenesisConfigModule {
@Named("default")
@Provides
GenesisConfigFile provideDefaultGenesisConfigFile() {
return GenesisConfigFile.DEFAULT;
}
@Named("mainnet")
@Provides
GenesisConfigFile provideMainnetGenesisConfigFile() {
return GenesisConfigFile.mainnet();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.components;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.cli.BesuCommand;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Module
public class MockBesuCommandModule {
@Provides
BesuCommand provideBesuCommand() {
return mock(BesuCommand.class);
}
@Provides
@Singleton
MetricsConfiguration provideMetricsConfiguration() {
return MetricsConfiguration.builder().build();
}
@Provides
@Named("besuCommandLogger")
@Singleton
Logger provideBesuCommandLogger() {
return LoggerFactory.getLogger(MockBesuCommandModule.class);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.components;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class NoOpMetricsSystemModule {
@Provides
@Singleton
MetricsSystem provideMetricsSystem() {
return new NoOpMetricsSystem();
}
@Provides
@Singleton
ObservableMetricsSystem provideObservableMetricsSystem() {
return new NoOpMetricsSystem();
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.components;
import org.hyperledger.besu.enclave.EnclaveFactory;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyStorageProvider;
import java.net.URI;
import java.net.URISyntaxException;
import dagger.Module;
import dagger.Provides;
import io.vertx.core.Vertx;
/** Provides a general use PrivacyParameters instance for testing. */
@Module
public class PrivacyParametersModule {
@Provides
PrivacyParameters providePrivacyParameters(
final PrivacyStorageProvider storageProvider, final Vertx vertx) {
try {
return new PrivacyParameters.Builder()
.setEnabled(true)
.setEnclaveUrl(new URI("http://127.0.0.1:8000"))
.setStorageProvider(storageProvider)
.setEnclaveFactory(new EnclaveFactory(vertx))
.setFlexiblePrivacyGroupsEnabled(false)
.build();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.components;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_BACKGROUND_THREAD_COUNT;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_CACHE_CAPACITY;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_IS_HIGH_SPEC;
import static org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBCLIOptions.DEFAULT_MAX_OPEN_FILES;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyStorageProvider;
import org.hyperledger.besu.ethereum.privacy.storage.keyvalue.PrivacyKeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBKeyValuePrivacyStorageFactory;
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBKeyValueStorageFactory;
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBMetricsFactory;
import org.hyperledger.besu.plugin.services.storage.rocksdb.configuration.RocksDBFactoryConfiguration;
import org.hyperledger.besu.services.BesuConfigurationImpl;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import io.vertx.core.Vertx;
@Module
public class PrivacyTestModule {
@Provides
@Named("dataDir")
Path provideDataDir() {
try {
return Files.createTempDirectory("PrivacyTestDatadir");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Provides
Vertx provideVertx() {
return Vertx.vertx();
}
@Provides
DataStorageConfiguration provideDataStorageConfiguration() {
return DataStorageConfiguration.DEFAULT_FOREST_CONFIG;
}
@Provides
@Singleton
@Named("dbDir")
Path provideDbDir(@Named("dataDir") final Path dataDir) {
try {
final Path dbDir = Files.createTempDirectory(dataDir, "database");
return dbDir;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Provides
@Singleton
@Named("flexibleEnabled")
Boolean provideFlexibleEnabled() {
return true;
}
@Provides
@Singleton
@SuppressWarnings("CloseableProvides")
PrivacyStorageProvider provideKeyValueStorageProvider(
@Named("dbDir") final Path dbDir,
final DataStorageConfiguration dataStorageConfiguration,
@Named("dataDir") final Path dataDir) {
final var besuConfiguration = new BesuConfigurationImpl();
besuConfiguration.init(dataDir, dbDir, dataStorageConfiguration);
return new PrivacyKeyValueStorageProviderBuilder()
.withStorageFactory(
new RocksDBKeyValuePrivacyStorageFactory(
new RocksDBKeyValueStorageFactory(
() ->
new RocksDBFactoryConfiguration(
DEFAULT_MAX_OPEN_FILES,
DEFAULT_BACKGROUND_THREAD_COUNT,
DEFAULT_CACHE_CAPACITY,
DEFAULT_IS_HIGH_SPEC),
Arrays.asList(KeyValueSegmentIdentifier.values()),
RocksDBMetricsFactory.PRIVATE_ROCKS_DB_METRICS)))
.withCommonConfiguration(besuConfiguration)
.withMetricsSystem(new NoOpMetricsSystem())
.build();
}
}

View File

@@ -19,6 +19,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.CheckpointConfigOptions;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
@@ -156,6 +157,7 @@ public abstract class AbstractBftBesuControllerBuilderTest {
.storageProvider(storageProvider)
.gasLimitCalculator(gasLimitCalculator)
.evmConfiguration(EvmConfiguration.DEFAULT)
.besuComponent(mock(BesuComponent.class))
.networkConfiguration(NetworkingConfiguration.create());
}

View File

@@ -20,6 +20,7 @@ import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.CheckpointConfigOptions;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
@@ -189,6 +190,7 @@ public class CliqueBesuControllerBuilderTest {
.storageProvider(storageProvider)
.gasLimitCalculator(gasLimitCalculator)
.evmConfiguration(EvmConfiguration.DEFAULT)
.besuComponent(mock(BesuComponent.class))
.networkConfiguration(NetworkingConfiguration.create());
}

View File

@@ -23,6 +23,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.CheckpointConfigOptions;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
@@ -189,6 +190,7 @@ public class MergeBesuControllerBuilderTest {
.storageProvider(storageProvider)
.evmConfiguration(EvmConfiguration.DEFAULT)
.networkConfiguration(NetworkingConfiguration.create())
.besuComponent(mock(BesuComponent.class))
.networkId(networkId);
}

View File

@@ -195,6 +195,7 @@ tx-pool-retention-hours=999
tx-pool-max-size=1234
tx-pool-limit-by-account-percentage=0.017
tx-pool-min-gas-price=1000
tx-pool-min-score=100
# Revert Reason
revert-reason-enabled=false

View File

@@ -25,10 +25,11 @@ import java.util.regex.Pattern
plugins {
id 'com.diffplug.spotless' version '6.25.0'
id 'com.github.ben-manes.versions' version '0.51.0'
id 'com.github.jk1.dependency-license-report' version '2.7'
id 'io.spring.dependency-management' version '1.1.5'
id 'com.github.jk1.dependency-license-report' version '2.9'
id 'com.jfrog.artifactory' version '5.2.5'
id 'io.spring.dependency-management' version '1.1.6'
id 'me.champeau.jmh' version '0.7.2' apply false
id 'net.ltgt.errorprone' version '3.1.0'
id 'net.ltgt.errorprone' version '4.0.1'
id 'maven-publish'
}

View File

@@ -55,6 +55,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -245,7 +246,8 @@ public class CliqueBlockCreatorTest {
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(metricsSystem),
conf);
conf,
new BlobCache());
transactionPool.setEnabled();
return transactionPool;
}

View File

@@ -45,6 +45,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -233,7 +234,8 @@ public class CliqueMinerExecutorTest {
mock(TransactionBroadcaster.class),
cliqueEthContext,
new TransactionPoolMetrics(metricsSystem),
conf);
conf,
new BlobCache());
transactionPool.setEnabled();
return transactionPool;

View File

@@ -84,6 +84,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -371,7 +372,8 @@ public class TestContextBuilder {
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(metricsSystem),
poolConf);
poolConf,
new BlobCache());
transactionPool.setEnabled();

View File

@@ -47,6 +47,7 @@ import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitV
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -152,7 +153,8 @@ public class BftBlockCreatorTest {
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(metricsSystem),
poolConf);
poolConf,
new BlobCache());
transactionPool.setEnabled();

View File

@@ -63,6 +63,7 @@ import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardSyncContext;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
@@ -214,7 +215,8 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper {
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(metricsSystem),
poolConf);
poolConf,
new BlobCache());
this.transactionPool.setEnabled();

View File

@@ -98,6 +98,7 @@ import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -480,7 +481,8 @@ public class TestContextBuilder {
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(metricsSystem),
poolConf);
poolConf,
new BlobCache());
transactionPool.setEnabled();

View File

@@ -54,7 +54,7 @@ public class SECPSignature {
* @param s the s
* @param recId the rec id
*/
SECPSignature(final BigInteger r, final BigInteger s, final byte recId) {
public SECPSignature(final BigInteger r, final BigInteger s, final byte recId) {
this.r = r;
this.s = s;
this.recId = recId;

View File

@@ -20,10 +20,13 @@ import java.math.BigInteger;
import java.util.Optional;
/**
* SetCodeAuthorization is a data structure that represents the authorization to set code on a EOA
* account.
* CodeDelegation is a data structure that represents the authorization to delegate code of an EOA
* account to another account.
*/
public interface SetCodeAuthorization {
public interface CodeDelegation {
/** The cost of delegating code on an existing account. */
long PER_AUTH_BASE_COST = 2_500L;
/**
* Return the chain id.
*
@@ -53,11 +56,11 @@ public interface SetCodeAuthorization {
Optional<Address> authorizer();
/**
* Return a valid nonce or empty otherwise. A nonce is valid if the size of the list is exactly 1
* Return the nonce
*
* @return all the optional nonce
* @return the nonce
*/
Optional<Long> nonce();
long nonce();
/**
* Return the recovery id.

View File

@@ -236,16 +236,16 @@ public interface Transaction {
int getSize();
/**
* Returns the set code transaction payload if this transaction is a 7702 transaction.
* Returns the code delegations if this transaction is a 7702 transaction.
*
* @return the set code transaction payloads
* @return the code delegations
*/
Optional<List<SetCodeAuthorization>> getAuthorizationList();
Optional<List<CodeDelegation>> getCodeDelegationList();
/**
* Returns the size of the authorization list.
*
* @return the size of the authorization list
*/
int authorizationListSize();
int codeDelegationListSize();
}

View File

@@ -29,10 +29,10 @@ public enum TransactionType {
/** Blob transaction type. */
BLOB(0x03),
/** Eip7702 transaction type. */
SET_CODE(0x04);
DELEGATE_CODE(0x04);
private static final Set<TransactionType> ACCESS_LIST_SUPPORTED_TRANSACTION_TYPES =
Set.of(ACCESS_LIST, EIP1559, BLOB, SET_CODE);
Set.of(ACCESS_LIST, EIP1559, BLOB, DELEGATE_CODE);
private static final EnumSet<TransactionType> LEGACY_FEE_MARKET_TRANSACTION_TYPES =
EnumSet.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST);
@@ -86,7 +86,7 @@ public enum TransactionType {
TransactionType.ACCESS_LIST,
TransactionType.EIP1559,
TransactionType.BLOB,
TransactionType.SET_CODE
TransactionType.DELEGATE_CODE
})
.filter(transactionType -> transactionType.typeValue == serializedTypeValue)
.findFirst()
@@ -132,12 +132,21 @@ public enum TransactionType {
return this.equals(BLOB);
}
/**
* Does transaction type support delegate code.
*
* @return the boolean
*/
public boolean supportsDelegateCode() {
return this.equals(DELEGATE_CODE);
}
/**
* Does transaction type require code.
*
* @return the boolean
*/
public boolean requiresSetCode() {
return this.equals(SET_CODE);
public boolean requiresCodeDelegation() {
return this.equals(DELEGATE_CODE);
}
}

View File

@@ -236,7 +236,12 @@ public class EthCreateAccessListIntegrationTest {
new JsonRpcSuccessResponse(null, new CreateAccessListResult(accessList, gasUsed));
final JsonRpcResponse response = method.response(request);
assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse);
assertThat(response)
.usingRecursiveComparison()
// customize the comparison for the type that lazy compute the hashCode
.withEqualsForType(UInt256::equals, UInt256.class)
.withEqualsForType(Address::equals, Address.class)
.isEqualTo(expectedResponse);
}
private JsonRpcRequestContext requestWithParams(final Object... params) {

View File

@@ -50,6 +50,7 @@ import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
@@ -121,7 +122,8 @@ public class EthGetFilterChangesIntegrationTest {
batchAddedListener,
ethContext,
new TransactionPoolMetrics(metricsSystem),
TransactionPoolConfiguration.DEFAULT);
TransactionPoolConfiguration.DEFAULT,
new BlobCache());
transactionPool.setEnabled();
final BlockchainQueries blockchainQueries =
new BlockchainQueries(

View File

@@ -50,6 +50,7 @@ import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
@@ -121,7 +122,8 @@ public class EthGetFilterChangesIntegrationTest {
batchAddedListener,
ethContext,
new TransactionPoolMetrics(metricsSystem),
TransactionPoolConfiguration.DEFAULT);
TransactionPoolConfiguration.DEFAULT,
new BlobCache());
transactionPool.setEnabled();
final BlockchainQueries blockchainQueries =
new BlockchainQueries(

View File

@@ -51,6 +51,7 @@ public enum RpcMethod {
DEBUG_GET_RAW_BLOCK("debug_getRawBlock"),
DEBUG_GET_RAW_RECEIPTS("debug_getRawReceipts"),
DEBUG_GET_RAW_TRANSACTION("debug_getRawTransaction"),
ENGINE_GET_BLOBS_V1("engine_getBlobsV1"),
ENGINE_GET_PAYLOAD_V1("engine_getPayloadV1"),
ENGINE_GET_PAYLOAD_V2("engine_getPayloadV2"),
ENGINE_GET_PAYLOAD_V3("engine_getPayloadV3"),

View File

@@ -14,15 +14,19 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonCallParameterUtil.validateAndGetCallParams;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
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.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
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.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
@@ -34,32 +38,68 @@ import org.hyperledger.besu.evm.tracing.EstimateGasOperationTracer;
import java.util.Optional;
public abstract class AbstractEstimateGas implements JsonRpcMethod {
public abstract class AbstractEstimateGas extends AbstractBlockParameterMethod {
private static final double SUB_CALL_REMAINING_GAS_RATIO = 65D / 64D;
protected final BlockchainQueries blockchainQueries;
protected final TransactionSimulator transactionSimulator;
public AbstractEstimateGas(
final BlockchainQueries blockchainQueries, final TransactionSimulator transactionSimulator) {
this.blockchainQueries = blockchainQueries;
super(blockchainQueries);
this.transactionSimulator = transactionSimulator;
}
protected BlockHeader blockHeader() {
final Blockchain theChain = blockchainQueries.getBlockchain();
// Optimistically get the block header for the chain head without taking a lock,
// but revert to the safe implementation if it returns an empty optional. (It's
// possible the chain head has been updated but the block is still being persisted
// to storage/cache under the lock).
return theChain
.getBlockHeader(theChain.getChainHeadHash())
.or(() -> theChain.getBlockHeaderSafe(theChain.getChainHeadHash()))
.orElse(null);
@Override
protected BlockParameter blockParameter(final JsonRpcRequestContext request) {
try {
return request.getOptionalParameter(1, BlockParameter.class).orElse(BlockParameter.LATEST);
} catch (JsonRpcParameter.JsonRpcParameterException e) {
throw new InvalidJsonRpcParameters(
"Invalid block parameter (index 1)", RpcErrorType.INVALID_BLOCK_PARAMS, e);
}
}
protected Optional<BlockHeader> blockHeader(final long blockNumber) {
if (getBlockchainQueries().headBlockNumber() == blockNumber) {
// chain head header if cached, and we can return it form memory
return Optional.of(getBlockchainQueries().getBlockchain().getChainHeadHeader());
}
return getBlockchainQueries().getBlockHeaderByNumber(blockNumber);
}
protected Optional<RpcErrorType> validateBlockHeader(
final Optional<BlockHeader> maybeBlockHeader) {
if (maybeBlockHeader.isEmpty()) {
return Optional.of(RpcErrorType.BLOCK_NOT_FOUND);
}
final var blockHeader = maybeBlockHeader.get();
if (!getBlockchainQueries()
.getWorldStateArchive()
.isWorldStateAvailable(blockHeader.getStateRoot(), blockHeader.getHash())) {
return Optional.of(RpcErrorType.WORLD_STATE_UNAVAILABLE);
}
return Optional.empty();
}
@Override
protected Object resultByBlockNumber(
final JsonRpcRequestContext requestContext, final long blockNumber) {
final JsonCallParameter jsonCallParameter = validateAndGetCallParams(requestContext);
final Optional<BlockHeader> maybeBlockHeader = blockHeader(blockNumber);
final Optional<RpcErrorType> jsonRpcError = validateBlockHeader(maybeBlockHeader);
if (jsonRpcError.isPresent()) {
return errorResponse(requestContext, jsonRpcError.get());
}
return resultByBlockHeader(requestContext, jsonCallParameter, maybeBlockHeader.get());
}
protected abstract Object resultByBlockHeader(
final JsonRpcRequestContext requestContext,
final JsonCallParameter jsonCallParameter,
final BlockHeader blockHeader);
protected CallParameter overrideGasLimitAndPrice(
final JsonCallParameter callParams, final long gasLimit) {
return new CallParameter(

View File

@@ -14,15 +14,11 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonCallParameterUtil.validateAndGetCallParams;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter;
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.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.CreateAccessListResult;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
@@ -52,44 +48,29 @@ public class EthCreateAccessList extends AbstractEstimateGas {
}
@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final JsonCallParameter jsonCallParameter = validateAndGetCallParams(requestContext);
final BlockHeader blockHeader = blockHeader();
final Optional<RpcErrorType> jsonRpcError = validateBlockHeader(blockHeader);
if (jsonRpcError.isPresent()) {
return errorResponse(requestContext, jsonRpcError.get());
}
protected Object resultByBlockHeader(
final JsonRpcRequestContext requestContext,
final JsonCallParameter jsonCallParameter,
final BlockHeader blockHeader) {
final AccessListSimulatorResult maybeResult =
processTransaction(jsonCallParameter, blockHeader);
// if the call accessList is different from the simulation result, calculate gas and return
if (shouldProcessWithAccessListOverride(jsonCallParameter, maybeResult.getTracer())) {
if (shouldProcessWithAccessListOverride(jsonCallParameter, maybeResult.tracer())) {
final AccessListSimulatorResult result =
processTransactionWithAccessListOverride(
jsonCallParameter, blockHeader, maybeResult.getTracer().getAccessList());
jsonCallParameter, blockHeader, maybeResult.tracer().getAccessList());
return createResponse(requestContext, result);
} else {
return createResponse(requestContext, maybeResult);
}
}
private Optional<RpcErrorType> validateBlockHeader(final BlockHeader blockHeader) {
if (blockHeader == null) {
return Optional.of(RpcErrorType.INTERNAL_ERROR);
}
if (!blockchainQueries
.getWorldStateArchive()
.isWorldStateAvailable(blockHeader.getStateRoot(), blockHeader.getHash())) {
return Optional.of(RpcErrorType.WORLD_STATE_UNAVAILABLE);
}
return Optional.empty();
}
private JsonRpcResponse createResponse(
private Object createResponse(
final JsonRpcRequestContext requestContext, final AccessListSimulatorResult result) {
return result
.getResult()
.map(createResponse(requestContext, result.getTracer()))
.orElse(errorResponse(requestContext, RpcErrorType.INTERNAL_ERROR));
.result()
.map(createResponse(requestContext, result.tracer()))
.orElseGet(() -> errorResponse(requestContext, RpcErrorType.INTERNAL_ERROR));
}
private TransactionValidationParams transactionValidationParams(
@@ -117,14 +98,12 @@ public class EthCreateAccessList extends AbstractEstimateGas {
return !Objects.equals(tracer.getAccessList(), parameters.getAccessList().get());
}
private Function<TransactionSimulatorResult, JsonRpcResponse> createResponse(
private Function<TransactionSimulatorResult, Object> createResponse(
final JsonRpcRequestContext request, final AccessListOperationTracer operationTracer) {
return result ->
result.isSuccessful()
? new JsonRpcSuccessResponse(
request.getRequest().getId(),
new CreateAccessListResult(
operationTracer.getAccessList(), processEstimateGas(result, operationTracer)))
? new CreateAccessListResult(
operationTracer.getAccessList(), processEstimateGas(result, operationTracer))
: errorResponse(request, result);
}
@@ -138,8 +117,7 @@ public class EthCreateAccessList extends AbstractEstimateGas {
final AccessListOperationTracer tracer = AccessListOperationTracer.create();
final Optional<TransactionSimulatorResult> result =
transactionSimulator.process(
callParams, transactionValidationParams, tracer, blockHeader.getNumber());
transactionSimulator.process(callParams, transactionValidationParams, tracer, blockHeader);
return new AccessListSimulatorResult(result, tracer);
}
@@ -156,7 +134,7 @@ public class EthCreateAccessList extends AbstractEstimateGas {
final Optional<TransactionSimulatorResult> result =
transactionSimulator.process(
callParameter, transactionValidationParams, tracer, blockHeader.getNumber());
callParameter, transactionValidationParams, tracer, blockHeader);
return new AccessListSimulatorResult(result, tracer);
}
@@ -176,22 +154,6 @@ public class EthCreateAccessList extends AbstractEstimateGas {
Optional.ofNullable(accessListEntries));
}
private static class AccessListSimulatorResult {
final Optional<TransactionSimulatorResult> result;
final AccessListOperationTracer tracer;
public AccessListSimulatorResult(
final Optional<TransactionSimulatorResult> result, final AccessListOperationTracer tracer) {
this.result = result;
this.tracer = tracer;
}
public Optional<TransactionSimulatorResult> getResult() {
return result;
}
public AccessListOperationTracer getTracer() {
return tracer;
}
}
private record AccessListSimulatorResult(
Optional<TransactionSimulatorResult> result, AccessListOperationTracer tracer) {}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright ConsenSys AG.
* Copyright contributors to Hyperledger Besu.
*
* 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
@@ -14,13 +14,10 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonCallParameterUtil.validateAndGetCallParams;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter;
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.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
@@ -38,7 +35,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EthEstimateGas extends AbstractEstimateGas {
private static final Logger LOG = LoggerFactory.getLogger(EthEstimateGas.class);
public EthEstimateGas(
@@ -52,19 +48,10 @@ public class EthEstimateGas extends AbstractEstimateGas {
}
@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final JsonCallParameter callParams = validateAndGetCallParams(requestContext);
final BlockHeader blockHeader = blockHeader();
if (blockHeader == null) {
LOG.error("Chain head block not found");
return errorResponse(requestContext, RpcErrorType.INTERNAL_ERROR);
}
if (!blockchainQueries
.getWorldStateArchive()
.isWorldStateAvailable(blockHeader.getStateRoot(), blockHeader.getHash())) {
return errorResponse(requestContext, RpcErrorType.WORLD_STATE_UNAVAILABLE);
}
protected Object resultByBlockHeader(
final JsonRpcRequestContext requestContext,
final JsonCallParameter callParams,
final BlockHeader blockHeader) {
final CallParameter modifiedCallParams =
overrideGasLimitAndPrice(callParams, blockHeader.getGasLimit());
@@ -72,44 +59,48 @@ public class EthEstimateGas extends AbstractEstimateGas {
final boolean isAllowExceedingBalance = !callParams.isMaybeStrict().orElse(Boolean.FALSE);
final EstimateGasOperationTracer operationTracer = new EstimateGasOperationTracer();
final var transactionValidationParams =
ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator())
.isAllowExceedingBalance(isAllowExceedingBalance)
.build();
var gasUsed =
executeSimulation(
blockHeader, modifiedCallParams, operationTracer, isAllowExceedingBalance);
LOG.debug("Processing transaction with params: {}", modifiedCallParams);
final var maybeResult =
transactionSimulator.process(
modifiedCallParams, transactionValidationParams, operationTracer, blockHeader);
if (gasUsed.isEmpty()) {
LOG.error("gasUsed is empty after simulating transaction.");
return errorResponse(requestContext, RpcErrorType.INTERNAL_ERROR);
final Optional<JsonRpcErrorResponse> maybeErrorResponse =
validateSimulationResult(requestContext, maybeResult);
if (maybeErrorResponse.isPresent()) {
return maybeErrorResponse.get();
}
// if the transaction is invalid or doesn't have enough gas with the max it never will!
if (gasUsed.get().isInvalid() || !gasUsed.get().isSuccessful()) {
return errorResponse(requestContext, gasUsed.get());
}
var low = gasUsed.get().result().getEstimateGasUsedByTransaction();
var lowResult =
executeSimulation(
blockHeader,
final var result = maybeResult.get();
long low = result.result().getEstimateGasUsedByTransaction();
final var lowResult =
transactionSimulator.process(
overrideGasLimitAndPrice(callParams, low),
transactionValidationParams,
operationTracer,
isAllowExceedingBalance);
blockHeader);
if (lowResult.isPresent() && lowResult.get().isSuccessful()) {
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), Quantity.create(low));
return Quantity.create(low);
}
var high = processEstimateGas(gasUsed.get(), operationTracer);
var mid = high;
while (low + 1 < high) {
mid = (high + low) / 2;
long high = processEstimateGas(result, operationTracer);
long mid;
while (low + 1 < high) {
mid = (low + high) / 2;
var binarySearchResult =
executeSimulation(
blockHeader,
transactionSimulator.process(
overrideGasLimitAndPrice(callParams, mid),
transactionValidationParams,
operationTracer,
isAllowExceedingBalance);
blockHeader);
if (binarySearchResult.isEmpty() || !binarySearchResult.get().isSuccessful()) {
low = mid;
} else {
@@ -117,21 +108,23 @@ public class EthEstimateGas extends AbstractEstimateGas {
}
}
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), Quantity.create(high));
return Quantity.create(high);
}
private Optional<TransactionSimulatorResult> executeSimulation(
final BlockHeader blockHeader,
final CallParameter modifiedCallParams,
final EstimateGasOperationTracer operationTracer,
final boolean allowExceedingBalance) {
return transactionSimulator.process(
modifiedCallParams,
ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator())
.isAllowExceedingBalance(allowExceedingBalance)
.build(),
operationTracer,
blockHeader.getNumber());
private Optional<JsonRpcErrorResponse> validateSimulationResult(
final JsonRpcRequestContext requestContext,
final Optional<TransactionSimulatorResult> maybeResult) {
if (maybeResult.isEmpty()) {
LOG.error("No result after simulating transaction.");
return Optional.of(
new JsonRpcErrorResponse(
requestContext.getRequest().getId(), RpcErrorType.INTERNAL_ERROR));
}
// if the transaction is invalid or doesn't have enough gas with the max it never will!
if (maybeResult.get().isInvalid() || !maybeResult.get().isSuccessful()) {
return Optional.of(errorResponse(requestContext, maybeResult.get()));
}
return Optional.empty();
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.internal.methods.engine;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter;
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.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlobAndProofV1;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.vertx.core.Vertx;
/**
* #### Specification
*
* <p>1. Given an array of blob versioned hashes client software **MUST** respond with an array of
* `BlobAndProofV1` objects with matching versioned hashes, respecting the order of versioned hashes
* in the input array.
*
* <p>2. Client software **MUST** place responses in the order given in the request, using `null`
* for any missing blobs. For instance, if the request is `[A_versioned_hash, B_versioned_hash,
* C_versioned_hash]` and client software has data for blobs `A` and `C`, but doesn't have data for
* `B`, the response **MUST** be `[A, null, C]`.
*
* <p>3. Client software **MUST** support request sizes of at least 128 blob versioned hashes. The
* client **MUST** return `-38004: Too large request` error if the number of requested blobs is too
* large.
*
* <p>4. Client software **MAY** return an array of all `null` entries if syncing or otherwise
* unable to serve blob pool data.
*
* <p>5. Callers **MUST** consider that execution layer clients may prune old blobs from their pool,
* and will respond with `null` if a blob has been pruned.
*/
public class EngineGetBlobsV1 extends ExecutionEngineJsonRpcMethod {
private final TransactionPool transactionPool;
public EngineGetBlobsV1(
final Vertx vertx,
final ProtocolContext protocolContext,
final EngineCallListener engineCallListener,
final TransactionPool transactionPool) {
super(vertx, protocolContext, engineCallListener);
this.transactionPool = transactionPool;
}
@Override
public String getName() {
return "engine_getBlobsV1";
}
@Override
public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) {
final VersionedHash[] versionedHashes;
try {
versionedHashes = requestContext.getRequiredParameter(0, VersionedHash[].class);
} catch (JsonRpcParameter.JsonRpcParameterException e) {
throw new InvalidJsonRpcParameters(
"Invalid versioned hashes parameter (index 0)",
RpcErrorType.INVALID_VERSIONED_HASHES_PARAMS,
e);
}
if (versionedHashes.length > 128) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(),
RpcErrorType.INVALID_ENGINE_GET_BLOBS_V1_TOO_LARGE_REQUEST);
}
final List<BlobAndProofV1> result = getBlobV1Result(versionedHashes);
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result);
}
private @Nonnull List<BlobAndProofV1> getBlobV1Result(final VersionedHash[] versionedHashes) {
return Arrays.stream(versionedHashes)
.map(transactionPool::getBlobQuad)
.map(this::getBlobAndProofV1)
.toList();
}
private @Nullable BlobAndProofV1 getBlobAndProofV1(final BlobsWithCommitments.BlobQuad bq) {
if (bq == null) {
return null;
}
return new BlobAndProofV1(
bq.blob().getData().toHexString(), bq.kzgProof().getData().toHexString());
}
}

View File

@@ -61,12 +61,12 @@ public class ConsolidationRequestParameter {
}
@JsonGetter
public String getSourcePubKey() {
public String getSourcePubkey() {
return sourcePubkey;
}
@JsonGetter
public String getTargetPubKey() {
public String getTargetPubkey() {
return targetPubkey;
}

View File

@@ -58,6 +58,7 @@ public enum RpcErrorType implements RpcMethodError {
INVALID_ENGINE_NEW_PAYLOAD_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid engine payload parameter"),
INVALID_ENGINE_PREPARE_PAYLOAD_PARAMS(
INVALID_PARAMS_ERROR_CODE, "Invalid engine prepare payload parameter"),
INVALID_ENGINE_GET_BLOBS_V1_TOO_LARGE_REQUEST(-38004, "Too large request"),
INVALID_ENODE_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid enode params"),
INVALID_EXCESS_BLOB_GAS_PARAMS(
INVALID_PARAMS_ERROR_CODE, "Invalid excess blob gas params (missing or invalid)"),
@@ -109,6 +110,7 @@ public enum RpcErrorType implements RpcMethodError {
INVALID_TRANSACTION_LIMIT_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid transaction limit params"),
INVALID_TRANSACTION_TRACE_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid transaction trace params"),
INVALID_VERSIONED_HASH_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid versioned hash params"),
INVALID_VERSIONED_HASHES_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid versioned hashes params"),
INVALID_VOTE_TYPE_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid vote type params"),
INVALID_WITHDRAWALS_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid withdrawals"),

View File

@@ -0,0 +1,42 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.internal.results;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
/**
* The result of the eth_getBlobAndProofV1 JSON-RPC method contains an array of BlobAndProofV1.
* BlobAndProofV1 contains the blob data and the kzg proof for the blob.
*/
@JsonPropertyOrder({"blob", "proof"})
public class BlobAndProofV1 {
private final String blob;
private final String proof;
public BlobAndProofV1(final String blob, final String proof) {
this.blob = blob;
this.proof = proof;
}
public String getProof() {
return proof;
}
public String getBlob() {
return blob;
}
}

View File

@@ -15,7 +15,7 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.SetCodeAuthorization;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
@@ -94,7 +94,7 @@ public class TransactionCompleteResult implements TransactionResult {
private final List<VersionedHash> versionedHashes;
@JsonInclude(JsonInclude.Include.NON_NULL)
private final List<SetCodeAuthorization> authorizationList;
private final List<CodeDelegation> authorizationList;
public TransactionCompleteResult(final TransactionWithMetadata tx) {
final Transaction transaction = tx.getTransaction();
@@ -131,7 +131,7 @@ public class TransactionCompleteResult implements TransactionResult {
this.v =
(transactionType == TransactionType.ACCESS_LIST
|| transactionType == TransactionType.EIP1559)
|| transactionType == TransactionType.SET_CODE
|| transactionType == TransactionType.DELEGATE_CODE
? Quantity.create(transaction.getYParity())
: null;
}
@@ -139,7 +139,7 @@ public class TransactionCompleteResult implements TransactionResult {
this.r = Quantity.create(transaction.getR());
this.s = Quantity.create(transaction.getS());
this.versionedHashes = transaction.getVersionedHashes().orElse(null);
this.authorizationList = transaction.getAuthorizationList().orElse(null);
this.authorizationList = transaction.getCodeDelegationList().orElse(null);
}
@JsonGetter(value = "accessList")
@@ -255,7 +255,7 @@ public class TransactionCompleteResult implements TransactionResult {
}
@JsonGetter(value = "authorizationList")
public List<SetCodeAuthorization> getAuthorizationList() {
public List<CodeDelegation> getAuthorizationList() {
return authorizationList;
}
}

View File

@@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineE
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV2;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV3;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetBlobsV1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetClientVersionV1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByHashV1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByRangeV1;
@@ -39,6 +40,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineQ
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory;
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import java.util.ArrayList;
@@ -60,6 +62,7 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods {
private final Vertx consensusEngineServer;
private final String clientVersion;
private final String commit;
private final TransactionPool transactionPool;
ExecutionEngineJsonRpcMethods(
final MiningCoordinator miningCoordinator,
@@ -68,7 +71,8 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods {
final EthPeers ethPeers,
final Vertx consensusEngineServer,
final String clientVersion,
final String commit) {
final String commit,
final TransactionPool transactionPool) {
this.mergeCoordinator =
Optional.ofNullable(miningCoordinator)
.filter(mc -> mc.isCompatibleWithEngineApi())
@@ -79,6 +83,7 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods {
this.consensusEngineServer = consensusEngineServer;
this.clientVersion = clientVersion;
this.commit = commit;
this.transactionPool = transactionPool;
}
@Override
@@ -156,7 +161,9 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods {
new EnginePreparePayloadDebug(
consensusEngineServer, protocolContext, engineQosTimer, mergeCoordinator.get()),
new EngineGetClientVersionV1(
consensusEngineServer, protocolContext, engineQosTimer, clientVersion, commit)));
consensusEngineServer, protocolContext, engineQosTimer, clientVersion, commit),
new EngineGetBlobsV1(
consensusEngineServer, protocolContext, engineQosTimer, transactionPool)));
if (protocolSchedule.anyMatch(p -> p.spec().getName().equalsIgnoreCase("cancun"))) {
executionEngineApisSupported.add(

View File

@@ -119,7 +119,8 @@ public class JsonRpcMethodsFactory {
ethPeers,
consensusEngineServer,
clientVersion,
commit),
commit,
transactionPool),
new EthJsonRpcMethods(
blockchainQueries,
synchronizer,

View File

@@ -16,7 +16,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
@@ -70,7 +69,9 @@ public class EthCreateAccessListTest {
private final String METHOD = "eth_createAccessList";
private EthCreateAccessList method;
@Mock private BlockHeader blockHeader;
@Mock private BlockHeader latestBlockHeader;
@Mock private BlockHeader finalizedBlockHeader;
@Mock private BlockHeader genesisBlockHeader;
@Mock private Blockchain blockchain;
@Mock private BlockchainQueries blockchainQueries;
@Mock private TransactionSimulator transactionSimulator;
@@ -80,16 +81,18 @@ public class EthCreateAccessListTest {
public void setUp() {
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchainQueries.getWorldStateArchive()).thenReturn(worldStateArchive);
when(blockchain.getChainHeadHash())
.thenReturn(
Hash.fromHexString(
"0x3f07a9c83155594c000642e7d60e8a8a00038d03e9849171a05ed0e2d47acbb3"));
when(blockchain.getBlockHeader(
Hash.fromHexString(
"0x3f07a9c83155594c000642e7d60e8a8a00038d03e9849171a05ed0e2d47acbb3")))
.thenReturn(Optional.of(blockHeader));
when(blockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE);
when(blockHeader.getNumber()).thenReturn(1L);
when(blockchainQueries.headBlockNumber()).thenReturn(2L);
when(blockchainQueries.getBlockHeaderByNumber(0L)).thenReturn(Optional.of(genesisBlockHeader));
when(blockchainQueries.finalizedBlockHeader()).thenReturn(Optional.of(finalizedBlockHeader));
when(blockchainQueries.getBlockHeaderByNumber(1L))
.thenReturn(Optional.of(finalizedBlockHeader));
when(genesisBlockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE);
when(genesisBlockHeader.getNumber()).thenReturn(0L);
when(finalizedBlockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE);
when(finalizedBlockHeader.getNumber()).thenReturn(1L);
when(blockchain.getChainHeadHeader()).thenReturn(latestBlockHeader);
when(latestBlockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE);
when(latestBlockHeader.getNumber()).thenReturn(2L);
when(worldStateArchive.isWorldStateAvailable(any(), any())).thenReturn(true);
method = new EthCreateAccessList(blockchainQueries, transactionSimulator);
@@ -105,18 +108,22 @@ public class EthCreateAccessListTest {
new JsonRpcRequest("2.0", METHOD, new Object[] {callParameter}));
}
private JsonRpcRequestContext ethCreateAccessListRequest(
final CallParameter callParameter, final String blockParam) {
return new JsonRpcRequestContext(
new JsonRpcRequest("2.0", METHOD, new Object[] {callParameter, blockParam}));
}
@Test
public void shouldReturnGasEstimateWhenTransientLegacyTransactionProcessorReturnsResultSuccess() {
final JsonRpcRequestContext request =
ethCreateAccessListRequest(legacyTransactionCallParameter(Wei.ZERO));
mockTransactionSimulatorResult(true, false, 1L);
mockTransactionSimulatorResult(true, false, 1L, latestBlockHeader);
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(null, new CreateAccessListResult(new ArrayList<>(), 1L));
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
@@ -124,21 +131,19 @@ public class EthCreateAccessListTest {
final Wei gasPrice = Wei.of(1000);
final JsonRpcRequestContext request =
ethCreateAccessListRequest(legacyTransactionCallParameter(gasPrice));
mockTransactionSimulatorResult(true, false, 1L);
mockTransactionSimulatorResult(true, false, 1L, latestBlockHeader);
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(null, new CreateAccessListResult(new ArrayList<>(), 1L));
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldReturnGasEstimateErrorWhenGasPricePresentForEip1559Transaction() {
final JsonRpcRequestContext request =
ethCreateAccessListRequest(eip1559TransactionCallParameter(Optional.of(Wei.of(10))));
mockTransactionSimulatorResult(false, false, 1L);
mockTransactionSimulatorResult(false, false, 1L, latestBlockHeader);
Assertions.assertThatThrownBy(() -> method.response(request))
.isInstanceOf(InvalidJsonRpcParameters.class)
@@ -150,29 +155,25 @@ public class EthCreateAccessListTest {
when(worldStateArchive.isWorldStateAvailable(any(), any())).thenReturn(false);
final JsonRpcRequestContext request =
ethCreateAccessListRequest(legacyTransactionCallParameter(Wei.ZERO));
mockTransactionSimulatorResult(false, false, 1L);
mockTransactionSimulatorResult(false, false, 1L, latestBlockHeader);
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, RpcErrorType.WORLD_STATE_UNAVAILABLE);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldReturnErrorWhenTransactionReverted() {
final JsonRpcRequestContext request =
ethCreateAccessListRequest(legacyTransactionCallParameter(Wei.ZERO));
mockTransactionSimulatorResult(false, true, 1L);
mockTransactionSimulatorResult(false, true, 1L, latestBlockHeader);
final String errorReason = "0x00";
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, new JsonRpcError(RpcErrorType.REVERT_ERROR, errorReason));
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
@@ -182,12 +183,10 @@ public class EthCreateAccessListTest {
new JsonRpcSuccessResponse(null, new CreateAccessListResult(expectedAccessList, 1L));
final JsonRpcRequestContext request =
ethCreateAccessListRequest(eip1559TransactionCallParameter());
mockTransactionSimulatorResult(true, false, 1L);
mockTransactionSimulatorResult(true, false, 1L, latestBlockHeader);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
verify(transactionSimulator, times(1)).process(any(), any(), any(), anyLong());
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
verify(transactionSimulator, times(1)).process(any(), any(), any(), eq(latestBlockHeader));
}
@Test
@@ -204,11 +203,11 @@ public class EthCreateAccessListTest {
final AccessListOperationTracer tracer = createMockTracer(expectedAccessList);
// Set TransactionSimulator.process response
mockTransactionSimulatorResult(true, false, 1L);
Assertions.assertThat(responseWithMockTracer(request, tracer))
mockTransactionSimulatorResult(true, false, 1L, latestBlockHeader);
assertThat(responseWithMockTracer(request, tracer))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
verify(transactionSimulator, times(2)).process(any(), any(), any(), anyLong());
verify(transactionSimulator, times(2)).process(any(), any(), any(), eq(latestBlockHeader));
}
@Test
@@ -223,11 +222,9 @@ public class EthCreateAccessListTest {
ethCreateAccessListRequest(eip1559TransactionCallParameter(accessListParam));
// Set TransactionSimulator.process response
mockTransactionSimulatorResult(true, false, 1L);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
verify(transactionSimulator, times(1)).process(any(), any(), any(), anyLong());
mockTransactionSimulatorResult(true, false, 1L, latestBlockHeader);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
verify(transactionSimulator, times(1)).process(any(), any(), any(), eq(latestBlockHeader));
}
@Test
@@ -244,11 +241,11 @@ public class EthCreateAccessListTest {
final AccessListOperationTracer tracer = createMockTracer(expectedAccessList);
// Set TransactionSimulator.process response
mockTransactionSimulatorResult(true, false, 1L);
Assertions.assertThat(responseWithMockTracer(request, tracer))
mockTransactionSimulatorResult(true, false, 1L, latestBlockHeader);
assertThat(responseWithMockTracer(request, tracer))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
verify(transactionSimulator, times(1)).process(any(), any(), any(), anyLong());
verify(transactionSimulator, times(1)).process(any(), any(), any(), eq(latestBlockHeader));
}
@Test
@@ -268,11 +265,51 @@ public class EthCreateAccessListTest {
final AccessListOperationTracer tracer = createMockTracer(expectedAccessList);
// Set TransactionSimulator.process response
mockTransactionSimulatorResult(true, false, 1L);
Assertions.assertThat(responseWithMockTracer(request, tracer))
mockTransactionSimulatorResult(true, false, 1L, latestBlockHeader);
assertThat(responseWithMockTracer(request, tracer))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
verify(transactionSimulator, times(2)).process(any(), any(), any(), anyLong());
verify(transactionSimulator, times(2)).process(any(), any(), any(), eq(latestBlockHeader));
}
@Test
public void shouldReturnAccessListWhenBlockTagParamIsPresent() {
final JsonRpcRequestContext request =
ethCreateAccessListRequest(eip1559TransactionCallParameter(), "finalized");
// Create a list with one access list entry
final List<AccessListEntry> expectedAccessList = createAccessList();
// expect a list with the mocked access list
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(null, new CreateAccessListResult(expectedAccessList, 1L));
final AccessListOperationTracer tracer = createMockTracer(expectedAccessList);
// Set TransactionSimulator.process response
mockTransactionSimulatorResult(true, false, 1L, finalizedBlockHeader);
assertThat(responseWithMockTracer(request, tracer))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
verify(transactionSimulator, times(2)).process(any(), any(), any(), eq(finalizedBlockHeader));
}
@Test
public void shouldReturnAccessListWhenBlockNumberParamIsPresent() {
final JsonRpcRequestContext request =
ethCreateAccessListRequest(eip1559TransactionCallParameter(), "0x0");
// Create a list with one access list entry
final List<AccessListEntry> expectedAccessList = createAccessList();
// expect a list with the mocked access list
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(null, new CreateAccessListResult(expectedAccessList, 1L));
final AccessListOperationTracer tracer = createMockTracer(expectedAccessList);
// Set TransactionSimulator.process response
mockTransactionSimulatorResult(true, false, 1L, genesisBlockHeader);
assertThat(responseWithMockTracer(request, tracer))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
verify(transactionSimulator, times(2)).process(any(), any(), any(), eq(genesisBlockHeader));
}
private JsonRpcResponse responseWithMockTracer(
@@ -292,9 +329,12 @@ public class EthCreateAccessListTest {
}
private void mockTransactionSimulatorResult(
final boolean isSuccessful, final boolean isReverted, final long estimateGas) {
final boolean isSuccessful,
final boolean isReverted,
final long estimateGas,
final BlockHeader blockHeader) {
final TransactionSimulatorResult mockTxSimResult = mock(TransactionSimulatorResult.class);
when(transactionSimulator.process(any(), any(), any(), anyLong()))
when(transactionSimulator.process(any(), any(), any(), eq(blockHeader)))
.thenReturn(Optional.of(mockTxSimResult));
final TransactionProcessingResult mockResult = mock(TransactionProcessingResult.class);
when(mockResult.getEstimateGasUsedByTransaction()).thenReturn(estimateGas);

View File

@@ -22,7 +22,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
@@ -66,7 +65,9 @@ public class EthEstimateGasTest {
private EthEstimateGas method;
@Mock private BlockHeader blockHeader;
@Mock private BlockHeader latestBlockHeader;
@Mock private BlockHeader finalizedBlockHeader;
@Mock private BlockHeader genesisBlockHeader;
@Mock private Blockchain blockchain;
@Mock private BlockchainQueries blockchainQueries;
@Mock private TransactionSimulator transactionSimulator;
@@ -76,16 +77,18 @@ public class EthEstimateGasTest {
public void setUp() {
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchainQueries.getWorldStateArchive()).thenReturn(worldStateArchive);
when(blockchain.getChainHeadHash())
.thenReturn(
Hash.fromHexString(
"0x3f07a9c83155594c000642e7d60e8a8a00038d03e9849171a05ed0e2d47acbb3"));
when(blockchain.getBlockHeader(
Hash.fromHexString(
"0x3f07a9c83155594c000642e7d60e8a8a00038d03e9849171a05ed0e2d47acbb3")))
.thenReturn(Optional.of(blockHeader));
when(blockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE);
when(blockHeader.getNumber()).thenReturn(1L);
when(blockchainQueries.headBlockNumber()).thenReturn(2L);
when(blockchainQueries.getBlockHeaderByNumber(0L)).thenReturn(Optional.of(genesisBlockHeader));
when(blockchainQueries.finalizedBlockHeader()).thenReturn(Optional.of(finalizedBlockHeader));
when(blockchainQueries.getBlockHeaderByNumber(1L))
.thenReturn(Optional.of(finalizedBlockHeader));
when(genesisBlockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE);
when(genesisBlockHeader.getNumber()).thenReturn(0L);
when(finalizedBlockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE);
when(finalizedBlockHeader.getNumber()).thenReturn(1L);
when(blockchain.getChainHeadHeader()).thenReturn(latestBlockHeader);
when(latestBlockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE);
when(latestBlockHeader.getNumber()).thenReturn(2L);
when(worldStateArchive.isWorldStateAvailable(any(), any())).thenReturn(true);
method = new EthEstimateGas(blockchainQueries, transactionSimulator);
@@ -104,15 +107,13 @@ public class EthEstimateGasTest {
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)),
any(TransactionValidationParams.class),
any(OperationTracer.class),
eq(1L)))
eq(latestBlockHeader)))
.thenReturn(Optional.empty());
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, RpcErrorType.INTERNAL_ERROR);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
@@ -122,28 +123,24 @@ public class EthEstimateGasTest {
eq(modifiedEip1559TransactionCallParameter()),
any(TransactionValidationParams.class),
any(OperationTracer.class),
eq(1L)))
eq(latestBlockHeader)))
.thenReturn(Optional.empty());
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, RpcErrorType.INTERNAL_ERROR);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldReturnGasEstimateWhenTransientLegacyTransactionProcessorReturnsResultSuccess() {
final JsonRpcRequestContext request =
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
mockTransientProcessorResultGasEstimate(1L, true, false);
mockTransientProcessorResultGasEstimate(1L, true, false, latestBlockHeader);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, Quantity.create(1L));
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
@@ -151,20 +148,19 @@ public class EthEstimateGasTest {
final Wei gasPrice = Wei.of(1000);
final JsonRpcRequestContext request =
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(gasPrice));
mockTransientProcessorResultGasEstimate(1L, true, gasPrice, Optional.empty());
mockTransientProcessorResultGasEstimate(
1L, true, gasPrice, Optional.empty(), latestBlockHeader);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, Quantity.create(1L));
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldReturnGasEstimateErrorWhenGasPricePresentForEip1559Transaction() {
final JsonRpcRequestContext request =
ethEstimateGasRequest(eip1559TransactionCallParameter(Optional.of(Wei.of(10))));
mockTransientProcessorResultGasEstimate(1L, false, false);
mockTransientProcessorResultGasEstimate(1L, false, false, latestBlockHeader);
Assertions.assertThatThrownBy(() -> method.response(request))
.isInstanceOf(InvalidJsonRpcParameters.class)
.hasMessageContaining("gasPrice cannot be used with maxFeePerGas or maxPriorityFeePerGas");
@@ -174,12 +170,10 @@ public class EthEstimateGasTest {
public void
shouldReturnGasEstimateWhenTransientEip1559TransactionProcessorReturnsResultSuccess() {
final JsonRpcRequestContext request = ethEstimateGasRequest(eip1559TransactionCallParameter());
mockTransientProcessorResultGasEstimate(1L, true, false);
mockTransientProcessorResultGasEstimate(1L, true, false, latestBlockHeader);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, Quantity.create(1L));
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
@@ -187,28 +181,24 @@ public class EthEstimateGasTest {
shouldReturnGasEstimateErrorWhenTransientLegacyTransactionProcessorReturnsResultFailure() {
final JsonRpcRequestContext request =
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
mockTransientProcessorResultGasEstimate(1L, false, false);
mockTransientProcessorResultGasEstimate(1L, false, false, latestBlockHeader);
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, RpcErrorType.INTERNAL_ERROR);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void
shouldReturnGasEstimateErrorWhenTransientEip1559TransactionProcessorReturnsResultFailure() {
final JsonRpcRequestContext request = ethEstimateGasRequest(eip1559TransactionCallParameter());
mockTransientProcessorResultGasEstimate(1L, false, false);
mockTransientProcessorResultGasEstimate(1L, false, false, latestBlockHeader);
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, RpcErrorType.INTERNAL_ERROR);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
@@ -217,7 +207,8 @@ public class EthEstimateGasTest {
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
mockTransientProcessorResultTxInvalidReason(
TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE,
"transaction up-front cost 10 exceeds transaction sender account balance 5");
"transaction up-front cost 10 exceeds transaction sender account balance 5",
latestBlockHeader);
final ValidationResult<TransactionInvalidReason> validationResult =
ValidationResult.invalid(
@@ -226,9 +217,7 @@ public class EthEstimateGasTest {
final JsonRpcError rpcError = JsonRpcError.from(validationResult);
final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse(null, rpcError);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
@@ -236,7 +225,8 @@ public class EthEstimateGasTest {
final JsonRpcRequestContext request = ethEstimateGasRequest(eip1559TransactionCallParameter());
mockTransientProcessorResultTxInvalidReason(
TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE,
"transaction up-front cost 10 exceeds transaction sender account balance 5");
"transaction up-front cost 10 exceeds transaction sender account balance 5",
latestBlockHeader);
final ValidationResult<TransactionInvalidReason> validationResult =
ValidationResult.invalid(
TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE,
@@ -244,9 +234,7 @@ public class EthEstimateGasTest {
final JsonRpcError rpcError = JsonRpcError.from(validationResult);
final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse(null, rpcError);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
@@ -254,21 +242,21 @@ public class EthEstimateGasTest {
when(worldStateArchive.isWorldStateAvailable(any(), any())).thenReturn(false);
final JsonRpcRequestContext request =
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
mockTransientProcessorResultGasEstimate(1L, false, false);
mockTransientProcessorResultGasEstimate(1L, false, false, latestBlockHeader);
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, RpcErrorType.WORLD_STATE_UNAVAILABLE);
JsonRpcResponse theResponse = method.response(request);
Assertions.assertThat(theResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
assertThat(theResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldReturnErrorWhenTransactionReverted() {
final JsonRpcRequestContext request =
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
mockTransientProcessorResultGasEstimate(1L, false, true);
mockTransientProcessorResultGasEstimate(1L, false, true, latestBlockHeader);
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, new JsonRpcError(RpcErrorType.REVERT_ERROR, "0x00"));
@@ -278,7 +266,7 @@ public class EthEstimateGasTest {
final JsonRpcResponse actualResponse = method.response(request);
Assertions.assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
assertThat(((JsonRpcErrorResponse) actualResponse).getError().getMessage())
.isEqualTo("Execution reverted");
@@ -296,7 +284,8 @@ public class EthEstimateGasTest {
+ "00002545524332303a207472616e736665722066726f6d20746865207a65726f20"
+ "61646472657373000000000000000000000000000000000000000000000000000000";
mockTransientProcessorTxReverted(1L, false, Bytes.fromHexString(executionRevertedReason));
mockTransientProcessorTxReverted(
1L, false, Bytes.fromHexString(executionRevertedReason), latestBlockHeader);
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(
@@ -307,7 +296,7 @@ public class EthEstimateGasTest {
final JsonRpcResponse actualResponse = method.response(request);
Assertions.assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
assertThat(((JsonRpcErrorResponse) actualResponse).getError().getMessage())
.isEqualTo("Execution reverted: ERC20: transfer from the zero address");
@@ -323,7 +312,8 @@ public class EthEstimateGasTest {
"0x08c379a000000000000000000000000000000000000000000000000000000000"
+ "123451234512345123451234512345123451234512345123451234512345123451";
mockTransientProcessorTxReverted(1L, false, Bytes.fromHexString(invalidRevertReason));
mockTransientProcessorTxReverted(
1L, false, Bytes.fromHexString(invalidRevertReason), latestBlockHeader);
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(
@@ -334,7 +324,7 @@ public class EthEstimateGasTest {
final JsonRpcResponse actualResponse = method.response(request);
Assertions.assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
assertThat(((JsonRpcErrorResponse) actualResponse).getError().getMessage())
.isEqualTo("Execution reverted: ABI decode error");
@@ -344,7 +334,7 @@ public class EthEstimateGasTest {
public void shouldIgnoreSenderBalanceAccountWhenStrictModeDisabled() {
final JsonRpcRequestContext request =
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
mockTransientProcessorResultGasEstimate(1L, false, true);
mockTransientProcessorResultGasEstimate(1L, false, true, latestBlockHeader);
method.response(request);
@@ -357,14 +347,14 @@ public class EthEstimateGasTest {
.isAllowExceedingBalance(true)
.build()),
any(OperationTracer.class),
eq(1L));
eq(latestBlockHeader));
}
@Test
public void shouldNotIgnoreSenderBalanceAccountWhenStrictModeEnabled() {
final JsonRpcRequestContext request =
ethEstimateGasRequest(legacyTransactionCallParameter(Wei.ZERO, true));
mockTransientProcessorResultGasEstimate(1L, false, true);
mockTransientProcessorResultGasEstimate(1L, false, true, latestBlockHeader);
method.response(request);
@@ -377,7 +367,7 @@ public class EthEstimateGasTest {
.isAllowExceedingBalance(false)
.build()),
any(OperationTracer.class),
eq(1L));
eq(latestBlockHeader));
}
@Test
@@ -385,22 +375,44 @@ public class EthEstimateGasTest {
final JsonRpcRequestContext request =
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
mockTransientProcessorResultTxInvalidReason(
TransactionInvalidReason.EXECUTION_HALTED, "INVALID_OPERATION");
TransactionInvalidReason.EXECUTION_HALTED, "INVALID_OPERATION", latestBlockHeader);
final ValidationResult<TransactionInvalidReason> validationResult =
ValidationResult.invalid(TransactionInvalidReason.EXECUTION_HALTED, "INVALID_OPERATION");
final JsonRpcError rpcError = JsonRpcError.from(validationResult);
final JsonRpcResponse expectedResponse = new JsonRpcErrorResponse(null, rpcError);
Assertions.assertThat(method.response(request))
.usingRecursiveComparison()
.isEqualTo(expectedResponse);
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldUseBlockTagParamWhenPresent() {
final JsonRpcRequestContext request =
ethEstimateGasRequest(eip1559TransactionCallParameter(), "finalized");
mockTransientProcessorResultGasEstimate(1L, true, false, finalizedBlockHeader);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, Quantity.create(1L));
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void shouldUseBlockNumberParamWhenPresent() {
final JsonRpcRequestContext request =
ethEstimateGasRequest(eip1559TransactionCallParameter(), "0x0");
mockTransientProcessorResultGasEstimate(1L, true, false, genesisBlockHeader);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, Quantity.create(1L));
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
}
private void mockTransientProcessorResultTxInvalidReason(
final TransactionInvalidReason reason, final String validationFailedErrorMessage) {
final TransactionInvalidReason reason,
final String validationFailedErrorMessage,
final BlockHeader blockHeader) {
final TransactionSimulatorResult mockTxSimResult =
getMockTransactionSimulatorResult(false, 0, Wei.ZERO, Optional.empty());
getMockTransactionSimulatorResult(false, 0, Wei.ZERO, Optional.empty(), blockHeader);
when(mockTxSimResult.getValidationResult())
.thenReturn(
validationFailedErrorMessage == null
@@ -409,45 +421,55 @@ public class EthEstimateGasTest {
}
private void mockTransientProcessorTxReverted(
final long estimateGas, final boolean isSuccessful, final Bytes revertReason) {
final long estimateGas,
final boolean isSuccessful,
final Bytes revertReason,
final BlockHeader blockHeader) {
mockTransientProcessorResultGasEstimate(
estimateGas, isSuccessful, Wei.ZERO, Optional.of(revertReason));
estimateGas, isSuccessful, Wei.ZERO, Optional.of(revertReason), blockHeader);
}
private void mockTransientProcessorResultGasEstimate(
final long estimateGas, final boolean isSuccessful, final boolean isReverted) {
final long estimateGas,
final boolean isSuccessful,
final boolean isReverted,
final BlockHeader blockHeader) {
mockTransientProcessorResultGasEstimate(
estimateGas,
isSuccessful,
Wei.ZERO,
isReverted ? Optional.of(Bytes.of(0)) : Optional.empty());
isReverted ? Optional.of(Bytes.of(0)) : Optional.empty(),
blockHeader);
}
private void mockTransientProcessorResultGasEstimate(
final long estimateGas,
final boolean isSuccessful,
final Wei gasPrice,
final Optional<Bytes> revertReason) {
getMockTransactionSimulatorResult(isSuccessful, estimateGas, gasPrice, revertReason);
final Optional<Bytes> revertReason,
final BlockHeader blockHeader) {
getMockTransactionSimulatorResult(
isSuccessful, estimateGas, gasPrice, revertReason, blockHeader);
}
private TransactionSimulatorResult getMockTransactionSimulatorResult(
final boolean isSuccessful,
final long estimateGas,
final Wei gasPrice,
final Optional<Bytes> revertReason) {
final Optional<Bytes> revertReason,
final BlockHeader blockHeader) {
final TransactionSimulatorResult mockTxSimResult = mock(TransactionSimulatorResult.class);
when(transactionSimulator.process(
eq(modifiedLegacyTransactionCallParameter(gasPrice)),
any(TransactionValidationParams.class),
any(OperationTracer.class),
eq(1L)))
eq(blockHeader)))
.thenReturn(Optional.of(mockTxSimResult));
when(transactionSimulator.process(
eq(modifiedEip1559TransactionCallParameter()),
any(TransactionValidationParams.class),
any(OperationTracer.class),
eq(1L)))
eq(blockHeader)))
.thenReturn(Optional.of(mockTxSimResult));
final TransactionProcessingResult mockResult = mock(TransactionProcessingResult.class);
@@ -523,4 +545,10 @@ public class EthEstimateGasTest {
return new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "eth_estimateGas", new Object[] {callParameter}));
}
private JsonRpcRequestContext ethEstimateGasRequest(
final CallParameter callParameter, final String blockParam) {
return new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "eth_estimateGas", new Object[] {callParameter, blockParam}));
}
}

View File

@@ -0,0 +1,267 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.internal.methods.engine;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SECPPrivateKey;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.ProtocolContext;
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.JsonRpcRequestContext;
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.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlobAndProofV1;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlobTestFixture;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.plugin.services.rpc.RpcResponseType;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
import io.vertx.core.Vertx;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class EngineGetBlobsV1Test {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
private static final SECPPrivateKey PRIVATE_KEY1 =
SIGNATURE_ALGORITHM
.get()
.createPrivateKey(
Bytes32.fromHexString(
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63"));
private static final KeyPair KEYS1 =
new KeyPair(PRIVATE_KEY1, SIGNATURE_ALGORITHM.get().createPublicKey(PRIVATE_KEY1));
public static final VersionedHash VERSIONED_HASH_ZERO = new VersionedHash((byte) 1, Hash.ZERO);
@Mock private ProtocolContext protocolContext;
@Mock private EngineCallListener engineCallListener;
@Mock private MutableBlockchain blockchain;
@Mock private TransactionPool transactionPool;
private EngineGetBlobsV1 method;
private static final Vertx vertx = Vertx.vertx();
@BeforeEach
public void before() {
when(protocolContext.getBlockchain()).thenReturn(blockchain);
this.method =
spy(new EngineGetBlobsV1(vertx, protocolContext, engineCallListener, transactionPool));
}
@Test
public void shouldReturnExpectedMethodName() {
assertThat(method.getName()).isEqualTo("engine_getBlobsV1");
}
@Test
public void shouldReturnBlobsAndProofsForKnownVersionedHashesFromMap() {
final Transaction blobTransaction = createBlobTransaction();
final BlobsWithCommitments blobsWithCommitments =
blobTransaction.getBlobsWithCommitments().get();
mockTransactionPoolMethod(blobsWithCommitments);
VersionedHash[] versionedHashes =
blobsWithCommitments.getVersionedHashes().toArray(new VersionedHash[0]);
final JsonRpcResponse jsonRpcResponse = resp(versionedHashes);
final List<BlobAndProofV1> blobAndProofV1s = fromSuccessResp(jsonRpcResponse);
assertThat(blobAndProofV1s.size()).isEqualTo(versionedHashes.length);
// for loop to check each blob and proof
for (int i = 0; i < versionedHashes.length; i++) {
assertThat(Bytes.fromHexString(blobAndProofV1s.get(i).getBlob()))
.isEqualTo(blobsWithCommitments.getBlobQuads().get(i).blob().getData());
assertThat(Bytes.fromHexString(blobAndProofV1s.get(i).getProof()))
.isEqualTo(blobsWithCommitments.getBlobQuads().get(i).kzgProof().getData());
}
}
@Test
public void shouldReturnNullForBlobsAndProofsForUnknownVersionedHashes() {
final Transaction blobTransaction = createBlobTransaction();
final BlobsWithCommitments blobsWithCommitments =
blobTransaction.getBlobsWithCommitments().get();
mockTransactionPoolMethod(blobsWithCommitments);
List<VersionedHash> versionedHashesList =
blobsWithCommitments.getVersionedHashes().stream().toList();
final VersionedHash[] hashes = versionedHashesList.toArray(new VersionedHash[0]);
hashes[1] = VERSIONED_HASH_ZERO;
final JsonRpcResponse jsonRpcResponse = resp(hashes);
final List<BlobAndProofV1> blobAndProofV1s = fromSuccessResp(jsonRpcResponse);
assertThat(blobAndProofV1s.size()).isEqualTo(versionedHashesList.size());
// for loop to check each blob and proof
for (int i = 0; i < versionedHashesList.size(); i++) {
if (i != 1) {
assertThat(Bytes.fromHexString(blobAndProofV1s.get(i).getBlob()))
.isEqualTo(blobsWithCommitments.getBlobQuads().get(i).blob().getData());
assertThat(Bytes.fromHexString(blobAndProofV1s.get(i).getProof()))
.isEqualTo(blobsWithCommitments.getBlobQuads().get(i).kzgProof().getData());
} else {
assertThat(blobAndProofV1s.get(i)).isNull();
}
}
}
@Test
public void shouldReturnOnlyNullsForBlobsAndProofsIfAllVersionedHashesUnknown() {
final Transaction blobTransaction = createBlobTransaction();
final BlobsWithCommitments blobsWithCommitments =
blobTransaction.getBlobsWithCommitments().get();
mockTransactionPoolMethod(blobsWithCommitments);
List<VersionedHash> versionedHashesList =
blobsWithCommitments.getVersionedHashes().stream().toList();
final VersionedHash[] versionedHashes = new VersionedHash[6];
Arrays.fill(versionedHashes, VERSIONED_HASH_ZERO);
final JsonRpcResponse jsonRpcResponse = resp(versionedHashes);
final List<BlobAndProofV1> blobAndProofV1s = fromSuccessResp(jsonRpcResponse);
assertThat(blobAndProofV1s.size()).isEqualTo(versionedHashesList.size());
// for loop to check each blob and proof
for (int i = 0; i < versionedHashes.length; i++) {
assertThat(blobAndProofV1s.get(i)).isNull();
}
}
@Test
public void shouldReturnEmptyResponseForEmptyRequest() {
final VersionedHash[] versionedHashes = new VersionedHash[0];
final JsonRpcResponse jsonRpcResponse = resp(versionedHashes);
assertThat(fromSuccessResp(jsonRpcResponse).size()).isEqualTo(0);
}
@Test
public void shouldFailWhenRequestingMoreThan128() {
final VersionedHash[] versionedHashes = new VersionedHash[129];
for (int i = 0; i < 129; i++) {
versionedHashes[i] = new VersionedHash((byte) 1, Hash.ZERO);
}
final JsonRpcResponse jsonRpcResponse = resp(versionedHashes);
assertThat(fromErrorResp(jsonRpcResponse).getCode())
.isEqualTo(RpcErrorType.INVALID_ENGINE_GET_BLOBS_V1_TOO_LARGE_REQUEST.getCode());
assertThat(fromErrorResp(jsonRpcResponse).getMessage())
.isEqualTo(RpcErrorType.INVALID_ENGINE_GET_BLOBS_V1_TOO_LARGE_REQUEST.getMessage());
}
Transaction createBlobTransaction() {
BlobTestFixture blobTestFixture = new BlobTestFixture();
BlobsWithCommitments bwc = blobTestFixture.createBlobsWithCommitments(6);
TransactionTestFixture ttf = new TransactionTestFixture();
Transaction fullOfBlobs =
ttf.to(Optional.of(Address.ZERO))
.type(TransactionType.BLOB)
.chainId(Optional.of(BigInteger.valueOf(42)))
.gasLimit(21000)
.maxFeePerGas(Optional.of(Wei.of(15)))
.maxFeePerBlobGas(Optional.of(Wei.of(128)))
.maxPriorityFeePerGas(Optional.of(Wei.of(1)))
.versionedHashes(Optional.of(bwc.getVersionedHashes()))
.blobsWithCommitments(Optional.of(bwc))
.createTransaction(KEYS1);
return fullOfBlobs;
}
private void mockTransactionPoolMethod(final BlobsWithCommitments blobsWithCommitments) {
blobsWithCommitments
.getBlobQuads()
.forEach(
blobQuad ->
when(transactionPool.getBlobQuad(blobQuad.versionedHash())).thenReturn(blobQuad));
}
private JsonRpcResponse resp(final VersionedHash[] versionedHashes) {
return method.response(
new JsonRpcRequestContext(
new JsonRpcRequest(
"2.0",
RpcMethod.ENGINE_GET_BLOBS_V1.getMethodName(),
new Object[] {versionedHashes})));
}
@SuppressWarnings({"unchecked", "rawtypes"})
private List<BlobAndProofV1> fromSuccessResp(final JsonRpcResponse resp) {
assertThat(resp.getType()).isEqualTo(RpcResponseType.SUCCESS);
final List list =
Optional.of(resp)
.map(JsonRpcSuccessResponse.class::cast)
.map(JsonRpcSuccessResponse::getResult)
.map(List.class::cast)
.get();
final ArrayList<BlobAndProofV1> blobAndProofV1s = new ArrayList<>();
list.forEach(obj -> blobAndProofV1s.add((BlobAndProofV1) obj));
return blobAndProofV1s;
}
private RpcErrorType fromErrorResp(final JsonRpcResponse resp) {
assertThat(resp.getType()).isEqualTo(RpcResponseType.ERROR);
return Optional.of(resp)
.map(JsonRpcErrorResponse.class::cast)
.map(JsonRpcErrorResponse::getErrorType)
.get();
}
}

View File

@@ -0,0 +1,21 @@
{
"request": {
"id": 3,
"jsonrpc": "2.0",
"method": "eth_estimateGas",
"params": [
{
"to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"from": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"data": "0x123456"
},
"0x1"
]
},
"response": {
"jsonrpc": "2.0",
"id": 3,
"result": "0x52d4"
},
"statusCode": 200
}

View File

@@ -0,0 +1,21 @@
{
"request": {
"id": 3,
"jsonrpc": "2.0",
"method": "eth_estimateGas",
"params": [
{
"to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"from": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"data": "0x123456"
},
"latest"
]
},
"response": {
"jsonrpc": "2.0",
"id": 3,
"result": "0x5238"
},
"statusCode": 200
}

View File

@@ -0,0 +1,21 @@
{
"request": {
"id": 3,
"jsonrpc": "2.0",
"method": "eth_estimateGas",
"params": [
{
"to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"from": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"gas": "0x1"
},
"0xa"
]
},
"response": {
"jsonrpc": "2.0",
"id": 3,
"result": "0x5208"
},
"statusCode": 200
}

View File

@@ -0,0 +1,21 @@
{
"request": {
"id": 3,
"jsonrpc": "2.0",
"method": "eth_estimateGas",
"params": [
{
"from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"to": "0x8888f1f195afa192cfee860698584c030f4c9db1",
"value": "0x1"
},
"earliest"
]
},
"response": {
"jsonrpc": "2.0",
"id": 3,
"result": "0x5208"
},
"statusCode": 200
}

View File

@@ -63,6 +63,7 @@ import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -419,7 +420,8 @@ abstract class AbstractBlockCreatorTest {
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(new NoOpMetricsSystem()),
poolConf);
poolConf,
new BlobCache());
transactionPool.setEnabled();
final MiningParameters miningParameters =

View File

@@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
@@ -94,7 +95,8 @@ public class LegacyFeeMarketBlockTransactionSelectorTest
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(metricsSystem),
poolConf);
poolConf,
new BlobCache());
transactionPool.setEnabled();
return transactionPool;
}

View File

@@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
@@ -101,7 +102,8 @@ public class LondonFeeMarketBlockTransactionSelectorTest
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(metricsSystem),
poolConf);
poolConf,
new BlobCache());
transactionPool.setEnabled();
return transactionPool;
}

View File

@@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyCalculators;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -371,7 +372,8 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest {
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(metricsSystem),
poolConf);
poolConf,
new BlobCache());
transactionPool.setEnabled();
return transactionPool;

View File

@@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionBroadcaster;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -117,7 +118,8 @@ public class PoWMinerExecutorTest {
mock(TransactionBroadcaster.class),
ethContext,
new TransactionPoolMetrics(new NoOpMetricsSystem()),
poolConf);
poolConf,
new BlobCache());
transactionPool.setEnabled();
return transactionPool;

View File

@@ -20,11 +20,10 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.encoding.SetCodeTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationEncoder;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
@@ -33,7 +32,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes;
public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetCodeAuthorization {
public class CodeDelegation implements org.hyperledger.besu.datatypes.CodeDelegation {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
@@ -41,7 +40,7 @@ public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetC
private final BigInteger chainId;
private final Address address;
private final Optional<Long> nonce;
private final long nonce;
private final SECPSignature signature;
private Optional<Address> authorizer = Optional.empty();
private boolean isAuthorityComputed = false;
@@ -51,13 +50,13 @@ public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetC
*
* @param chainId can be either the current chain id or zero
* @param address the address from which the code will be set into the EOA account
* @param nonce an optional nonce after which this auth expires
* @param nonce the nonce after which this auth expires
* @param signature the signature of the EOA account which will be used to set the code
*/
public SetCodeAuthorization(
public CodeDelegation(
final BigInteger chainId,
final Address address,
final Optional<Long> nonce,
final long nonce,
final SECPSignature signature) {
this.chainId = chainId;
this.address = address;
@@ -66,29 +65,26 @@ public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetC
}
/**
* Create access list entry.
* Create code delegation.
*
* @param chainId can be either the current chain id or zero
* @param address the address from which the code will be set into the EOA account
* @param nonces the list of nonces
* @param nonce the nonce
* @param v the recovery id
* @param r the r value of the signature
* @param s the s value of the signature
* @return SetCodeTransactionEntry
* @return CodeDelegation
*/
@JsonCreator
public static org.hyperledger.besu.datatypes.SetCodeAuthorization createSetCodeAuthorizationEntry(
public static org.hyperledger.besu.datatypes.CodeDelegation createCodeDelegation(
@JsonProperty("chainId") final BigInteger chainId,
@JsonProperty("address") final Address address,
@JsonProperty("nonce") final List<Long> nonces,
@JsonProperty("nonce") final long nonce,
@JsonProperty("v") final byte v,
@JsonProperty("r") final BigInteger r,
@JsonProperty("s") final BigInteger s) {
return new SetCodeAuthorization(
chainId,
address,
Optional.ofNullable(nonces.get(0)),
SIGNATURE_ALGORITHM.get().createSignature(r, s, v));
return new CodeDelegation(
chainId, address, nonce, SIGNATURE_ALGORITHM.get().createSignature(r, s, v));
}
@JsonProperty("chainId")
@@ -120,7 +116,7 @@ public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetC
}
@Override
public Optional<Long> nonce() {
public long nonce() {
return nonce;
}
@@ -144,30 +140,38 @@ public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetC
private Optional<Address> computeAuthority() {
BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
SetCodeTransactionEncoder.encodeSingleSetCodeWithoutSignature(this, rlpOutput);
CodeDelegationEncoder.encodeSingleCodeDelegationWithoutSignature(this, rlpOutput);
final Hash hash = Hash.hash(Bytes.concatenate(MAGIC, rlpOutput.encoded()));
return SIGNATURE_ALGORITHM
.get()
.recoverPublicKeyFromSignature(hash, signature)
.map(Address::extract);
Optional<Address> authorityAddress;
try {
authorityAddress =
SIGNATURE_ALGORITHM
.get()
.recoverPublicKeyFromSignature(hash, signature)
.map(Address::extract);
} catch (final IllegalArgumentException e) {
authorityAddress = Optional.empty();
}
return authorityAddress;
}
/**
* Create set code authorization with a builder.
* Create a code delegation authorization with a builder.
*
* @return SetCodeAuthorization.Builder
* @return CodeDelegation.Builder
*/
public static Builder builder() {
return new Builder();
}
/** Builder for SetCodeAuthorization. */
/** Builder for CodeDelegation authorizations. */
public static class Builder {
private BigInteger chainId = BigInteger.ZERO;
private Address address;
private Optional<Long> nonce = Optional.empty();
private Long nonce;
private SECPSignature signature;
/** Create a new builder. */
@@ -196,12 +200,12 @@ public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetC
}
/**
* Set the optional nonce.
* Set the nonce.
*
* @param nonce the optional nonce.
* @param nonce the nonce.
* @return this builder
*/
public Builder nonces(final Optional<Long> nonce) {
public Builder nonce(final long nonce) {
this.nonce = nonce;
return this;
}
@@ -221,16 +225,14 @@ public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetC
* Sign the authorization with the given key pair and return the authorization.
*
* @param keyPair the key pair
* @return SetCodeAuthorization
* @return CodeDelegation
*/
public org.hyperledger.besu.datatypes.SetCodeAuthorization signAndBuild(final KeyPair keyPair) {
public org.hyperledger.besu.datatypes.CodeDelegation signAndBuild(final KeyPair keyPair) {
final BytesValueRLPOutput output = new BytesValueRLPOutput();
output.startList();
output.writeBigIntegerScalar(chainId);
output.writeBytes(address);
output.startList();
nonce.ifPresent(output::writeLongScalar);
output.endList();
output.writeLongScalar(nonce);
output.endList();
signature(
@@ -243,18 +245,22 @@ public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetC
/**
* Build the authorization.
*
* @return SetCodeAuthorization
* @return CodeDelegation
*/
public org.hyperledger.besu.datatypes.SetCodeAuthorization build() {
public org.hyperledger.besu.datatypes.CodeDelegation build() {
if (address == null) {
throw new IllegalStateException("Address must be set");
}
if (nonce == null) {
throw new IllegalStateException("Nonce must be set");
}
if (signature == null) {
throw new IllegalStateException("Signature must be set");
}
return new SetCodeAuthorization(chainId, address, nonce, signature);
return new CodeDelegation(chainId, address, nonce, signature);
}
}
}

View File

@@ -28,18 +28,18 @@ import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Blob;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.KZGCommitment;
import org.hyperledger.besu.datatypes.KZGProof;
import org.hyperledger.besu.datatypes.SetCodeAuthorization;
import org.hyperledger.besu.datatypes.Sha256Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationEncoder;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.SetCodeTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
@@ -124,7 +124,7 @@ public class Transaction
private final Optional<List<VersionedHash>> versionedHashes;
private final Optional<BlobsWithCommitments> blobsWithCommitments;
private final Optional<List<SetCodeAuthorization>> maybeAuthorizationList;
private final Optional<List<CodeDelegation>> maybeCodeDelegationList;
public static Builder builder() {
return new Builder();
@@ -181,7 +181,7 @@ public class Transaction
final Optional<BigInteger> chainId,
final Optional<List<VersionedHash>> versionedHashes,
final Optional<BlobsWithCommitments> blobsWithCommitments,
final Optional<List<SetCodeAuthorization>> maybeAuthorizationList) {
final Optional<List<CodeDelegation>> maybeCodeDelegationList) {
if (!forCopy) {
if (transactionType.requiresChainId()) {
@@ -218,10 +218,10 @@ public class Transaction
maxFeePerBlobGas.isPresent(), "Must specify max fee per blob gas for blob transaction");
}
if (transactionType.requiresSetCode()) {
if (transactionType.requiresCodeDelegation()) {
checkArgument(
maybeAuthorizationList.isPresent(),
"Must specify set code transaction payload for set code transaction");
maybeCodeDelegationList.isPresent(),
"Must specify code delegation authorizations for code delegation transaction");
}
}
@@ -241,7 +241,7 @@ public class Transaction
this.chainId = chainId;
this.versionedHashes = versionedHashes;
this.blobsWithCommitments = blobsWithCommitments;
this.maybeAuthorizationList = maybeAuthorizationList;
this.maybeCodeDelegationList = maybeCodeDelegationList;
}
/**
@@ -473,7 +473,7 @@ public class Transaction
payload,
maybeAccessList,
versionedHashes.orElse(null),
maybeAuthorizationList,
maybeCodeDelegationList,
chainId);
}
return hashNoSignature;
@@ -681,13 +681,13 @@ public class Transaction
}
@Override
public Optional<List<SetCodeAuthorization>> getAuthorizationList() {
return maybeAuthorizationList;
public Optional<List<CodeDelegation>> getCodeDelegationList() {
return maybeCodeDelegationList;
}
@Override
public int authorizationListSize() {
return maybeAuthorizationList.map(List::size).orElse(0);
public int codeDelegationListSize() {
return maybeCodeDelegationList.map(List::size).orElse(0);
}
/**
@@ -714,7 +714,7 @@ public class Transaction
final Bytes payload,
final Optional<List<AccessListEntry>> accessList,
final List<VersionedHash> versionedHashes,
final Optional<List<SetCodeAuthorization>> authorizationList,
final Optional<List<CodeDelegation>> codeDelegationList,
final Optional<BigInteger> chainId) {
if (transactionType.requiresChainId()) {
checkArgument(chainId.isPresent(), "Transaction type %s requires chainId", transactionType);
@@ -759,8 +759,8 @@ public class Transaction
new IllegalStateException(
"Developer error: the transaction should be guaranteed to have an access list here")),
chainId);
case SET_CODE ->
setCodePreimage(
case DELEGATE_CODE ->
codeDelegationPreimage(
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
@@ -770,10 +770,10 @@ public class Transaction
payload,
chainId,
accessList,
authorizationList.orElseThrow(
codeDelegationList.orElseThrow(
() ->
new IllegalStateException(
"Developer error: the transaction should be guaranteed to have a set code payload here")));
"Developer error: the transaction should be guaranteed to have a code delegations here")));
};
return keccak256(preimage);
}
@@ -911,7 +911,7 @@ public class Transaction
return Bytes.concatenate(Bytes.of(TransactionType.ACCESS_LIST.getSerializedType()), encode);
}
private static Bytes setCodePreimage(
private static Bytes codeDelegationPreimage(
final long nonce,
final Wei maxPriorityFeePerGas,
final Wei maxFeePerGas,
@@ -921,7 +921,7 @@ public class Transaction
final Bytes payload,
final Optional<BigInteger> chainId,
final Optional<List<AccessListEntry>> accessList,
final List<SetCodeAuthorization> authorizationList) {
final List<CodeDelegation> authorizationList) {
final Bytes encoded =
RLP.encode(
rlpOutput -> {
@@ -937,10 +937,10 @@ public class Transaction
chainId,
accessList,
rlpOutput);
SetCodeTransactionEncoder.encodeSetCodeInner(authorizationList, rlpOutput);
CodeDelegationEncoder.encodeCodeDelegationInner(authorizationList, rlpOutput);
rlpOutput.endList();
});
return Bytes.concatenate(Bytes.of(TransactionType.SET_CODE.getSerializedType()), encoded);
return Bytes.concatenate(Bytes.of(TransactionType.DELEGATE_CODE.getSerializedType()), encoded);
}
@Override
@@ -1111,7 +1111,7 @@ public class Transaction
chainId,
detachedVersionedHashes,
detachedBlobsWithCommitments,
maybeAuthorizationList);
maybeCodeDelegationList);
// copy also the computed fields, to avoid to recompute them
copiedTx.sender = this.sender;
@@ -1179,7 +1179,7 @@ public class Transaction
protected Optional<BigInteger> v = Optional.empty();
protected List<VersionedHash> versionedHashes = null;
private BlobsWithCommitments blobsWithCommitments;
protected Optional<List<SetCodeAuthorization>> setCodeTransactionPayloads = Optional.empty();
protected Optional<List<CodeDelegation>> codeDelegationAuthorizations = Optional.empty();
public Builder copiedFrom(final Transaction toCopy) {
this.transactionType = toCopy.transactionType;
@@ -1198,7 +1198,7 @@ public class Transaction
this.chainId = toCopy.chainId;
this.versionedHashes = toCopy.versionedHashes.orElse(null);
this.blobsWithCommitments = toCopy.blobsWithCommitments.orElse(null);
this.setCodeTransactionPayloads = toCopy.maybeAuthorizationList;
this.codeDelegationAuthorizations = toCopy.maybeCodeDelegationList;
return this;
}
@@ -1292,8 +1292,8 @@ public class Transaction
transactionType = TransactionType.EIP1559;
} else if (accessList.isPresent()) {
transactionType = TransactionType.ACCESS_LIST;
} else if (setCodeTransactionPayloads.isPresent()) {
transactionType = TransactionType.SET_CODE;
} else if (codeDelegationAuthorizations.isPresent()) {
transactionType = TransactionType.DELEGATE_CODE;
} else {
transactionType = TransactionType.FRONTIER;
}
@@ -1324,7 +1324,7 @@ public class Transaction
chainId,
Optional.ofNullable(versionedHashes),
Optional.ofNullable(blobsWithCommitments),
setCodeTransactionPayloads);
codeDelegationAuthorizations);
}
public Transaction signAndBuild(final KeyPair keys) {
@@ -1351,7 +1351,7 @@ public class Transaction
payload,
accessList,
versionedHashes,
setCodeTransactionPayloads,
codeDelegationAuthorizations,
chainId),
keys);
}
@@ -1376,9 +1376,8 @@ public class Transaction
return this;
}
public Builder setCodeTransactionPayloads(
final List<SetCodeAuthorization> setCodeTransactionEntries) {
this.setCodeTransactionPayloads = Optional.ofNullable(setCodeTransactionEntries);
public Builder codeDelegations(final List<CodeDelegation> codeDelegations) {
this.codeDelegationAuthorizations = Optional.ofNullable(codeDelegations);
return this;
}
}

View File

@@ -17,7 +17,7 @@ package org.hyperledger.besu.ethereum.core.encoding;
import static org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder.writeAccessList;
import static org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignatureAndRecoveryId;
import org.hyperledger.besu.datatypes.SetCodeAuthorization;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
@@ -25,28 +25,28 @@ import java.util.List;
import org.apache.tuweni.bytes.Bytes;
public class SetCodeTransactionEncoder {
public class CodeDelegationEncoder {
private SetCodeTransactionEncoder() {
private CodeDelegationEncoder() {
// private constructor
}
public static void encodeSetCodeInner(
final List<SetCodeAuthorization> payloads, final RLPOutput rlpOutput) {
public static void encodeCodeDelegationInner(
final List<CodeDelegation> payloads, final RLPOutput rlpOutput) {
rlpOutput.startList();
payloads.forEach(payload -> encodeSingleSetCode(payload, rlpOutput));
payloads.forEach(payload -> encodeSingleCodeDelegation(payload, rlpOutput));
rlpOutput.endList();
}
public static void encodeSingleSetCodeWithoutSignature(
final SetCodeAuthorization payload, final RLPOutput rlpOutput) {
public static void encodeSingleCodeDelegationWithoutSignature(
final CodeDelegation payload, final RLPOutput rlpOutput) {
rlpOutput.startList();
encodeAuthorizationDetails(payload, rlpOutput);
rlpOutput.endList();
}
public static void encodeSingleSetCode(
final SetCodeAuthorization payload, final RLPOutput rlpOutput) {
public static void encodeSingleCodeDelegation(
final CodeDelegation payload, final RLPOutput rlpOutput) {
rlpOutput.startList();
encodeAuthorizationDetails(payload, rlpOutput);
rlpOutput.writeIntScalar(payload.signature().getRecId());
@@ -56,12 +56,10 @@ public class SetCodeTransactionEncoder {
}
private static void encodeAuthorizationDetails(
final SetCodeAuthorization payload, final RLPOutput rlpOutput) {
final CodeDelegation payload, final RLPOutput rlpOutput) {
rlpOutput.writeBigIntegerScalar(payload.chainId());
rlpOutput.writeBytes(payload.address().copy());
rlpOutput.startList();
payload.nonce().ifPresent(rlpOutput::writeLongScalar);
rlpOutput.endList();
rlpOutput.writeLongScalar(payload.nonce());
}
public static void encode(final Transaction transaction, final RLPOutput out) {
@@ -75,13 +73,13 @@ public class SetCodeTransactionEncoder {
out.writeUInt256Scalar(transaction.getValue());
out.writeBytes(transaction.getPayload());
writeAccessList(out, transaction.getAccessList());
encodeSetCodeInner(
encodeCodeDelegationInner(
transaction
.getAuthorizationList()
.getCodeDelegationList()
.orElseThrow(
() ->
new IllegalStateException(
"Developer error: the transaction should be guaranteed to have a set code payload here")),
"Developer error: the transaction should be guaranteed to have a code delegation authorizations here")),
out);
writeSignatureAndRecoveryId(transaction, out);
out.endList();

View File

@@ -19,23 +19,22 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.SetCodeAuthorization;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.math.BigInteger;
import java.util.Optional;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
public class SetCodeTransactionDecoder {
public class CodeDelegationTransactionDecoder {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
private SetCodeTransactionDecoder() {
private CodeDelegationTransactionDecoder() {
// private constructor
}
@@ -44,7 +43,7 @@ public class SetCodeTransactionDecoder {
final BigInteger chainId = input.readBigIntegerScalar();
final Transaction.Builder builder =
Transaction.builder()
.type(TransactionType.SET_CODE)
.type(TransactionType.DELEGATE_CODE)
.chainId(chainId)
.nonce(input.readLongScalar())
.maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar()))
@@ -64,10 +63,7 @@ public class SetCodeTransactionDecoder {
accessListEntryRLPInput.leaveList();
return accessListEntry;
}))
.setCodeTransactionPayloads(
input.readList(
setCodeTransactionPayloadsRLPInput ->
decodeInnerPayload(setCodeTransactionPayloadsRLPInput)));
.codeDelegations(input.readList(CodeDelegationTransactionDecoder::decodeInnerPayload));
final byte recId = (byte) input.readUnsignedByteScalar();
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger();
@@ -75,33 +71,15 @@ public class SetCodeTransactionDecoder {
input.leaveList();
final Transaction transaction =
builder.signature(SIGNATURE_ALGORITHM.get().createSignature(r, s, recId)).build();
return transaction;
return builder.signature(SIGNATURE_ALGORITHM.get().createSignature(r, s, recId)).build();
}
public static org.hyperledger.besu.datatypes.SetCodeAuthorization decodeInnerPayload(
final RLPInput input) {
public static CodeDelegation decodeInnerPayload(final RLPInput input) {
input.enterList();
final BigInteger chainId = input.readBigIntegerScalar();
final Address address = Address.wrap(input.readBytes());
Optional<Long> nonce = Optional.empty();
if (!input.nextIsList()) {
throw new IllegalArgumentException("Optional nonce must be an list, but isn't");
}
final long noncesSize = input.nextSize();
input.enterList();
if (noncesSize == 1) {
nonce = Optional.ofNullable(input.readLongScalar());
} else if (noncesSize > 1) {
throw new IllegalArgumentException("Nonce list may only have 1 member, if any");
}
input.leaveList();
final long nonce = input.readLongScalar();
final byte yParity = (byte) input.readUnsignedByteScalar();
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger();
@@ -111,6 +89,7 @@ public class SetCodeTransactionDecoder {
final SECPSignature signature = SIGNATURE_ALGORITHM.get().createSignature(r, s, yParity);
return new SetCodeAuthorization(chainId, address, nonce, signature);
return new org.hyperledger.besu.ethereum.core.CodeDelegation(
chainId, address, nonce, signature);
}
}

View File

@@ -41,8 +41,8 @@ public class TransactionDecoder {
EIP1559TransactionDecoder::decode,
TransactionType.BLOB,
BlobTransactionDecoder::decode,
TransactionType.SET_CODE,
SetCodeTransactionDecoder::decode);
TransactionType.DELEGATE_CODE,
CodeDelegationTransactionDecoder::decode);
private static final ImmutableMap<TransactionType, Decoder> POOLED_TRANSACTION_DECODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionDecoder::decode);

View File

@@ -40,8 +40,8 @@ public class TransactionEncoder {
EIP1559TransactionEncoder::encode,
TransactionType.BLOB,
BlobTransactionEncoder::encode,
TransactionType.SET_CODE,
SetCodeTransactionEncoder::encode);
TransactionType.DELEGATE_CODE,
CodeDelegationEncoder::encode);
private static final ImmutableMap<TransactionType, Encoder> POOLED_TRANSACTION_ENCODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode);

View File

@@ -1,88 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.Transaction;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.AccountState;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.EVMWorldUpdater;
import java.math.BigInteger;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AuthorityProcessor {
private static final Logger LOG = LoggerFactory.getLogger(AuthorityProcessor.class);
private final Optional<BigInteger> maybeChainId;
public AuthorityProcessor(final Optional<BigInteger> maybeChainId) {
this.maybeChainId = maybeChainId;
}
public void addContractToAuthority(
final EVMWorldUpdater evmWorldUpdater, final Transaction transaction) {
transaction
.getAuthorizationList()
.get()
.forEach(
payload ->
payload
.authorizer()
.ifPresent(
authorityAddress -> {
LOG.trace("Set code authority: {}", authorityAddress);
if (maybeChainId.isPresent()
&& !payload.chainId().equals(BigInteger.ZERO)
&& !maybeChainId.get().equals(payload.chainId())) {
return;
}
final Optional<MutableAccount> maybeAccount =
Optional.ofNullable(evmWorldUpdater.getAccount(authorityAddress));
final long accountNonce =
maybeAccount.map(AccountState::getNonce).orElse(0L);
if (payload.nonce().isPresent()
&& !payload.nonce().get().equals(accountNonce)) {
return;
}
if (evmWorldUpdater
.authorizedCodeService()
.hasAuthorizedCode(authorityAddress)) {
return;
}
Optional<Account> codeAccount =
Optional.ofNullable(evmWorldUpdater.get(payload.address()));
final Bytes code;
if (codeAccount.isPresent()) {
code = codeAccount.get().getCode();
} else {
code = Bytes.EMPTY;
}
evmWorldUpdater
.authorizedCodeService()
.addAuthorizedCode(authorityAddress, code);
}));
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.datatypes.Address;
import org.hyperledger.besu.ethereum.core.CodeDelegation;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.EVMWorldUpdater;
import java.math.BigInteger;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CodeDelegationProcessor {
private static final Logger LOG = LoggerFactory.getLogger(CodeDelegationProcessor.class);
private final Optional<BigInteger> maybeChainId;
public CodeDelegationProcessor(final Optional<BigInteger> maybeChainId) {
this.maybeChainId = maybeChainId;
}
/**
* At the start of executing the transaction, after incrementing the senders nonce, for each
* authorization we do the following:
*
* <ol>
* <li>Verify the chain id is either 0 or the chain's current ID.
* <li>`authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s]`
* <li>Add `authority` to `accessed_addresses` (as defined in [EIP-2929](./eip-2929.md).)
* <li>Verify the code of `authority` is either empty or already delegated.
* <li>Verify the nonce of `authority` is equal to `nonce`.
* <li>Add `PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST` gas to the global refund counter if
* `authority` exists in the trie.
* <li>Set the code of `authority` to be `0xef0100 || address`. This is a delegation
* designation.
* <li>Increase the nonce of `authority` by one.
* </ol>
*
* @param evmWorldUpdater The world state updater which is aware of code delegation.
* @param transaction The transaction being processed.
* @return The result of the code delegation processing.
*/
public CodeDelegationResult process(
final EVMWorldUpdater evmWorldUpdater, final Transaction transaction) {
final CodeDelegationResult result = new CodeDelegationResult();
transaction
.getCodeDelegationList()
.get()
.forEach(
codeDelegation ->
processAuthorization(
evmWorldUpdater,
(org.hyperledger.besu.ethereum.core.CodeDelegation) codeDelegation,
result));
return result;
}
private void processAuthorization(
final EVMWorldUpdater evmWorldUpdater,
final CodeDelegation codeDelegation,
final CodeDelegationResult result) {
LOG.trace("Processing code delegation: {}", codeDelegation);
if (maybeChainId.isPresent()
&& !codeDelegation.chainId().equals(BigInteger.ZERO)
&& !maybeChainId.get().equals(codeDelegation.chainId())) {
LOG.trace(
"Invalid chain id for code delegation. Expected: {}, Actual: {}",
maybeChainId.get(),
codeDelegation.chainId());
return;
}
final Optional<Address> authorizer = codeDelegation.authorizer();
if (authorizer.isEmpty()) {
LOG.trace("Invalid signature for code delegation");
return;
}
LOG.trace("Set code delegation for authority: {}", authorizer.get());
final Optional<MutableAccount> maybeAuthorityAccount =
Optional.ofNullable(evmWorldUpdater.getAccount(authorizer.get()));
result.addAccessedDelegatorAddress(authorizer.get());
MutableAccount authority;
boolean authorityDoesAlreadyExist = false;
if (maybeAuthorityAccount.isEmpty()) {
authority = evmWorldUpdater.createAccount(authorizer.get());
} else {
authority = maybeAuthorityAccount.get();
if (!evmWorldUpdater.authorizedCodeService().canSetDelegatedCode(authority)) {
return;
}
authorityDoesAlreadyExist = true;
}
if (codeDelegation.nonce() != authority.getNonce()) {
LOG.trace(
"Invalid nonce for code delegation. Expected: {}, Actual: {}",
authority.getNonce(),
codeDelegation.nonce());
return;
}
if (authorityDoesAlreadyExist) {
result.incremenentAlreadyExistingDelegators();
}
evmWorldUpdater.authorizedCodeService().addDelegatedCode(authority, codeDelegation.address());
authority.incrementNonce();
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.collections.trie.BytesTrieSet;
import org.hyperledger.besu.datatypes.Address;
import java.util.Set;
public class CodeDelegationResult {
private final Set<Address> accessedDelegatorAddresses = new BytesTrieSet<>(Address.SIZE);
private long alreadyExistingDelegators = 0L;
public void addAccessedDelegatorAddress(final Address address) {
accessedDelegatorAddresses.add(address);
}
public void incremenentAlreadyExistingDelegators() {
alreadyExistingDelegators += 1;
}
public Set<Address> accessedDelegatorAddresses() {
return accessedDelegatorAddresses;
}
public long alreadyExistingDelegators() {
return alreadyExistingDelegators;
}
}

View File

@@ -650,7 +650,7 @@ public abstract class MainnetProtocolSpecs {
TransactionType.FRONTIER,
TransactionType.ACCESS_LIST,
TransactionType.EIP1559),
evm.getEvmVersion().getMaxInitcodeSize()))
evm.getMaxInitcodeSize()))
.withdrawalsProcessor(new WithdrawalsProcessor())
.withdrawalsValidator(new WithdrawalsValidator.AllowedWithdrawals())
.name("Shanghai");
@@ -715,7 +715,7 @@ public abstract class MainnetProtocolSpecs {
evmConfiguration.evmStackSize(),
feeMarket,
CoinbaseFeePriceCalculator.eip1559(),
new AuthorityProcessor(chainId)))
new CodeDelegationProcessor(chainId)))
// change to check for max blob gas per block for EIP-4844
.transactionValidatorFactoryBuilder(
(evm, gasLimitCalculator, feeMarket) ->
@@ -730,7 +730,7 @@ public abstract class MainnetProtocolSpecs {
TransactionType.ACCESS_LIST,
TransactionType.EIP1559,
TransactionType.BLOB),
evm.getEvmVersion().getMaxInitcodeSize()))
evm.getMaxInitcodeSize()))
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::cancun)
.blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::cancunBlockHeaderValidator)
.blockHashProcessor(new CancunBlockHashProcessor())
@@ -813,8 +813,8 @@ public abstract class MainnetProtocolSpecs {
TransactionType.ACCESS_LIST,
TransactionType.EIP1559,
TransactionType.BLOB,
TransactionType.SET_CODE),
evm.getEvmVersion().getMaxInitcodeSize()))
TransactionType.DELEGATE_CODE),
evm.getMaxInitcodeSize()))
// EIP-2935 Blockhash processor
.blockHashProcessor(new PragueBlockHashProcessor())

View File

@@ -81,7 +81,7 @@ public class MainnetTransactionProcessor {
protected final FeeMarket feeMarket;
private final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator;
private final Optional<AuthorityProcessor> maybeAuthorityProcessor;
private final Optional<CodeDelegationProcessor> maybeCodeDelegationProcessor;
public MainnetTransactionProcessor(
final GasCalculator gasCalculator,
@@ -116,7 +116,7 @@ public class MainnetTransactionProcessor {
final int maxStackSize,
final FeeMarket feeMarket,
final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator,
final AuthorityProcessor maybeAuthorityProcessor) {
final CodeDelegationProcessor maybeCodeDelegationProcessor) {
this.gasCalculator = gasCalculator;
this.transactionValidatorFactory = transactionValidatorFactory;
this.contractCreationProcessor = contractCreationProcessor;
@@ -126,7 +126,7 @@ public class MainnetTransactionProcessor {
this.maxStackSize = maxStackSize;
this.feeMarket = feeMarket;
this.coinbaseFeePriceCalculator = coinbaseFeePriceCalculator;
this.maybeAuthorityProcessor = Optional.ofNullable(maybeAuthorityProcessor);
this.maybeCodeDelegationProcessor = Optional.ofNullable(maybeCodeDelegationProcessor);
}
/**
@@ -316,16 +316,7 @@ public class MainnetTransactionProcessor {
operationTracer.tracePrepareTransaction(evmWorldUpdater, transaction);
final Set<Address> addressList = new BytesTrieSet<>(Address.SIZE);
if (transaction.getAuthorizationList().isPresent()) {
if (maybeAuthorityProcessor.isEmpty()) {
throw new RuntimeException("Authority processor is required for 7702 transactions");
}
maybeAuthorityProcessor.get().addContractToAuthority(evmWorldUpdater, transaction);
addressList.addAll(evmWorldUpdater.authorizedCodeService().getAuthorities());
}
final Set<Address> warmAddressList = new BytesTrieSet<>(Address.SIZE);
final long previousNonce = sender.incrementNonce();
LOG.trace(
@@ -349,6 +340,20 @@ public class MainnetTransactionProcessor {
previousBalance,
sender.getBalance());
long codeDelegationRefund = 0L;
if (transaction.getCodeDelegationList().isPresent()) {
if (maybeCodeDelegationProcessor.isEmpty()) {
throw new RuntimeException("Code delegation processor is required for 7702 transactions");
}
final CodeDelegationResult codeDelegationResult =
maybeCodeDelegationProcessor.get().process(evmWorldUpdater, transaction);
warmAddressList.addAll(codeDelegationResult.accessedDelegatorAddresses());
codeDelegationRefund =
gasCalculator.calculateDelegateCodeGasRefund(
(codeDelegationResult.alreadyExistingDelegators()));
}
final List<AccessListEntry> accessListEntries = transaction.getAccessList().orElse(List.of());
// we need to keep a separate hash set of addresses in case they specify no storage.
// No-storage is a common pattern, especially for Externally Owned Accounts
@@ -356,13 +361,13 @@ public class MainnetTransactionProcessor {
int accessListStorageCount = 0;
for (final var entry : accessListEntries) {
final Address address = entry.address();
addressList.add(address);
warmAddressList.add(address);
final List<Bytes32> storageKeys = entry.storageKeys();
storageList.putAll(address, storageKeys);
accessListStorageCount += storageKeys.size();
}
if (warmCoinbase) {
addressList.add(miningBeneficiary);
warmAddressList.add(miningBeneficiary);
}
final long intrinsicGas =
@@ -370,16 +375,17 @@ public class MainnetTransactionProcessor {
transaction.getPayload(), transaction.isContractCreation());
final long accessListGas =
gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount);
final long setCodeGas = gasCalculator.setCodeListGasCost(transaction.authorizationListSize());
final long codeDelegationGas =
gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize());
final long gasAvailable =
transaction.getGasLimit() - intrinsicGas - accessListGas - setCodeGas;
transaction.getGasLimit() - intrinsicGas - accessListGas - codeDelegationGas;
LOG.trace(
"Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - setCode)",
"Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - codeDelegation)",
gasAvailable,
transaction.getGasLimit(),
intrinsicGas,
accessListGas,
setCodeGas);
codeDelegationGas);
final WorldUpdater worldUpdater = evmWorldUpdater.updater();
final ImmutableMap.Builder<String, Object> contextVariablesBuilder =
@@ -409,7 +415,7 @@ public class MainnetTransactionProcessor {
.miningBeneficiary(miningBeneficiary)
.blockHashLookup(blockHashLookup)
.contextVariables(contextVariablesBuilder.build())
.accessListWarmAddresses(addressList)
.accessListWarmAddresses(warmAddressList)
.accessListWarmStorage(storageList);
if (transaction.getVersionedHashes().isPresent()) {
@@ -488,7 +494,8 @@ public class MainnetTransactionProcessor {
// after the other so that if it is the same account somehow, we end up with the right result)
final long selfDestructRefund =
gasCalculator.getSelfDestructRefundAmount() * initialFrame.getSelfDestructs().size();
final long baseRefundGas = initialFrame.getGasRefund() + selfDestructRefund;
final long baseRefundGas =
initialFrame.getGasRefund() + selfDestructRefund + codeDelegationRefund;
final long refundedGas = refunded(transaction, initialFrame.getRemainingGas(), baseRefundGas);
final Wei refundedWei = transactionGasPrice.multiply(refundedGas);
final Wei balancePriorToRefund = sender.getBalance();
@@ -528,7 +535,6 @@ public class MainnetTransactionProcessor {
final var coinbase = evmWorldUpdater.getOrCreate(miningBeneficiary);
coinbase.incrementBalance(coinbaseWeiDelta);
evmWorldUpdater.authorizedCodeService().resetAuthorities();
operationTracer.traceEndTransaction(
worldUpdater,

View File

@@ -20,6 +20,7 @@ import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Blob;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.KZGCommitment;
import org.hyperledger.besu.datatypes.TransactionType;
@@ -129,9 +130,50 @@ public class MainnetTransactionValidator implements TransactionValidator {
transaction.getPayload().size(), maxInitcodeSize));
}
if (transactionType == TransactionType.DELEGATE_CODE) {
if (isDelegateCodeEmpty(transaction)) {
return ValidationResult.invalid(
TransactionInvalidReason.EMPTY_CODE_DELEGATION,
"transaction code delegation transactions must have a non-empty code delegation list");
}
final BigInteger halfCurveOrder = SignatureAlgorithmFactory.getInstance().getHalfCurveOrder();
final Optional<ValidationResult<TransactionInvalidReason>> validationResult =
transaction
.getCodeDelegationList()
.map(
codeDelegations -> {
for (CodeDelegation codeDelegation : codeDelegations) {
if (codeDelegation.signature().getS().compareTo(halfCurveOrder) > 0) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_SIGNATURE,
"Invalid signature for code delegation. S value must be less or equal than the half curve order.");
}
if (codeDelegation.signature().getRecId() != 0
&& codeDelegation.signature().getRecId() != 1) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_SIGNATURE,
"Invalid signature for code delegation. RecId value must be 0 or 1.");
}
}
return ValidationResult.valid();
});
if (validationResult.isPresent() && !validationResult.get().isValid()) {
return validationResult.get();
}
}
return validateCostAndFee(transaction, baseFee, blobFee, transactionValidationParams);
}
private static boolean isDelegateCodeEmpty(final Transaction transaction) {
return transaction.getCodeDelegationList().isEmpty()
|| transaction.getCodeDelegationList().get().isEmpty();
}
private ValidationResult<TransactionInvalidReason> validateCostAndFee(
final Transaction transaction,
final Optional<Wei> maybeBaseFee,
@@ -190,7 +232,7 @@ public class MainnetTransactionValidator implements TransactionValidator {
gasCalculator.transactionIntrinsicGasCost(
transaction.getPayload(), transaction.isContractCreation())
+ (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L))
+ gasCalculator.setCodeListGasCost(transaction.authorizationListSize());
+ gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize());
if (Long.compareUnsigned(intrinsicGasCost, transaction.getGasLimit()) > 0) {
return ValidationResult.invalid(
TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT,
@@ -250,7 +292,8 @@ public class MainnetTransactionValidator implements TransactionValidator {
transaction.getNonce(), senderNonce));
}
if (!validationParams.isAllowContractAddressAsSender() && !codeHash.equals(Hash.EMPTY)) {
if (!validationParams.isAllowContractAddressAsSender()
&& !canSendTransaction(sender, codeHash)) {
return ValidationResult.invalid(
TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED,
String.format(
@@ -261,6 +304,10 @@ public class MainnetTransactionValidator implements TransactionValidator {
return ValidationResult.valid();
}
private static boolean canSendTransaction(final Account sender, final Hash codeHash) {
return codeHash.equals(Hash.EMPTY) || sender.hasDelegatedCode();
}
private ValidationResult<TransactionInvalidReason> validateTransactionSignature(
final Transaction transaction) {
if (chainId.isPresent()

View File

@@ -51,6 +51,7 @@ public enum TransactionInvalidReason {
PLUGIN_TX_POOL_VALIDATOR,
EXECUTION_HALTED,
EOF_CODE_INVALID,
EMPTY_CODE_DELEGATION,
// Private Transaction Invalid Reasons
PRIVATE_TRANSACTION_INVALID,
PRIVATE_TRANSACTION_FAILED,

View File

@@ -376,7 +376,7 @@ public class BlockDataGenerator {
case EIP1559 -> eip1559Transaction(payload, to);
case ACCESS_LIST -> accessListTransaction(payload, to);
case BLOB -> blobTransaction(payload, to);
case SET_CODE -> null;
case DELEGATE_CODE -> null;
// no default, all types accounted for.
};
}

View File

@@ -92,7 +92,7 @@ public class TransactionTestFixture {
builder.versionedHashes(versionedHashes.get());
}
break;
case SET_CODE:
case DELEGATE_CODE:
break;
}

View File

@@ -15,11 +15,10 @@
package org.hyperledger.besu.ethereum.core.encoding;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.SetCodeAuthorization;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import java.math.BigInteger;
@@ -27,7 +26,7 @@ import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Test;
class SetCodeTransactionDecoderTest {
class CodeDelegationDecoderTest {
@Test
void shouldDecodeInnerPayloadWithNonce() {
@@ -36,14 +35,14 @@ class SetCodeTransactionDecoderTest {
final BytesValueRLPInput input =
new BytesValueRLPInput(
Bytes.fromHexString(
"0xf85b0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c18080a0840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5a03b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99"),
"0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa562a80a0840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5a03b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99"),
true);
final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input);
final CodeDelegation authorization = CodeDelegationTransactionDecoder.decodeInnerPayload(input);
assertThat(authorization.chainId()).isEqualTo(BigInteger.ONE);
assertThat(authorization.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonce().get()).isEqualTo(0L);
assertThat(authorization.nonce()).isEqualTo(42);
final SECPSignature signature = authorization.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 0);
@@ -54,20 +53,20 @@ class SetCodeTransactionDecoderTest {
}
@Test
void shouldDecodeInnerPayloadWithoutNonce() {
void shouldDecodeInnerPayloadWithNonceZero() {
// "0xd70194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5"
final BytesValueRLPInput input =
new BytesValueRLPInput(
Bytes.fromHexString(
"0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148a025b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031"),
"0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa568001a0dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148a025b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031"),
true);
final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input);
final CodeDelegation authorization = CodeDelegationTransactionDecoder.decodeInnerPayload(input);
assertThat(authorization.chainId()).isEqualTo(BigInteger.ONE);
assertThat(authorization.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonce()).isEmpty();
assertThat(authorization.nonce()).isEqualTo(0);
final SECPSignature signature = authorization.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 1);
@@ -78,37 +77,20 @@ class SetCodeTransactionDecoderTest {
}
@Test
void shouldThrowInnerPayloadWithMultipleNonces() {
// "d90194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c20107"
final BytesValueRLPInput input =
new BytesValueRLPInput(
Bytes.fromHexString(
"0xf85c0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c2010201a0401b5d4ebe88306448115d1a46a30e5ad1136f2818b4ebb0733d9c4efffd135aa0753ff1dbce6db504ecb9635a64d8c4506ff887e2d2a0d2b7175baf94c849eccc"),
true);
assertThrows(
IllegalArgumentException.class,
() -> {
SetCodeTransactionDecoder.decodeInnerPayload(input);
});
}
@Test
void shouldDecodeInnerPayloadWithoutNonceAndChainIdZero() {
void shouldDecodeInnerPayloadWithChainIdZero() {
// "d70094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5"
final BytesValueRLPInput input =
new BytesValueRLPInput(
Bytes.fromHexString(
"0xf85a0094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0025c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2a03c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df"),
"0xf85a8094633688abc3ccf8b0c03088d2d1c6ae4958c2fa560501a0025c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2a03c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df"),
true);
final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input);
final CodeDelegation authorization = CodeDelegationTransactionDecoder.decodeInnerPayload(input);
assertThat(authorization.chainId()).isEqualTo(BigInteger.ZERO);
assertThat(authorization.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonce().isEmpty()).isTrue();
assertThat(authorization.nonce()).isEqualTo(5);
final SECPSignature signature = authorization.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 1);

View File

@@ -19,11 +19,10 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.core.SetCodeAuthorization;
import org.hyperledger.besu.ethereum.core.CodeDelegation;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import java.math.BigInteger;
import java.util.Optional;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
@@ -31,7 +30,7 @@ import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class SetCodeTransactionEncoderTest {
class CodeDelegationEncoderTest {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
@@ -43,14 +42,14 @@ class SetCodeTransactionEncoderTest {
}
@Test
void shouldEncodeSingleSetCodeWithNonce() {
void shouldEncodeSingleCodeDelegationWithNonceAndChainId() {
// "0xd80194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c105"
final SetCodeAuthorization authorization =
new SetCodeAuthorization(
final CodeDelegation authorization =
new CodeDelegation(
BigInteger.ONE,
Address.fromHexString("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"),
Optional.of(0L),
42,
SIGNATURE_ALGORITHM
.get()
.createSignature(
@@ -60,23 +59,23 @@ class SetCodeTransactionEncoderTest {
"3b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99", 16),
(byte) 0));
SetCodeTransactionEncoder.encodeSingleSetCode(authorization, output);
CodeDelegationEncoder.encodeSingleCodeDelegation(authorization, output);
assertThat(output.encoded())
.isEqualTo(
Bytes.fromHexString(
"0xf85b0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c18080a0840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5a03b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99"));
"0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa562a80a0840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5a03b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99"));
}
@Test
void shouldEncodeSingleSetCodeWithoutNonce() {
void shouldEncodeSingleCodeDelegationWithNonceZero() {
// "0xd70194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5"
final SetCodeAuthorization authorization =
new SetCodeAuthorization(
final CodeDelegation authorization =
new CodeDelegation(
BigInteger.ONE,
Address.fromHexString("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"),
Optional.empty(),
0,
SIGNATURE_ALGORITHM
.get()
.createSignature(
@@ -86,23 +85,23 @@ class SetCodeTransactionEncoderTest {
"25b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031", 16),
(byte) 1));
SetCodeTransactionEncoder.encodeSingleSetCode(authorization, output);
CodeDelegationEncoder.encodeSingleCodeDelegation(authorization, output);
assertThat(output.encoded())
.isEqualTo(
Bytes.fromHexString(
"0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148a025b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031"));
"0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa568001a0dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148a025b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031"));
}
@Test
void shouldEncodeSingleSetCodeWithoutNonceAndChainIdZero() {
void shouldEncodeSingleCodeDelegationWithChainIdZero() {
// "d70094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5"
final SetCodeAuthorization authorization =
new SetCodeAuthorization(
final CodeDelegation authorization =
new CodeDelegation(
BigInteger.ZERO,
Address.fromHexString("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"),
Optional.empty(),
5,
SIGNATURE_ALGORITHM
.get()
.createSignature(
@@ -112,11 +111,11 @@ class SetCodeTransactionEncoderTest {
"3c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df", 16),
(byte) 1));
SetCodeTransactionEncoder.encodeSingleSetCode(authorization, output);
CodeDelegationEncoder.encodeSingleCodeDelegation(authorization, output);
assertThat(output.encoded())
.isEqualTo(
Bytes.fromHexString(
"0xf85a8094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0025c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2a03c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df"));
"0xf85a8094633688abc3ccf8b0c03088d2d1c6ae4958c2fa560501a0025c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2a03c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df"));
}
}

View File

@@ -89,7 +89,7 @@ class MainnetTransactionProcessorTest {
MAX_STACK_SIZE,
FeeMarket.legacy(),
CoinbaseFeePriceCalculator.frontier(),
new AuthorityProcessor(Optional.of(BigInteger.ONE)));
new CodeDelegationProcessor(Optional.of(BigInteger.ONE)));
}
@Test

View File

@@ -181,7 +181,8 @@ public abstract class AbstractIsolationTests {
mock(TransactionBroadcaster.class),
ethContext,
txPoolMetrics,
poolConfiguration);
poolConfiguration,
new BlobCache());
transactionPool.setEnabled();
}

View File

@@ -87,4 +87,8 @@ public class BlobCache {
return Optional.empty();
}
}
public BlobsWithCommitments.BlobQuad get(final VersionedHash vh) {
return cache.getIfPresent(vh);
}
}

View File

@@ -31,8 +31,8 @@ import java.util.concurrent.atomic.AtomicLong;
public abstract class PendingTransaction
implements org.hyperledger.besu.datatypes.PendingTransaction {
static final int NOT_INITIALIZED = -1;
static final int FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE = 888;
static final int EIP1559_AND_EIP4844_SHALLOW_MEMORY_SIZE = 1000;
static final int FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE = 904;
static final int EIP1559_AND_EIP4844_SHALLOW_MEMORY_SIZE = 1016;
static final int OPTIONAL_TO_MEMORY_SIZE = 112;
static final int OPTIONAL_CHAIN_ID_MEMORY_SIZE = 80;
static final int PAYLOAD_BASE_MEMORY_SIZE = 32;
@@ -147,7 +147,7 @@ public abstract class PendingTransaction
case ACCESS_LIST -> computeAccessListMemorySize();
case EIP1559 -> computeEIP1559MemorySize();
case BLOB -> computeBlobMemorySize();
case SET_CODE -> computeSetCodeMemorySize();
case DELEGATE_CODE -> computeSetCodeMemorySize();
}
+ PENDING_TRANSACTION_MEMORY_SIZE;
}

View File

@@ -20,8 +20,10 @@ import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.TRANSACTION_ALREADY_KNOWN;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BlockAddedEvent;
@@ -55,6 +57,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Map;
@@ -89,6 +92,7 @@ public class TransactionPool implements BlockAddedObserver {
private static final Logger LOG = LoggerFactory.getLogger(TransactionPool.class);
private static final Logger LOG_FOR_REPLAY = LoggerFactory.getLogger("LOG_FOR_REPLAY");
private final Supplier<PendingTransactions> pendingTransactionsSupplier;
private final BlobCache cacheForBlobsOfTransactionsAddedToABlock;
private volatile PendingTransactions pendingTransactions = new DisabledPendingTransactions();
private final ProtocolSchedule protocolSchedule;
private final ProtocolContext protocolContext;
@@ -103,6 +107,8 @@ public class TransactionPool implements BlockAddedObserver {
private final SaveRestoreManager saveRestoreManager = new SaveRestoreManager();
private final Set<Address> localSenders = ConcurrentHashMap.newKeySet();
private final EthScheduler.OrderedProcessor<BlockAddedEvent> blockAddedEventOrderedProcessor;
private final Map<VersionedHash, BlobsWithCommitments.BlobQuad> mapOfBlobsInTransactionPool =
new HashMap<>();
public TransactionPool(
final Supplier<PendingTransactions> pendingTransactionsSupplier,
@@ -111,7 +117,8 @@ public class TransactionPool implements BlockAddedObserver {
final TransactionBroadcaster transactionBroadcaster,
final EthContext ethContext,
final TransactionPoolMetrics metrics,
final TransactionPoolConfiguration configuration) {
final TransactionPoolConfiguration configuration,
final BlobCache blobCache) {
this.pendingTransactionsSupplier = pendingTransactionsSupplier;
this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext;
@@ -121,7 +128,10 @@ public class TransactionPool implements BlockAddedObserver {
this.configuration = configuration;
this.blockAddedEventOrderedProcessor =
ethContext.getScheduler().createOrderedProcessor(this::processBlockAddedEvent);
this.cacheForBlobsOfTransactionsAddedToABlock = blobCache;
initLogForReplay();
subscribePendingTransactions(this::mapBlobsOnTransactionAdded);
subscribeDroppedTransactions(this::unmapBlobsOnTransactionDropped);
}
private void initLogForReplay() {
@@ -640,6 +650,38 @@ public class TransactionPool implements BlockAddedObserver {
return CompletableFuture.completedFuture(null);
}
private void mapBlobsOnTransactionAdded(
final org.hyperledger.besu.datatypes.Transaction transaction) {
final Optional<BlobsWithCommitments> maybeBlobsWithCommitments =
transaction.getBlobsWithCommitments();
if (maybeBlobsWithCommitments.isEmpty()) {
return;
}
final List<BlobsWithCommitments.BlobQuad> blobQuads =
maybeBlobsWithCommitments.get().getBlobQuads();
blobQuads.forEach(bq -> mapOfBlobsInTransactionPool.put(bq.versionedHash(), bq));
}
private void unmapBlobsOnTransactionDropped(
final org.hyperledger.besu.datatypes.Transaction transaction) {
final Optional<BlobsWithCommitments> maybeBlobsWithCommitments =
transaction.getBlobsWithCommitments();
if (maybeBlobsWithCommitments.isEmpty()) {
return;
}
final List<BlobsWithCommitments.BlobQuad> blobQuads =
maybeBlobsWithCommitments.get().getBlobQuads();
blobQuads.forEach(bq -> mapOfBlobsInTransactionPool.remove(bq.versionedHash()));
}
public BlobsWithCommitments.BlobQuad getBlobQuad(final VersionedHash vh) {
BlobsWithCommitments.BlobQuad blobQuad = mapOfBlobsInTransactionPool.get(vh);
if (blobQuad == null) {
blobQuad = cacheForBlobsOfTransactionsAddedToABlock.get(vh);
}
return blobQuad;
}
public boolean isEnabled() {
return isPoolEnabled.get();
}

View File

@@ -80,6 +80,7 @@ public interface TransactionPoolConfiguration {
Implementation DEFAULT_TX_POOL_IMPLEMENTATION = Implementation.LAYERED;
Set<Address> DEFAULT_PRIORITY_SENDERS = Set.of();
Wei DEFAULT_TX_POOL_MIN_GAS_PRICE = Wei.of(1000);
byte DEFAULT_TX_POOL_MIN_SCORE = -128;
TransactionPoolConfiguration DEFAULT = ImmutableTransactionPoolConfiguration.builder().build();
@@ -173,6 +174,11 @@ public interface TransactionPoolConfiguration {
return DEFAULT_TX_POOL_MIN_GAS_PRICE;
}
@Value.Default
default byte getMinScore() {
return DEFAULT_TX_POOL_MIN_SCORE;
}
@Value.Default
default TransactionPoolValidatorService getTransactionPoolValidatorService() {
return new TransactionPoolValidatorService() {

Some files were not shown because too many files have changed in this diff Show More