mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-08 21:38:15 -05:00
Merge branch 'main' into zkbesu
# Conflicts: # .github/workflows/acceptance-tests.yml # .github/workflows/pre-review.yml # build.gradle
This commit is contained in:
175
CHANGELOG.md
175
CHANGELOG.md
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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))));
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,8 @@
|
||||
"consolidationRequests": [
|
||||
{
|
||||
"sourceAddress": "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f",
|
||||
"sourcePubKey": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"targetPubKey": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
|
||||
"sourcePubkey": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"targetPubkey": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
|
||||
}
|
||||
],
|
||||
"blockNumber": "0x4",
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ public interface BesuComponent {
|
||||
*
|
||||
* @return BesuPluginContextImpl
|
||||
*/
|
||||
@Named("besuPluginContext")
|
||||
BesuPluginContextImpl getBesuPluginContext();
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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"),
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -119,7 +119,8 @@ public class JsonRpcMethodsFactory {
|
||||
ethPeers,
|
||||
consensusEngineServer,
|
||||
clientVersion,
|
||||
commit),
|
||||
commit,
|
||||
transactionPool),
|
||||
new EthJsonRpcMethods(
|
||||
blockchainQueries,
|
||||
synchronizer,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 =
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -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 sender’s 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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
};
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class TransactionTestFixture {
|
||||
builder.versionedHashes(versionedHashes.get());
|
||||
}
|
||||
break;
|
||||
case SET_CODE:
|
||||
case DELEGATE_CODE:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -181,7 +181,8 @@ public abstract class AbstractIsolationTests {
|
||||
mock(TransactionBroadcaster.class),
|
||||
ethContext,
|
||||
txPoolMetrics,
|
||||
poolConfiguration);
|
||||
poolConfiguration,
|
||||
new BlobCache());
|
||||
transactionPool.setEnabled();
|
||||
}
|
||||
|
||||
|
||||
@@ -87,4 +87,8 @@ public class BlobCache {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public BlobsWithCommitments.BlobQuad get(final VersionedHash vh) {
|
||||
return cache.getIfPresent(vh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user