From d584aab7c152b5b5864fdee827f6f347b65fee8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20L=C3=B3pez=20Le=C3=B3n?= Date: Mon, 28 Aug 2023 19:10:20 -0300 Subject: [PATCH 01/34] Drop Kotti Network support (ETC) (#5816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Diego López León Signed-off-by: garyschulte --- CHANGELOG.md | 1 + .../besu/cli/config/NetworkName.java | 2 - .../besu/ForkIdsNetworkConfigTest.java | 11 - .../hyperledger/besu/cli/BesuCommandTest.java | 22 - .../cli/NetworkDeprecationMessageTest.java | 2 +- .../config/DefaultDiscoveryConfiguration.java | 19 - config/src/main/resources/kotti.json | 815 ------------------ 7 files changed, 2 insertions(+), 870 deletions(-) delete mode 100644 config/src/main/resources/kotti.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 40ce5583d5c..60aaaf4c1b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.2/besu-23.7.2.z ### Breaking Changes - Removed deprecated GoQuorum permissioning interop [#5607](https://github.com/hyperledger/besu/pull/5607) - Removed support for version 0 of the database as it is no longer used by any active node. [#5698](https://github.com/hyperledger/besu/pull/5698) +- Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816) ### Additions and Improvements - `evmtool` launcher binaries now ship as part of the standard distribution. [#5701](https://github.com/hyperledger/besu/pull/5701) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java index a83ef68aaee..6638ddfa44e 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java @@ -38,8 +38,6 @@ public enum NetworkName { EXPERIMENTAL_EIPS("/experimental.json", BigInteger.valueOf(2023), false), /** Classic network name. */ CLASSIC("/classic.json", BigInteger.valueOf(1)), - /** Kotti network name. */ - KOTTI("/kotti.json", BigInteger.valueOf(6)), /** Mordor network name. */ MORDOR("/mordor.json", BigInteger.valueOf(7)); diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java index 7324038264f..df5607120e5 100644 --- a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java +++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java @@ -131,17 +131,6 @@ public static Collection parameters() { new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L), new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L)) }, - new Object[] { - NetworkName.KOTTI, - List.of( - new ForkId(Bytes.ofUnsignedInt(0x550152eL), 716617L), - new ForkId(Bytes.ofUnsignedInt(0xa3270822L), 1705549L), - new ForkId(Bytes.ofUnsignedInt(0x8f3698e0L), 2200013L), - new ForkId(Bytes.ofUnsignedInt(0x6f402821L), 4368634), - new ForkId(Bytes.ofUnsignedInt(0xf03e54e7L), 5578000L), - new ForkId(Bytes.ofUnsignedInt(0xc5459816L), 0L), - new ForkId(Bytes.ofUnsignedInt(0xc5459816L), 0L)) - }, new Object[] { NetworkName.CLASSIC, List.of( diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index bfabc53eb6f..3376d2b7001 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -25,7 +25,6 @@ import static org.hyperledger.besu.cli.config.NetworkName.FUTURE_EIPS; import static org.hyperledger.besu.cli.config.NetworkName.GOERLI; import static org.hyperledger.besu.cli.config.NetworkName.HOLESKY; -import static org.hyperledger.besu.cli.config.NetworkName.KOTTI; import static org.hyperledger.besu.cli.config.NetworkName.MAINNET; import static org.hyperledger.besu.cli.config.NetworkName.MORDOR; import static org.hyperledger.besu.cli.config.NetworkName.SEPOLIA; @@ -4109,22 +4108,6 @@ public void classicValuesAreUsed() throws Exception { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } - @Test - public void kottiValuesAreUsed() throws Exception { - parseCommand("--network", "kotti"); - - final ArgumentCaptor networkArg = - ArgumentCaptor.forClass(EthNetworkConfig.class); - - verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any()); - verify(mockControllerBuilder).build(); - - assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(KOTTI)); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - @Test public void mordorValuesAreUsed() throws Exception { parseCommand("--network", "mordor"); @@ -4166,11 +4149,6 @@ public void classicValuesCanBeOverridden() throws Exception { networkValuesCanBeOverridden("classic"); } - @Test - public void kottiValuesCanBeOverridden() throws Exception { - networkValuesCanBeOverridden("kotti"); - } - @Test public void mordorValuesCanBeOverridden() throws Exception { networkValuesCanBeOverridden("mordor"); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java b/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java index b1b0363a3b0..f40dde9313d 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java @@ -39,7 +39,7 @@ void shouldGenerateDeprecationMessageForDeprecatedNetworks(final NetworkName net @EnumSource( value = NetworkName.class, names = { - "MAINNET", "SEPOLIA", "GOERLI", "DEV", "CLASSIC", "KOTTI", "MORDOR", "HOLESKY", + "MAINNET", "SEPOLIA", "GOERLI", "DEV", "CLASSIC", "MORDOR", "HOLESKY", }) void shouldThrowErrorForNonDeprecatedNetworks(final NetworkName network) { assertThatThrownBy(() -> NetworkDeprecationMessage.generate(network)) diff --git a/besu/src/test/java/org/hyperledger/besu/ethereum/p2p/config/DefaultDiscoveryConfiguration.java b/besu/src/test/java/org/hyperledger/besu/ethereum/p2p/config/DefaultDiscoveryConfiguration.java index 3a63648bcbb..a5b4f965001 100644 --- a/besu/src/test/java/org/hyperledger/besu/ethereum/p2p/config/DefaultDiscoveryConfiguration.java +++ b/besu/src/test/java/org/hyperledger/besu/ethereum/p2p/config/DefaultDiscoveryConfiguration.java @@ -109,25 +109,6 @@ public class DefaultDiscoveryConfiguration { "enode://5cd218959f8263bc3721d7789070806b0adff1a0ed3f95ec886fb469f9362c7507e3b32b256550b9a7964a23a938e8d42d45a0c34b332bfebc54b29081e83b93@35.187.57.94:30303") .map(EnodeURLImpl::fromString) .collect(toList())); - public static final List KOTTI_BOOTSTRAP_NODES = - Collections.unmodifiableList( - Stream.of( - // Authority Nodes - "enode://a59e33ccd2b3e52d578f1fbd70c6f9babda2650f0760d6ff3b37742fdcdfdb3defba5d56d315b40c46b70198c7621e63ffa3f987389c7118634b0fefbbdfa7fd@51.158.191.43:37956", // @q9f Mizar - "enode://93c94e999be5dd854c5d82a7cf5c14822973b5d9badb56ad4974586ec4d4f1995c815af795c20bb6e0a6226d3ee55808435c4dc89baf94ee581141b064d19dfc@80.187.116.161:25720", - "enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303", - "enode://b477ca6d507a3f57070783eb62ba838847635f8b1a0cbffb8b7f8173f5894cf550f0225a5c279341e2d862a606e778b57180a4f1db3db78c51eadcfa4fdc6963@40.68.240.160:30303", - - // @q9f Bootnodes - "enode://4956f6924335c951cb70cbc169a85c081f6ff0b374aa2815453b8a3132b49613f38a1a6b8e103f878dbec86364f60091e92a376d7cd3aca9d82d2f2554794e63@51.15.97.240:41235", // @q9f Ginan - "enode://6c9a052c01bb9995fa53bebfcdbc17733fe90708270d0e6d8e38dc57b32e1dbe8c287590b634ee9753b94ba302f411c96519c7fa07df0df6a6848149d819b2c5@51.15.70.7:41235", // @q9f Polis - "enode://95a7302fd8f35d9ad716a591b90dfe839dbf2d3d6a6737ef39e07899f844ad82f1659dd6212492922dd36705fb0a1e984c1d5d5c42069d5bd329388831e820c1@51.15.97.240:45678", // @q9f Ginan - "enode://8c5c4dec9a0728c7058d3c29698bae888adc244e443cebc21f3d708a20751511acbf98a52b5e5ea472f8715c658913e8084123461fd187a4980a0600420b0791@51.15.70.7:45678", // @q9f Polis - "enode://efd7391a3bed73ad74ae5760319bb48f9c9f1983ff22964422688cdb426c5d681004ece26c47121396653cf9bafe7104aa4ecff70e24cc5b11fd76be8e5afce0@51.158.191.43:45678", // @q9f Mizar - "enode://93b12383c74c39b67afa99a7ff44ce250fe94295fa1fc087465cc4fe2d0b33b91a8d8cabe03b250104a9096aa0e06bcde5f95665a5bd9f890edd2ab33e16ae47@51.15.41.19:30303" // @q9f Zibal - ) - .map(EnodeURLImpl::fromString) - .collect(toList())); public static final List MORDOR_BOOTSTRAP_NODES = Collections.unmodifiableList( Stream.of( diff --git a/config/src/main/resources/kotti.json b/config/src/main/resources/kotti.json deleted file mode 100644 index e861afd95c8..00000000000 --- a/config/src/main/resources/kotti.json +++ /dev/null @@ -1,815 +0,0 @@ -{ - "config": { - "chainId": 6, - "ecip1041Block": 0, - "atlantisBlock": 716617, - "aghartaBlock": 1705549, - "phoenixBlock": 2200013, - "magnetoBlock": 4368634, - "mystiqueBlock": 5578000, - "clique":{ - "blockperiodseconds":15, - "epochlength":30000 - }, - "discovery": { - "bootnodes": [ - "enode://a59e33ccd2b3e52d578f1fbd70c6f9babda2650f0760d6ff3b37742fdcdfdb3defba5d56d315b40c46b70198c7621e63ffa3f987389c7118634b0fefbbdfa7fd@51.158.191.43:37956", - "enode://93c94e999be5dd854c5d82a7cf5c14822973b5d9badb56ad4974586ec4d4f1995c815af795c20bb6e0a6226d3ee55808435c4dc89baf94ee581141b064d19dfc@80.187.116.161:25720", - "enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303", - "enode://b477ca6d507a3f57070783eb62ba838847635f8b1a0cbffb8b7f8173f5894cf550f0225a5c279341e2d862a606e778b57180a4f1db3db78c51eadcfa4fdc6963@40.68.240.160:30303", - "enode://4956f6924335c951cb70cbc169a85c081f6ff0b374aa2815453b8a3132b49613f38a1a6b8e103f878dbec86364f60091e92a376d7cd3aca9d82d2f2554794e63@51.15.97.240:41235", - "enode://6c9a052c01bb9995fa53bebfcdbc17733fe90708270d0e6d8e38dc57b32e1dbe8c287590b634ee9753b94ba302f411c96519c7fa07df0df6a6848149d819b2c5@51.15.70.7:41235", - "enode://95a7302fd8f35d9ad716a591b90dfe839dbf2d3d6a6737ef39e07899f844ad82f1659dd6212492922dd36705fb0a1e984c1d5d5c42069d5bd329388831e820c1@51.15.97.240:45678", - "enode://8c5c4dec9a0728c7058d3c29698bae888adc244e443cebc21f3d708a20751511acbf98a52b5e5ea472f8715c658913e8084123461fd187a4980a0600420b0791@51.15.70.7:45678", - "enode://efd7391a3bed73ad74ae5760319bb48f9c9f1983ff22964422688cdb426c5d681004ece26c47121396653cf9bafe7104aa4ecff70e24cc5b11fd76be8e5afce0@51.158.191.43:45678", - "enode://93b12383c74c39b67afa99a7ff44ce250fe94295fa1fc087465cc4fe2d0b33b91a8d8cabe03b250104a9096aa0e06bcde5f95665a5bd9f890edd2ab33e16ae47@51.15.41.19:30303" - ] - } - }, - "nonce": "0x0", - "timestamp": "0x5c2d2287", - "extraData": "0x000000000000000000000000000000000000000000000000000000000000000025b7955e43adf9c2a01a9475908702cce67f302a6aaf8cba3c9255a2b863415d4db7bae4f4bbca020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "0xa00000", - "difficulty": "0x1", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "alloc": { - "0000000000000000000000000000000000000000": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000001": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000002": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000003": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000004": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000005": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000006": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000007": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000008": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000009": { - "balance": "0x1" - }, - "000000000000000000000000000000000000000a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000000b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000000c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000000d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000000e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000000f": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000010": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000011": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000012": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000013": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000014": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000015": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000016": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000017": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000018": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000019": { - "balance": "0x1" - }, - "000000000000000000000000000000000000001a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000001b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000001c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000001d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000001e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000001f": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000020": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000021": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000022": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000023": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000024": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000025": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000026": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000027": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000028": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000029": { - "balance": "0x1" - }, - "000000000000000000000000000000000000002a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000002b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000002c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000002d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000002e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000002f": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000030": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000031": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000032": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000033": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000034": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000035": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000036": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000037": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000038": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000039": { - "balance": "0x1" - }, - "000000000000000000000000000000000000003a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000003b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000003c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000003d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000003e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000003f": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000040": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000041": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000042": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000043": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000044": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000045": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000046": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000047": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000048": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000049": { - "balance": "0x1" - }, - "000000000000000000000000000000000000004a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000004b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000004c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000004d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000004e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000004f": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000050": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000051": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000052": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000053": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000054": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000055": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000056": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000057": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000058": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000059": { - "balance": "0x1" - }, - "000000000000000000000000000000000000005a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000005b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000005c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000005d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000005e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000005f": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000060": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000061": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000062": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000063": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000064": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000065": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000066": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000067": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000068": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000069": { - "balance": "0x1" - }, - "000000000000000000000000000000000000006a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000006b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000006c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000006d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000006e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000006f": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000070": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000071": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000072": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000073": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000074": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000075": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000076": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000077": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000078": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000079": { - "balance": "0x1" - }, - "000000000000000000000000000000000000007a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000007b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000007c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000007d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000007e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000007f": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000080": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000081": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000082": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000083": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000084": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000085": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000086": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000087": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000088": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000089": { - "balance": "0x1" - }, - "000000000000000000000000000000000000008a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000008b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000008c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000008d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000008e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000008f": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000090": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000091": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000092": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000093": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000094": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000095": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000096": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000097": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000098": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000099": { - "balance": "0x1" - }, - "000000000000000000000000000000000000009a": { - "balance": "0x1" - }, - "000000000000000000000000000000000000009b": { - "balance": "0x1" - }, - "000000000000000000000000000000000000009c": { - "balance": "0x1" - }, - "000000000000000000000000000000000000009d": { - "balance": "0x1" - }, - "000000000000000000000000000000000000009e": { - "balance": "0x1" - }, - "000000000000000000000000000000000000009f": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a0": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a1": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a2": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a3": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a4": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a5": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a6": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a7": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a8": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000a9": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000aa": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ab": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ac": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ad": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ae": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000af": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b0": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b1": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b2": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b3": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b4": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b5": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b6": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b7": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b8": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000b9": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ba": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000bb": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000bc": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000bd": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000be": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000bf": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c0": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c1": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c2": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c3": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c4": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c5": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c6": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c7": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c8": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000c9": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ca": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000cb": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000cc": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000cd": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ce": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000cf": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d0": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d1": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d2": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d3": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d4": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d5": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d6": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d7": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d8": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000d9": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000da": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000db": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000dc": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000dd": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000de": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000df": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e0": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e1": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e2": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e3": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e4": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e5": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e6": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e7": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e8": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000e9": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ea": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000eb": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ec": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ed": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ee": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ef": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f0": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f1": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f2": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f3": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f4": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f5": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f6": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f7": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f8": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000f9": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000fa": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000fb": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000fc": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000fd": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000fe": { - "balance": "0x1" - }, - "00000000000000000000000000000000000000ff": { - "balance": "0x1" - }, - "25b7955e43adf9c2a01a9475908702cce67f302a": { - "balance": "0x84595161401484a000000" - }, - "6aaf8cba3c9255a2b863415d4db7bae4f4bbca02": { - "balance": "0x4a723dc6b40b8a9a000000" - } - }, - "number": "0x0", - "gasUsed": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" -} \ No newline at end of file From dd2ad353d7ff3e2202fb25ba5a7564d3f792abf5 Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:01:38 +1000 Subject: [PATCH 02/34] fix ForkId if there are no Forks and the starting timestamp is not 0 (#5819) Signed-off-by: Stefan Signed-off-by: garyschulte --- .../besu/ethereum/forkid/ForkIdManager.java | 6 +++--- .../besu/ethereum/forkid/ForkIdTest.java | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java index 61457b5bbce..bae8cfc339e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java @@ -45,7 +45,7 @@ public class ForkIdManager { private final Supplier chainHeadSupplier; private final long forkNext; - private final boolean onlyZerosForkBlocks; + private final boolean noForksAvailable; private final long highestKnownFork; private Bytes genesisHashCrc; private final boolean legacyEth64; @@ -77,11 +77,11 @@ public ForkIdManager( final List allForkNumbers = Stream.concat(blockNumberForks.stream(), timestampForks.stream()) .collect(Collectors.toList()); - this.onlyZerosForkBlocks = allForkNumbers.stream().allMatch(value -> 0L == value); this.forkNext = createForkIds(); this.allForkIds = Stream.concat(blockNumbersForkIds.stream(), timestampsForkIds.stream()) .collect(Collectors.toList()); + this.noForksAvailable = allForkIds.isEmpty(); this.highestKnownFork = !allForkNumbers.isEmpty() ? allForkNumbers.get(allForkNumbers.size() - 1) : 0L; } @@ -128,7 +128,7 @@ public static ForkId readFrom(final RLPInput in) { * @return boolean (peer valid (true) or invalid (false)) */ public boolean peerCheck(final ForkId forkId) { - if (forkId == null || onlyZerosForkBlocks) { + if (forkId == null || noForksAvailable) { return true; // Another method must be used to validate (i.e. genesis hash) } // Run the fork checksum validation rule set: diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java index 87f210bfa00..c9c727286cd 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java @@ -619,4 +619,18 @@ public void testGenesisTimestampEqualToShanghaiTimestamp() { assertThat(forkIdManager.getAllForkIds().get(0).getNext()).isEqualTo(2L); assertThat(forkIdManager.getAllForkIds().get(1).getNext()).isEqualTo(0L); } + + @Test + public void testNoBlockNoForksAndNoTimestampForksGreaterThanGenesisTimestamp() { + final ForkIdManager forkIdManager = + new ForkIdManager( + mockBlockchain(Hash.ZERO.toHexString(), 10L, 1L), + Collections.emptyList(), + List.of(1L), + false); + assertThat(forkIdManager.getAllForkIds().size()).isEqualTo(0); + // There is no ForkId, so peerCheck always has to return true + assertThat(forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0xdeadbeef"), 100L))) + .isEqualTo(true); + } } From fdeae23ef8b3bda016655bbe496f02822186dba1 Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Thu, 31 Aug 2023 09:42:32 +1000 Subject: [PATCH 03/34] enforce that BlobTransactions have at least one blob (#5826) * enforce that BlobTransactions have at least one blob Signed-off-by: Stefan Signed-off-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Signed-off-by: garyschulte --- .../besu/datatypes/BlobsWithCommitments.java | 8 ++- .../datatypes/BlobsWithCommitmentsTest.java | 57 ++++++++++++++++++- .../engine/AbstractEngineNewPayload.java | 2 +- .../besu/ethereum/core/Transaction.java | 15 ++--- .../ethereum/core/TransactionBuilderTest.java | 2 +- .../eth/manager/RespondingEthPeer.java | 2 +- 6 files changed, 71 insertions(+), 15 deletions(-) diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java index ed0a6dcf9a8..7a4f0f4de6c 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java @@ -38,11 +38,15 @@ public BlobsWithCommitments( final List blobs, final List kzgProofs, final List versionedHashes) { + if (blobs.size() == 0) { + throw new InvalidParameterException( + "There needs to be a minimum of one blob in a blob transaction with commitments"); + } if (blobs.size() != kzgCommitments.size() || blobs.size() != kzgProofs.size() - || kzgCommitments.size() != versionedHashes.size()) { + || blobs.size() != versionedHashes.size()) { throw new InvalidParameterException( - "There must be an equal number of blobs, commitments and proofs"); + "There must be an equal number of blobs, commitments, proofs, and versioned hashes"); } this.kzgCommitments = kzgCommitments; this.blobs = blobs; diff --git a/datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java b/datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java index fa5d3066d42..9816288e82a 100644 --- a/datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java +++ b/datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java @@ -22,19 +22,70 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.Test; public class BlobsWithCommitmentsTest { @Test - public void blobsWithCommitmentsMustHaveSameNumberOfElements() { + public void blobsWithCommitmentsMustHaveAtLeastOneBlob() { + String actualMessage = + assertThrows( + InvalidParameterException.class, + () -> new BlobsWithCommitments(List.of(), List.of(), List.of(), List.of())) + .getMessage(); + final String expectedMessage = + "There needs to be a minimum of one blob in a blob transaction with commitments"; + assertThat(actualMessage).isEqualTo(expectedMessage); + } + + @Test + public void blobsWithCommitmentsMustHaveSameNumberOfElementsVersionedHashes() { + String actualMessage = + assertThrows( + InvalidParameterException.class, + () -> + new BlobsWithCommitments( + List.of(new KZGCommitment(Bytes.of(1))), + List.of(new Blob(Bytes.EMPTY)), + List.of(new KZGProof(Bytes.EMPTY)), + List.of())) + .getMessage(); + final String expectedMessage = + "There must be an equal number of blobs, commitments, proofs, and versioned hashes"; + assertThat(actualMessage).isEqualTo(expectedMessage); + } + + @Test + public void blobsWithCommitmentsMustHaveSameNumberOfElementsKZGCommitment() { + String actualMessage = + assertThrows( + InvalidParameterException.class, + () -> + new BlobsWithCommitments( + List.of(), + List.of(new Blob(Bytes.EMPTY)), + List.of(new KZGProof(Bytes.EMPTY)), + List.of(new VersionedHash(Bytes32.rightPad(Bytes.fromHexString("0x01")))))) + .getMessage(); + final String expectedMessage = + "There must be an equal number of blobs, commitments, proofs, and versioned hashes"; + assertThat(actualMessage).isEqualTo(expectedMessage); + } + + @Test + public void blobsWithCommitmentsMustHaveSameNumberOfElementsKZGProof() { String actualMessage = assertThrows( InvalidParameterException.class, () -> new BlobsWithCommitments( - List.of(new KZGCommitment(Bytes.of(1))), List.of(), List.of(), List.of())) + List.of(new KZGCommitment(Bytes.of(1))), + List.of(new Blob(Bytes.EMPTY)), + List.of(), + List.of(new VersionedHash(Bytes32.rightPad(Bytes.fromHexString("0x01")))))) .getMessage(); - final String expectedMessage = "There must be an equal number of blobs, commitments and proofs"; + final String expectedMessage = + "There must be an equal number of blobs, commitments, proofs, and versioned hashes"; assertThat(actualMessage).isEqualTo(expectedMessage); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index d70b1cc1997..b7b42d696ca 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -209,7 +209,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) blockParam.getPrevRandao(), 0, maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null), - blockParam.getBlobGasUsed() == null ? null : blockParam.getBlobGasUsed(), + blockParam.getBlobGasUsed(), blockParam.getExcessBlobGas() == null ? null : BlobGas.fromHexString(blockParam.getExcessBlobGas()), diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 77c7ad4131f..e04d036c738 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -189,14 +189,15 @@ public Transaction( if (versionedHashes.isPresent() || maxFeePerBlobGas.isPresent()) { checkArgument( transactionType.supportsBlob(), - "Must not specify blob versioned hashes of max fee per blob gas for transaction not supporting it"); + "Must not specify blob versioned hashes or max fee per blob gas for transaction not supporting it"); } if (transactionType.supportsBlob()) { checkArgument( versionedHashes.isPresent(), "Must specify blob versioned hashes for blob transaction"); checkArgument( - !versionedHashes.get().isEmpty(), "Blob transaction must have at least one blob"); + !versionedHashes.get().isEmpty(), + "Blob transaction must have at least one versioned hash"); checkArgument( maxFeePerBlobGas.isPresent(), "Must specify max fee per blob gas for blob transaction"); } @@ -680,13 +681,13 @@ private void memoizeHashAndSize() { if (transactionType.supportsBlob()) { if (getBlobsWithCommitments().isPresent()) { - size = TransactionEncoder.encodeOpaqueBytes(this).size(); + size = bytes.size(); + return; } - } else { - final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); - TransactionEncoder.encodeForWire(transactionType, bytes, rlpOutput); - size = rlpOutput.encodedSize(); } + final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); + TransactionEncoder.encodeForWire(transactionType, bytes, rlpOutput); + size = rlpOutput.encodedSize(); } /** diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionBuilderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionBuilderTest.java index 6e5c92524d7..b06a63cb95b 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionBuilderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionBuilderTest.java @@ -73,7 +73,7 @@ public void zeroBlobTransactionIsInvalid() { .createTransaction(senderKeys); fail(); } catch (IllegalArgumentException iea) { - assertThat(iea).hasMessage("Blob transaction must have at least one blob"); + assertThat(iea).hasMessage("Blob transaction must have at least one versioned hash"); } } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/RespondingEthPeer.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/RespondingEthPeer.java index abb0d05a4f9..7427545984b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/RespondingEthPeer.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/RespondingEthPeer.java @@ -307,7 +307,7 @@ public static Responder partialResponder( final TransactionPool transactionPool, final ProtocolSchedule protocolSchedule, final float portion) { - checkArgument(portion >= 0.0 && portion <= 1.0, "Portion is in the range [0.0..1.0]"); + checkArgument(portion >= 0.0 && portion <= 1.0, "Portion is not in the range [0.0..1.0]"); final Responder fullResponder = blockchainResponder(blockchain, worldStateArchive, transactionPool); From 474250cd0ea9f0982e2c2015c3d6040bb9cddd0f Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 31 Aug 2023 08:44:17 -0700 Subject: [PATCH 04/34] Do not create ignorable segments on `revert storage-variables` (#5830) * fix the bug that creates the ignorable chain pruner segment, add rocks exception parsing to RocksDBColumnarKeyValueStorage subclasses * parse rocksdb error for unprintable column family id's Signed-off-by: garyschulte --- CHANGELOG.md | 15 ++++- .../org/hyperledger/besu/cli/BesuCommand.java | 3 +- .../storage/StorageSubCommand.java | 2 + ...imisticRocksDBColumnarKeyValueStorage.java | 2 +- .../RocksDBColumnarKeyValueStorage.java | 56 ++++++++++++++++++- ...ctionDBRocksDBColumnarKeyValueStorage.java | 2 +- .../RocksDBColumnarKeyValueStorageTest.java | 4 +- 7 files changed, 77 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60aaaf4c1b5..5c1c9f18513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 23.7.3 +### Additions and Improvements + +### Breaking Changes +- Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816) + +### Additions and Improvements + +### Bug Fixes +- do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) + +### Download Links + + ## 23.7.2 ### Additions and Improvements @@ -32,7 +46,6 @@ https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.2/besu-23.7.2.z ### Breaking Changes - Removed deprecated GoQuorum permissioning interop [#5607](https://github.com/hyperledger/besu/pull/5607) - Removed support for version 0 of the database as it is no longer used by any active node. [#5698](https://github.com/hyperledger/besu/pull/5698) -- Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816) ### Additions and Improvements - `evmtool` launcher binaries now ship as part of the standard distribution. [#5701](https://github.com/hyperledger/besu/pull/5701) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index e0330170b7f..9ccf10df966 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -3489,7 +3489,8 @@ private void setMergeConfigOptions() { getActualGenesisConfigOptions().getTerminalTotalDifficulty().isPresent()); } - private void setIgnorableStorageSegments() { + /** Set ignorable segments in RocksDB Storage Provider plugin. */ + public void setIgnorableStorageSegments() { if (!unstableChainPruningOptions.getChainDataPruningEnabled()) { rocksDBPlugin.addIgnorableSegmentIdentifier(KeyValueSegmentIdentifier.CHAIN_PRUNER_STATE); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java index f7a1a6eca11..bd40a42a431 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java @@ -99,6 +99,8 @@ public void run() { } private StorageProvider getStorageProvider() { + // init collection of ignorable segments + parentCommand.parentCommand.setIgnorableStorageSegments(); return parentCommand.parentCommand.getStorageProvider(); } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java index 13f50da388e..fa5786e6b9a 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java @@ -63,7 +63,7 @@ public OptimisticRocksDBColumnarKeyValueStorage( initColumnHandles(); } catch (final RocksDBException e) { - throw new StorageException(e); + throw parseRocksDBException(e, segments, ignorableSegments); } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index 567b3f623b9..3d98be37523 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -40,7 +40,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.google.common.base.Splitter; +import com.google.common.collect.Streams; import org.apache.commons.lang3.tuple.Pair; +import org.apache.tuweni.bytes.Bytes; import org.rocksdb.BlockBasedTableConfig; import org.rocksdb.BloomFilter; import org.rocksdb.ColumnFamilyDescriptor; @@ -161,7 +164,52 @@ public RocksDBColumnarKeyValueStorage( txOptions = new TransactionDBOptions(); columnHandles = new ArrayList<>(columnDescriptors.size()); } catch (RocksDBException e) { - throw new StorageException(e); + throw parseRocksDBException(e, defaultSegments, ignorableSegments); + } + } + + /** + * Parse RocksDBException and wrap in StorageException + * + * @param ex RocksDBException + * @param defaultSegments segments requested to open + * @param ignorableSegments segments which are ignorable if not present + * @return StorageException wrapping the RocksDB Exception + */ + protected static StorageException parseRocksDBException( + final RocksDBException ex, + final List defaultSegments, + final List ignorableSegments) { + String message = ex.getMessage(); + List knownSegments = + Streams.concat(defaultSegments.stream(), ignorableSegments.stream()).distinct().toList(); + + // parse out unprintable segment names for a more useful exception: + String columnExceptionMessagePrefix = "Column families not opened: "; + if (message.contains(columnExceptionMessagePrefix)) { + String substring = message.substring(message.indexOf(": ") + 2); + + List unHandledSegments = new ArrayList<>(); + Splitter.on(", ") + .splitToStream(substring) + .forEach( + part -> { + byte[] bytes = part.getBytes(StandardCharsets.UTF_8); + unHandledSegments.add( + knownSegments.stream() + .filter(seg -> Arrays.equals(seg.getId(), bytes)) + .findFirst() + .map(seg -> new SegmentRecord(seg.getName(), seg.getId())) + .orElse(new SegmentRecord(part, bytes)) + .forDisplay()); + }); + + return new StorageException( + "RocksDBException: Unhandled column families: [" + + unHandledSegments.stream().collect(Collectors.joining(", ")) + + "]"); + } else { + return new StorageException(ex); } } @@ -356,4 +404,10 @@ void throwIfClosed() { } abstract RocksDB getDB(); + + record SegmentRecord(String name, byte[] id) { + public String forDisplay() { + return String.format("'%s'(%s)", name, Bytes.of(id).toHexString()); + } + } } diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java index 6825a05063a..4825154561a 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java @@ -66,7 +66,7 @@ public TransactionDBRocksDBColumnarKeyValueStorage( initColumnHandles(); } catch (final RocksDBException e) { - throw new StorageException(e); + throw parseRocksDBException(e, segments, ignorableSegments); } } diff --git a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java index 827b18eb0c1..5462d239b91 100644 --- a/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java +++ b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorageTest.java @@ -222,7 +222,7 @@ public void dbShouldNotIgnoreExperimentalSegmentsIfExisted(@TempDir final Path t createSegmentedStore(testPath, Arrays.asList(TestSegment.FOO, TestSegment.BAR), List.of()); fail("DB without knowledge of experimental column family should fail"); } catch (StorageException e) { - assertThat(e.getMessage()).contains("Column families not opened"); + assertThat(e.getMessage()).contains("Unhandled column families"); } // Even if the column family is marked as ignored, as long as it exists, it will not be ignored @@ -265,7 +265,7 @@ public void dbWillBeBackwardIncompatibleAfterExperimentalSegmentsAreAdded( createSegmentedStore(testPath, Arrays.asList(TestSegment.FOO, TestSegment.BAR), List.of()); fail("DB without knowledge of experimental column family should fail"); } catch (StorageException e) { - assertThat(e.getMessage()).contains("Column families not opened"); + assertThat(e.getMessage()).contains("Unhandled column families"); } } From 1b2fbce6ce1b05cfadd4164149890ca8106976de Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:06:08 +1000 Subject: [PATCH 05/34] add versioned hashes and number of blobs to toString() (#5831) Signed-off-by: Stefan Signed-off-by: garyschulte --- .../besu/ethereum/core/Transaction.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index e04d036c738..827c9241b5e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -1091,10 +1091,26 @@ public String toString() { sb.append("value=").append(getValue()).append(", "); sb.append("sig=").append(getSignature()).append(", "); if (chainId.isPresent()) sb.append("chainId=").append(getChainId().get()).append(", "); - sb.append("payload=").append(getPayload()); if (transactionType.equals(TransactionType.ACCESS_LIST)) { - sb.append(", ").append("accessList=").append(maybeAccessList); + sb.append("accessList=").append(maybeAccessList).append(", "); + } + if (versionedHashes.isPresent()) { + final List vhs = versionedHashes.get(); + if (!vhs.isEmpty()) { + sb.append("versionedHashes=["); + sb.append( + vhs.get(0) + .toString()); // can't be empty if present, as this is checked in the constructor + for (int i = 1; i < vhs.size(); i++) { + sb.append(", ").append(vhs.get(i).toString()); + } + sb.append("], "); + } } + if (transactionType.supportsBlob() && this.blobsWithCommitments.isPresent()) { + sb.append("numberOfBlobs=").append(blobsWithCommitments.get().getBlobs().size()).append(", "); + } + sb.append("payload=").append(getPayload()); return sb.append("}").toString(); } From 827abdc13cc2b048fe85d1d97fd642877153c1af Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Tue, 5 Sep 2023 18:41:46 +1000 Subject: [PATCH 06/34] add parent beacon block root to payload id calculation (#5843) Signed-off-by: Stefan Signed-off-by: garyschulte --- .../merge/blockcreation/MergeCoordinator.java | 7 +- .../blockcreation/PayloadIdentifier.java | 7 +- .../blockcreation/PayloadIdentifierTest.java | 93 +++++++++++++++++-- .../AbstractEngineForkchoiceUpdatedTest.java | 6 +- .../engine/AbstractEngineGetPayloadTest.java | 14 ++- .../engine/EngineGetPayloadV3Test.java | 1 + 6 files changed, 115 insertions(+), 13 deletions(-) diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index 7b394b5b952..cac3edf952c 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -254,7 +254,12 @@ public PayloadIdentifier preparePayload( final PayloadIdentifier payloadIdentifier = PayloadIdentifier.forPayloadParams( - parentHeader.getBlockHash(), timestamp, prevRandao, feeRecipient, withdrawals); + parentHeader.getBlockHash(), + timestamp, + prevRandao, + feeRecipient, + withdrawals, + parentBeaconBlockRoot); if (blockCreationTasks.containsKey(payloadIdentifier)) { LOG.debug( diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifier.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifier.java index 6c946ba2ee2..ddd3c1b3e4e 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifier.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifier.java @@ -62,6 +62,7 @@ public PayloadIdentifier(final Long payloadId) { * @param prevRandao the prev randao * @param feeRecipient the fee recipient * @param withdrawals the withdrawals + * @param parentBeaconBlockRoot the parent beacon block root * @return the payload identifier */ public static PayloadIdentifier forPayloadParams( @@ -69,7 +70,8 @@ public static PayloadIdentifier forPayloadParams( final Long timestamp, final Bytes32 prevRandao, final Address feeRecipient, - final Optional> withdrawals) { + final Optional> withdrawals, + final Optional parentBeaconBlockRoot) { return new PayloadIdentifier( timestamp @@ -84,7 +86,8 @@ public static PayloadIdentifier forPayloadParams( .sorted(Comparator.comparing(Withdrawal::getIndex)) .map(Withdrawal::hashCode) .reduce(1, (a, b) -> a ^ (b * 31))) - .orElse(0)); + .orElse(0) + ^ ((long) parentBeaconBlockRoot.hashCode()) << 40); } @Override diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifierTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifierTest.java index 39597f9aabe..314224cf55d 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifierTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifierTest.java @@ -48,7 +48,12 @@ public void serializesToEvenHexRepresentation() { public void conversionCoverage() { var idTest = PayloadIdentifier.forPayloadParams( - Hash.ZERO, 1337L, Bytes32.random(), Address.fromHexString("0x42"), Optional.empty()); + Hash.ZERO, + 1337L, + Bytes32.random(), + Address.fromHexString("0x42"), + Optional.empty(), + Optional.empty()); assertThat(new PayloadIdentifier(idTest.getAsBigInteger().longValue())).isEqualTo(idTest); assertThat(new PayloadIdentifier(idTest.getAsBigInteger().longValue())).isEqualTo(idTest); } @@ -82,10 +87,20 @@ public void differentWithdrawalAmountsYieldDifferentHash() { final Bytes32 prevRandao = Bytes32.random(); var idForWithdrawals1 = PayloadIdentifier.forPayloadParams( - Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(withdrawals1)); + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.of(withdrawals1), + Optional.empty()); var idForWithdrawals2 = PayloadIdentifier.forPayloadParams( - Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(withdrawals2)); + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.of(withdrawals2), + Optional.empty()); assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2); } @@ -118,10 +133,20 @@ public void differentOrderedWithdrawalsYieldSameHash() { final Bytes32 prevRandao = Bytes32.random(); var idForWithdrawals1 = PayloadIdentifier.forPayloadParams( - Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(withdrawals1)); + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.of(withdrawals1), + Optional.empty()); var idForWithdrawals2 = PayloadIdentifier.forPayloadParams( - Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(withdrawals2)); + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.of(withdrawals2), + Optional.empty()); assertThat(idForWithdrawals1).isEqualTo(idForWithdrawals2); } @@ -130,10 +155,64 @@ public void emptyOptionalAndEmptyListWithdrawalsYieldDifferentHash() { final Bytes32 prevRandao = Bytes32.random(); var idForWithdrawals1 = PayloadIdentifier.forPayloadParams( - Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.empty()); + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.empty(), + Optional.empty()); var idForWithdrawals2 = PayloadIdentifier.forPayloadParams( - Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(emptyList())); + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.of(emptyList()), + Optional.empty()); + assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2); + } + + @Test + public void emptyOptionalAndNonEmptyParentBeaconBlockRootYieldDifferentHash() { + final Bytes32 prevRandao = Bytes32.random(); + var idForWithdrawals1 = + PayloadIdentifier.forPayloadParams( + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.empty(), + Optional.empty()); + var idForWithdrawals2 = + PayloadIdentifier.forPayloadParams( + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.empty(), + Optional.of(Bytes32.ZERO)); + assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2); + } + + @Test + public void differentParentBeaconBlockRootYieldDifferentHash() { + final Bytes32 prevRandao = Bytes32.random(); + var idForWithdrawals1 = + PayloadIdentifier.forPayloadParams( + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.empty(), + Optional.of(Bytes32.fromHexStringLenient("0x1"))); + var idForWithdrawals2 = + PayloadIdentifier.forPayloadParams( + Hash.ZERO, + 1337L, + prevRandao, + Address.fromHexString("0x42"), + Optional.empty(), + Optional.of(Bytes32.ZERO)); assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java index 32dc15ffc57..63713c4bd0f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java @@ -242,6 +242,7 @@ public void shouldReturnValidWithoutFinalizedWithPayload() { payloadParams.getTimestamp(), payloadParams.getPrevRandao(), payloadParams.getSuggestedFeeRecipient(), + Optional.empty(), Optional.empty()); when(mergeCoordinator.preparePayload( @@ -518,6 +519,7 @@ public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() { payloadParams.getTimestamp(), payloadParams.getPrevRandao(), payloadParams.getSuggestedFeeRecipient(), + Optional.empty(), Optional.empty()); when(mergeCoordinator.preparePayload( @@ -603,7 +605,8 @@ public void shouldReturnValidIfWithdrawalsIsNotNull_WhenWithdrawalsAllowed() { payloadParams.getTimestamp(), payloadParams.getPrevRandao(), payloadParams.getSuggestedFeeRecipient(), - withdrawals); + withdrawals, + Optional.empty()); when(mergeCoordinator.preparePayload( mockHeader, @@ -645,6 +648,7 @@ public void shouldReturnValidIfProtocolScheduleIsEmpty() { payloadParams.getTimestamp(), payloadParams.getPrevRandao(), payloadParams.getSuggestedFeeRecipient(), + Optional.empty(), Optional.empty()); when(mergeCoordinator.preparePayload( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java index 823cd6712ab..fd2f02ba024 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java @@ -85,7 +85,12 @@ public AbstractEngineGetPayloadTest() { protected static final BlockResultFactory factory = new BlockResultFactory(); protected static final PayloadIdentifier mockPid = PayloadIdentifier.forPayloadParams( - Hash.ZERO, 1337L, Bytes32.random(), Address.fromHexString("0x42"), Optional.empty()); + Hash.ZERO, + 1337L, + Bytes32.random(), + Address.fromHexString("0x42"), + Optional.empty(), + Optional.empty()); protected static final BlockHeader mockHeader = new BlockHeaderTestFixture().prevRandao(Bytes32.random()).buildHeader(); private static final Block mockBlock = @@ -147,7 +152,12 @@ public void shouldFailForUnknownPayloadId() { resp( getMethodName(), PayloadIdentifier.forPayloadParams( - Hash.ZERO, 0L, Bytes32.random(), Address.fromHexString("0x42"), Optional.empty())); + Hash.ZERO, + 0L, + Bytes32.random(), + Address.fromHexString("0x42"), + Optional.empty(), + Optional.empty())); assertThat(resp).isInstanceOf(JsonRpcErrorResponse.class); verify(engineCallListener, times(1)).executionEngineCalled(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java index 3fc8a6bfd83..1e19bc3fd5d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java @@ -104,6 +104,7 @@ public void shouldReturnBlockForKnownPayloadId() { cancunHardfork.milestone(), Bytes32.random(), Address.fromHexString("0x42"), + Optional.empty(), Optional.empty()); BlobTestFixture blobTestFixture = new BlobTestFixture(); From c42873b08af8e146d2c65b67f2bc8388bba6bcea Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Wed, 6 Sep 2023 10:42:27 +0200 Subject: [PATCH 07/34] bump version to 23.7.3-SNAPSHOT (#5854) Signed-off-by: Daniel Lehrner Signed-off-by: garyschulte --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 74841be4784..32a11f7cc8c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=23.7.2 +version=23.7.3-SNAPSHOT org.gradle.welcome=never # Set exports/opens flags required by Google Java Format and ErrorProne plugins. (JEP-396) From 9b37763d82827735bd9b77a8bc7b038cc78fcb40 Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 6 Sep 2023 21:24:27 +1000 Subject: [PATCH 08/34] set the beacon root address to the correct value (#5853) Signed-off-by: Stefan Signed-off-by: garyschulte --- .../hyperledger/besu/datatypes/Address.java | 22 ++++++++----------- .../mainnet/ParentBeaconBlockRootHelper.java | 20 ++++------------- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java index 6fa4de418ef..0897617c834 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java @@ -59,28 +59,24 @@ public class Address extends DelegatingBytes { public static final Address BLAKE2B_F_COMPRESSION = Address.precompiled(0x09); /** The constant KZG_POINT_EVAL aka POINT_EVALUATION_PRECOMPILE_ADDRESS. */ public static final Address KZG_POINT_EVAL = Address.precompiled(0xA); - /** The constant PARENT_BEACON_BLOCK_ROOT_REGISTRY aka HISTORY_STORAGE_ADDRESS. */ - public static final Address PARENT_BEACON_BLOCK_ROOT_REGISTRY = Address.precompiled(0xB); - // TODO: this is not a precompile anymore. The address is correct for testnet 8. Fix after testnet - // 8 when we know what the real address is /** The constant BLS12_G1ADD. */ - public static final Address BLS12_G1ADD = Address.precompiled(0xC); + public static final Address BLS12_G1ADD = Address.precompiled(0xB); /** The constant BLS12_G1MUL. */ - public static final Address BLS12_G1MUL = Address.precompiled(0xD); + public static final Address BLS12_G1MUL = Address.precompiled(0xC); /** The constant BLS12_G1MULTIEXP. */ - public static final Address BLS12_G1MULTIEXP = Address.precompiled(0xE); + public static final Address BLS12_G1MULTIEXP = Address.precompiled(0xD); /** The constant BLS12_G2ADD. */ - public static final Address BLS12_G2ADD = Address.precompiled(0xF); + public static final Address BLS12_G2ADD = Address.precompiled(0xE); /** The constant BLS12_G2MUL. */ - public static final Address BLS12_G2MUL = Address.precompiled(0x10); + public static final Address BLS12_G2MUL = Address.precompiled(0xF); /** The constant BLS12_G2MULTIEXP. */ - public static final Address BLS12_G2MULTIEXP = Address.precompiled(0x11); + public static final Address BLS12_G2MULTIEXP = Address.precompiled(0x10); /** The constant BLS12_PAIRING. */ - public static final Address BLS12_PAIRING = Address.precompiled(0x12); + public static final Address BLS12_PAIRING = Address.precompiled(0x11); /** The constant BLS12_MAP_FP_TO_G1. */ - public static final Address BLS12_MAP_FP_TO_G1 = Address.precompiled(0x13); + public static final Address BLS12_MAP_FP_TO_G1 = Address.precompiled(0x12); /** The constant BLS12_MAP_FP2_TO_G2. */ - public static final Address BLS12_MAP_FP2_TO_G2 = Address.precompiled(0x14); + public static final Address BLS12_MAP_FP2_TO_G2 = Address.precompiled(0x13); /** The constant ZERO. */ public static final Address ZERO = Address.fromHexString("0x0"); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java index 39d5b664fbe..8b9cf256aef 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java @@ -26,24 +26,13 @@ public class ParentBeaconBlockRootHelper { // Modulus use to for the timestamp to store the root public static final long HISTORICAL_ROOTS_MODULUS = 98304; - - // Address of the system user, that is used to call the contract for storing the root - // public static final Address SYSTEM_ADDRESS = - // Address.fromHexString("0xfffffffffffffffffffffffffffffffffffffffe"); - - // The address of the contract that stores the roots - // public static final Address BEACON_ROOTS_ADDRESS = - // Address.fromHexString("0x89e64Be8700cC37EB34f9209c96466DEEDc0d8a6"); + public static final Address BEACON_ROOTS_ADDRESS = + Address.fromHexString("0xbEac00dDB15f3B6d645C48263dC93862413A222D"); public static void storeParentBeaconBlockRoot( final WorldUpdater worldUpdater, final long timestamp, final Bytes32 root) { /* - pseudo code from EIP 4788: - timestamp_as_uint256 = to_uint256_be(block_header.timestamp) - parent_beacon_block_root = block_header.parent_beacon_block_root - - sstore(HISTORY_STORAGE_ADDRESS, timestamp_index, timestamp_as_uint256) - sstore(HISTORY_STORAGE_ADDRESS, root_index, parent_beacon_block_root) + see EIP-4788: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4788.md */ final long timestampReduced = timestamp % HISTORICAL_ROOTS_MODULUS; final long timestampExtended = timestampReduced + HISTORICAL_ROOTS_MODULUS; @@ -51,8 +40,7 @@ public static void storeParentBeaconBlockRoot( final UInt256 timestampIndex = UInt256.valueOf(timestampReduced); final UInt256 rootIndex = UInt256.valueOf(timestampExtended); - final MutableAccount account = - worldUpdater.getOrCreate(Address.PARENT_BEACON_BLOCK_ROOT_REGISTRY).getMutable(); + final MutableAccount account = worldUpdater.getOrCreate(BEACON_ROOTS_ADDRESS).getMutable(); account.setStorageValue(timestampIndex, UInt256.valueOf(timestamp)); account.setStorageValue(rootIndex, UInt256.fromBytes(root)); worldUpdater.commit(); From 476617c2a8a93ef05de90547a871a975d7d73ff2 Mon Sep 17 00:00:00 2001 From: Peter Somogyvari Date: Wed, 6 Sep 2023 17:56:03 -0700 Subject: [PATCH 09/34] docs(readme): fix broken link to installation of binaries page (#5859) Fixes #5858 Signed-off-by: Peter Somogyvari Signed-off-by: garyschulte --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 98560c66ed6..38eb3e7725f 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ If you have any questions, queries or comments, [Besu channel on Hyperledger Dis ## Besu Users -To install the Besu binary, follow [these instructions](https://besu.hyperledger.org/HowTo/Get-Started/Install-Binaries/). +To install the Besu binary, follow [these instructions](https://besu.hyperledger.org/public-networks/get-started/install/binary-distribution). ## Besu Developers From 0d5a643ec9f6ff510b6249acb8917796d47e403b Mon Sep 17 00:00:00 2001 From: ahamlat Date: Thu, 7 Sep 2023 05:23:23 +0200 Subject: [PATCH 10/34] Update RocksDB version from 8.0.0 to 8.3.2 (#5832) Signed-off-by: Ameziane H Co-authored-by: Sally MacFarlane Signed-off-by: garyschulte --- gradle/verification-metadata.xml | 8 ++++++++ gradle/versions.gradle | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index cd2a9ded305..82f6b48f02c 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5731,6 +5731,14 @@ + + + + + + + + diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 54c62d8f251..dc6bdb97da9 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -206,7 +206,7 @@ dependencyManagement { dependency 'org.owasp.encoder:encoder:1.2.3' - dependency 'org.rocksdb:rocksdbjni:8.0.0' + dependency 'org.rocksdb:rocksdbjni:8.3.2' dependencySet(group: 'org.slf4j', version:'2.0.7') { entry 'slf4j-api' From 486eaadec251c7e41498190848b338e7604819f3 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 7 Sep 2023 14:34:39 +1000 Subject: [PATCH 11/34] use non-deprecated authenticate methods (#5852) Signed-off-by: Sally MacFarlane Signed-off-by: garyschulte --- .../authentication/DefaultAuthenticationService.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/DefaultAuthenticationService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/DefaultAuthenticationService.java index 4cdc96e14af..96a1a2d023f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/DefaultAuthenticationService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/DefaultAuthenticationService.java @@ -33,6 +33,9 @@ import io.vertx.ext.auth.JWTOptions; import io.vertx.ext.auth.User; import io.vertx.ext.auth.authentication.AuthenticationProvider; +import io.vertx.ext.auth.authentication.Credentials; +import io.vertx.ext.auth.authentication.TokenCredentials; +import io.vertx.ext.auth.authentication.UsernamePasswordCredentials; import io.vertx.ext.auth.jwt.JWTAuth; import io.vertx.ext.auth.jwt.JWTAuthOptions; import io.vertx.ext.web.RoutingContext; @@ -166,7 +169,7 @@ public void handleLogin(final RoutingContext routingContext) { private void login( final RoutingContext routingContext, final AuthenticationProvider credentialAuthProvider) { - final JsonObject requestBody = routingContext.getBodyAsJson(); + final JsonObject requestBody = routingContext.body().asJsonObject(); if (requestBody == null) { routingContext @@ -181,8 +184,10 @@ private void login( final JsonObject authParams = new JsonObject(); authParams.put(USERNAME, requestBody.getValue(USERNAME)); authParams.put("password", requestBody.getValue("password")); + final Credentials credentials = new UsernamePasswordCredentials(authParams); + credentialAuthProvider.authenticate( - authParams, + credentials, r -> { if (r.failed()) { routingContext @@ -227,7 +232,7 @@ public void authenticate(final String token, final Handler> handl try { getJwtAuthProvider() .authenticate( - new JsonObject().put("token", token), + new TokenCredentials(new JsonObject().put("token", token)), r -> { if (r.succeeded()) { final Optional user = Optional.ofNullable(r.result()); From 2326df424bf59e4701719a2b24591ab9c5745aad Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 7 Sep 2023 15:51:42 -0700 Subject: [PATCH 12/34] move to Hyperledger shared runners for current github actions (#5860) Signed-off-by: garyschulte --- .github/workflows/checks.yml | 4 ++-- .github/workflows/codeql.yml | 2 +- .github/workflows/dco-merge-group.yml | 4 ++-- .github/workflows/dco.yml | 4 ++-- .github/workflows/gradle-wrapper-validation.yml | 2 +- .github/workflows/pr-checklist-on-open.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/repolinter.yml | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index c72331b84e8..9fdae30a99b 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -7,7 +7,7 @@ on: jobs: spotless: - runs-on: [besu,Linux,self-hosted,X64,nodocker] + runs-on: [besu-research-ubuntu-16] if: ${{ github.actor != 'dependabot[bot]' }} steps: - name: Checkout Repo @@ -21,7 +21,7 @@ jobs: - name: spotless run: ./gradlew --no-daemon --parallel clean spotlessCheck javadoc_17: - runs-on: [besu,Linux,self-hosted,X64,nodocker] + runs-on: [besu-research-ubuntu-8] if: ${{ github.actor != 'dependabot[bot]' }} steps: - name: Checkout Repo diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0e170cfb288..100be39e0df 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,7 +24,7 @@ on: jobs: analyze: name: Analyze - runs-on: [besu,Linux,self-hosted,X64,nodocker] + runs-on: [besu-research-ubuntu-16] permissions: actions: read contents: read diff --git a/.github/workflows/dco-merge-group.yml b/.github/workflows/dco-merge-group.yml index f93170b1c24..fee29b6c5d7 100644 --- a/.github/workflows/dco-merge-group.yml +++ b/.github/workflows/dco-merge-group.yml @@ -4,7 +4,7 @@ on: jobs: dco: - runs-on: [besu,Linux,self-hosted,nodocker] + runs-on: [besu-research-ubuntu-8] if: ${{ github.actor != 'dependabot[bot]' }} steps: - - run: echo "This DCO job runs on merge_queue event and doesn't check PR contents" \ No newline at end of file + - run: echo "This DCO job runs on merge_queue event and doesn't check PR contents" diff --git a/.github/workflows/dco.yml b/.github/workflows/dco.yml index 341e1d38776..5fa9931c77a 100644 --- a/.github/workflows/dco.yml +++ b/.github/workflows/dco.yml @@ -5,7 +5,7 @@ on: jobs: dco: - runs-on: [besu,Linux,self-hosted,nodocker] + runs-on: [besu-research-ubuntu-8] if: ${{ github.actor != 'dependabot[bot]' }} steps: - run: echo "This DCO job runs on pull_request event and workflow_dispatch" @@ -17,4 +17,4 @@ jobs: - name: DCO Check uses: tim-actions/dco@v1.1.0 with: - commits: ${{ steps.get-pr-commits.outputs.commits }} \ No newline at end of file + commits: ${{ steps.get-pr-commits.outputs.commits }} diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index bb0feddd1e8..2be77e8c2ea 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -5,7 +5,7 @@ on: [push, pull_request] jobs: validation: name: "Gradle Wrapper Validation" - runs-on: [besu,Linux,self-hosted,nodocker] + runs-on: [besu-research-ubuntu-8] steps: - uses: actions/checkout@v3 - uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/pr-checklist-on-open.yml b/.github/workflows/pr-checklist-on-open.yml index d89748a9437..3a4d4342c58 100644 --- a/.github/workflows/pr-checklist-on-open.yml +++ b/.github/workflows/pr-checklist-on-open.yml @@ -6,7 +6,7 @@ on: jobs: checklist: name: "add checklist as a comment on newly opened PRs" - runs-on: [besu,Linux,self-hosted,nodocker] + runs-on: [besu-research-ubuntu-8] steps: - uses: actions/github-script@v5 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 36ea3ab50fe..5c9b2328208 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,7 @@ on: types: released jobs: dockerPromoteX64: - runs-on: [besu,Linux,self-hosted,nodocker] + runs-on: [besu-research-ubuntu-16] steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 diff --git a/.github/workflows/repolinter.yml b/.github/workflows/repolinter.yml index 39b0d6cab39..e1c61cadea8 100644 --- a/.github/workflows/repolinter.yml +++ b/.github/workflows/repolinter.yml @@ -15,7 +15,7 @@ on: jobs: build: - runs-on: [besu,Linux,self-hosted,X64,docker] + runs-on: [besu-research-ubuntu-16] container: ghcr.io/todogroup/repolinter:v0.10.1 steps: - name: Checkout Code From d4ae08f4a82e5bb5f2843cdcb7e05afd9c8e6c7c Mon Sep 17 00:00:00 2001 From: matkt Date: Fri, 8 Sep 2023 21:10:43 +0200 Subject: [PATCH 13/34] Add range tracing with worldstate (#5844) Implement a method to trace a range of blocks and have access to the worldstate before and after the tracing Signed-off-by: Karim TAAM Signed-off-by: garyschulte --- .../besu/services/TraceServiceImpl.java | 150 ++++++++++++------ .../besu/services/TraceServiceImplTest.java | 105 ++++++++++++ .../jsonrpc/internal/methods/TraceBlock.java | 5 + plugin-api/build.gradle | 2 +- .../besu/plugin/services/TraceService.java | 19 +++ .../tracer/BlockAwareOperationTracer.java | 7 + 6 files changed, 238 insertions(+), 50 deletions(-) create mode 100644 besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java diff --git a/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java index f98e96c15af..8b27108191f 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.services.TraceService; import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; @@ -38,6 +39,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; +import java.util.stream.LongStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -88,61 +91,110 @@ public void traceBlock(final Hash hash, final BlockAwareOperationTracer tracer) block.ifPresent(value -> trace(value, tracer)); } - private void trace(final Block block, final BlockAwareOperationTracer tracer) { - LOG.debug("Tracing block {}", block.toLogString()); - final List results = new ArrayList<>(); + /** + * Traces range of blocks + * + * @param fromBlockNumber the beginning of the range (inclusive) + * @param toBlockNumber the end of the range (inclusive) + * @param beforeTracing Function which performs an operation on a MutableWorldState before tracing + * @param afterTracing Function which performs an operation on a MutableWorldState after tracing + * @param tracer an instance of OperationTracer + */ + @Override + public void trace( + final long fromBlockNumber, + final long toBlockNumber, + final Consumer beforeTracing, + final Consumer afterTracing, + final BlockAwareOperationTracer tracer) { + checkArgument(tracer != null); + LOG.debug("Tracing from block {} to block {}", fromBlockNumber, toBlockNumber); + final Blockchain blockchain = blockchainQueries.getBlockchain(); + final List blocks = + LongStream.rangeClosed(fromBlockNumber, toBlockNumber) + .mapToObj( + number -> + blockchain + .getBlockByNumber(number) + .orElseThrow(() -> new RuntimeException("Block not found " + number))) + .toList(); Tracer.processTracing( blockchainQueries, - block.getHash(), + blocks.get(0).getHash(), traceableState -> { - final Blockchain blockchain = blockchainQueries.getBlockchain(); - final ChainUpdater chainUpdater = new ChainUpdater(traceableState); - final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(block.getHeader()); - final MainnetTransactionProcessor transactionProcessor = - protocolSpec.getTransactionProcessor(); - final BlockHeader header = block.getHeader(); - - tracer.traceStartBlock(block.getHeader(), block.getBody()); - - block - .getBody() - .getTransactions() - .forEach( - transaction -> { - final Optional maybeParentHeader = - blockchain.getBlockHeader(header.getParentHash()); - final Wei blobGasPrice = - protocolSpec - .getFeeMarket() - .blobGasPricePerGas( - maybeParentHeader - .map( - parent -> - calculateExcessBlobGasForParent(protocolSpec, parent)) - .orElse(BlobGas.ZERO)); - - tracer.traceStartTransaction(transaction); - - final TransactionProcessingResult result = - transactionProcessor.processTransaction( - blockchain, - chainUpdater.getNextUpdater(), - header, - transaction, - header.getCoinbase(), - tracer, - new CachingBlockHashLookup(header, blockchain), - false, - blobGasPrice); - - long transactionGasUsed = transaction.getGasLimit() - result.getGasRemaining(); - tracer.traceEndTransaction(result.getOutput(), transactionGasUsed, 0); - - results.add(result); - }); + final WorldUpdater worldStateUpdater = traceableState.updater(); + final ChainUpdater chainUpdater = new ChainUpdater(traceableState, worldStateUpdater); + beforeTracing.accept(worldStateUpdater); + final List results = new ArrayList<>(); + blocks.forEach( + block -> { + results.addAll(trace(blockchain, block, chainUpdater, tracer)); + tracer.traceEndBlock(block.getHeader(), block.getBody()); + }); + afterTracing.accept(chainUpdater.getNextUpdater()); return Optional.of(results); }); + } + private void trace(final Block block, final BlockAwareOperationTracer tracer) { + LOG.debug("Tracing block {}", block.toLogString()); + final Blockchain blockchain = blockchainQueries.getBlockchain(); + Tracer.processTracing( + blockchainQueries, + block.getHash(), + traceableState -> + Optional.of(trace(blockchain, block, new ChainUpdater(traceableState), tracer))); tracer.traceEndBlock(block.getHeader(), block.getBody()); } + + private List trace( + final Blockchain blockchain, + final Block block, + final ChainUpdater chainUpdater, + final BlockAwareOperationTracer tracer) { + final List results = new ArrayList<>(); + final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(block.getHeader()); + final MainnetTransactionProcessor transactionProcessor = protocolSpec.getTransactionProcessor(); + final BlockHeader header = block.getHeader(); + tracer.traceStartBlock(block.getHeader(), block.getBody()); + + block + .getBody() + .getTransactions() + .forEach( + transaction -> { + final Optional maybeParentHeader = + blockchain.getBlockHeader(header.getParentHash()); + final Wei blobGasPrice = + protocolSpec + .getFeeMarket() + .blobGasPricePerGas( + maybeParentHeader + .map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); + + tracer.traceStartTransaction(transaction); + + final TransactionProcessingResult result = + transactionProcessor.processTransaction( + blockchain, + chainUpdater.getNextUpdater(), + header, + transaction, + header.getCoinbase(), + tracer, + new CachingBlockHashLookup(header, blockchain), + false, + blobGasPrice); + + long transactionGasUsed = transaction.getGasLimit() - result.getGasRemaining(); + tracer.traceEndTransaction(result.getOutput(), transactionGasUsed, 0); + + results.add(result); + }); + + tracer.traceEndBlock(block.getHeader(), block.getBody()); + + return results; + } } diff --git a/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java new file mode 100644 index 00000000000..0c8acd6a190 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java @@ -0,0 +1,105 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.services; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; +import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.plugin.services.TraceService; +import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +class TraceServiceImplTest { + + TraceService traceService; + private MutableBlockchain blockchain; + private WorldStateArchive worldStateArchive; + private BlockchainQueries blockchainQueries; + + /** + * The blockchain for testing has a height of 32 and the account + * 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b makes a transaction per block. So, in the head, the + * nonce of this account should be 32. + */ + @BeforeEach + public void setup() { + final BlockchainSetupUtil blockchainSetupUtil = + BlockchainSetupUtil.forTesting(DataStorageFormat.BONSAI); + blockchainSetupUtil.importAllBlocks(); + blockchain = blockchainSetupUtil.getBlockchain(); + worldStateArchive = blockchainSetupUtil.getWorldArchive(); + blockchainQueries = new BlockchainQueries(blockchain, worldStateArchive); + traceService = + new TraceServiceImpl(blockchainQueries, blockchainSetupUtil.getProtocolSchedule()); + } + + @Test + void shouldRetrieveStateUpdatePostTracingForOneBlock() { + + final Address addressToVerify = + Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); + + final long persistedNonceForAccount = + worldStateArchive.getMutable().get(addressToVerify).getNonce(); + + traceService.trace( + 2, + 2, + worldState -> { + assertThat(worldState.get(addressToVerify).getNonce()).isEqualTo(1); + }, + worldState -> { + assertThat(worldState.get(addressToVerify).getNonce()).isEqualTo(2); + }, + BlockAwareOperationTracer.NO_TRACING); + + assertThat(worldStateArchive.getMutable().get(addressToVerify).getNonce()) + .isEqualTo(persistedNonceForAccount); + } + + @Test + void shouldRetrieveStateUpdatePostTracingForAllBlocks() { + final Address addressToVerify = + Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); + + final long persistedNonceForAccount = + worldStateArchive.getMutable().get(addressToVerify).getNonce(); + + traceService.trace( + 0, + 32, + worldState -> { + assertThat(worldState.get(addressToVerify).getNonce()).isEqualTo(0); + }, + worldState -> { + assertThat(worldState.get(addressToVerify).getNonce()) + .isEqualTo(persistedNonceForAccount); + }, + BlockAwareOperationTracer.NO_TRACING); + + assertThat(worldStateArchive.getMutable().get(addressToVerify).getNonce()) + .isEqualTo(persistedNonceForAccount); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceBlock.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceBlock.java index a6125f393aa..6ac03eb91a1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceBlock.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceBlock.java @@ -199,6 +199,11 @@ public ChainUpdater(final MutableWorldState worldState) { this.worldState = worldState; } + public ChainUpdater(final MutableWorldState worldState, final WorldUpdater updater) { + this.worldState = worldState; + this.updater = updater; + } + public WorldUpdater getNextUpdater() { // if we have no prior updater, it must be the first TX, so use the block's initial state if (updater == null) { diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 4e8c697e158..aedc706bab1 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -69,7 +69,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'W/4RHhLwUOWYDqwT3oZVKdRAnu/CEFCtqNDOT9cdPNk=' + knownHash = 'fPOd/MnNB1PwfTV7HDTXc3oYRcoeUzMJrlzDUdg/HNk=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TraceService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TraceService.java index e49057d6bfc..0b4809544ab 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TraceService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TraceService.java @@ -15,9 +15,12 @@ package org.hyperledger.besu.plugin.services; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; +import java.util.function.Consumer; + /** The Trace service interface */ @Unstable public interface TraceService extends BesuService { @@ -36,4 +39,20 @@ public interface TraceService extends BesuService { * @param tracer the tracer (OperationTracer) */ void traceBlock(Hash hash, BlockAwareOperationTracer tracer); + + /** + * Traces range of blocks + * + * @param fromBlockNumber the beginning of the range (inclusive) + * @param toBlockNumber the end of the range (inclusive) + * @param beforeTracing Function which performs an operation on a MutableWorldState before tracing + * @param afterTracing Function which performs an operation on a MutableWorldState after tracing + * @param tracer an instance of OperationTracer + */ + void trace( + final long fromBlockNumber, + final long toBlockNumber, + final Consumer beforeTracing, + final Consumer afterTracing, + final BlockAwareOperationTracer tracer); } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java index 037f7325dc4..846f783b5fd 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java @@ -24,6 +24,13 @@ *

In both methods, the block header and body are provided. */ public interface BlockAwareOperationTracer extends OperationTracer { + + /** + * BlockAwareOperationTracer object with no tracing functionality. This serves as a default for + * scenarios where no specific tracing operation is required. + */ + BlockAwareOperationTracer NO_TRACING = new BlockAwareOperationTracer() {}; + /** * Trace the start of a block. * From 241237973429018020b2438e4a2af95598200b6f Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Mon, 11 Sep 2023 12:16:18 +0200 Subject: [PATCH 14/34] Layered txpool by default and txpool options hoverhaul (#5772) Signed-off-by: Fabio Di Fabio Signed-off-by: garyschulte --- CHANGELOG.md | 6 +- .../org/hyperledger/besu/cli/BesuCommand.java | 127 ++------- .../cli/ConfigurationOverviewBuilder.java | 15 +- .../besu/cli/DefaultCommandValues.java | 4 - .../converter/DurationMillisConverter.java | 44 +++ .../besu/cli/converter/FractionConverter.java | 6 +- .../cli/converter/PercentageConverter.java | 6 +- .../besu/cli/converter/TypeFormatter.java | 31 +++ .../DurationConversionException.java | 39 +++ .../besu/cli/options/OptionParser.java | 45 +++ .../stable/TransactionPoolOptions.java | 263 ++++++++++++++++++ .../unstable/TransactionPoolOptions.java | 122 ++------ .../besu/cli/util/CommandLineUtils.java | 104 +++++++ .../util/TomlConfigFileDefaultProvider.java | 3 + .../hyperledger/besu/cli/BesuCommandTest.java | 187 ------------- .../besu/cli/CommandTestAbstract.java | 7 +- .../cli/ConfigurationOverviewBuilderTest.java | 22 +- .../cli/converter/FractionConverterTest.java | 5 +- .../converter/PercentageConverterTest.java | 5 +- .../cli/options/AbstractCLIOptionsTest.java | 27 +- .../cli/options/EthProtocolOptionsTest.java | 9 +- .../cli/options/MetricsCLIOptionsTest.java | 9 +- .../cli/options/NetworkingOptionsTest.java | 8 +- .../besu/cli/options/OptionParserTest.java | 21 ++ .../cli/options/SynchronizerOptionsTest.java | 8 +- .../options/TransactionPoolOptionsTest.java | 155 ----------- .../stable/TransactionPoolOptionsTest.java | 243 ++++++++++++++++ .../unstable/TransactionPoolOptionsTest.java | 105 +++++++ .../controller/BesuControllerBuilderTest.java | 11 +- .../MergeBesuControllerBuilderTest.java | 11 +- .../QbftBesuControllerBuilderTest.java | 11 +- .../src/test/resources/everything_config.toml | 13 +- .../blockcreation/MergeCoordinatorTest.java | 3 +- ...FeeMarketBlockTransactionSelectorTest.java | 3 +- ...FeeMarketBlockTransactionSelectorTest.java | 3 +- ...oledTransactionHashesMessageProcessor.java | 8 +- .../TransactionPoolConfiguration.java | 57 ++-- .../transactions/TransactionPoolFactory.java | 22 +- .../layered/AbstractTransactionsLayer.java | 1 + .../BaseFeePrioritizedTransactions.java | 24 +- ...TransactionHashesMessageProcessorTest.java | 8 +- .../TransactionPoolFactoryTest.java | 53 +++- .../TransactionPoolLegacyTest.java | 3 +- .../TransactionPoolLondonTest.java | 3 +- .../AbstractPendingTransactionsTestBase.java | 12 +- .../ethereum/retesteth/RetestethContext.java | 3 +- 46 files changed, 1184 insertions(+), 691 deletions(-) create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/converter/DurationMillisConverter.java create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/converter/TypeFormatter.java create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/converter/exception/DurationConversionException.java create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptions.java delete mode 100644 besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java create mode 100644 besu/src/test/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptionsTest.java create mode 100644 besu/src/test/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptionsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c1c9f18513..6ed641a1b06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,15 @@ ### Breaking Changes - Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816) +- Layered transaction pool implementation is now stable and enabled by default, so the following changes to experimental options have been done [#5772](https://github.com/hyperledger/besu): + - `--Xlayered-tx-pool` is gone, to select the implementation use the new `--tx-pool` option with values `layered` (default) or `legacy` + - `--Xlayered-tx-pool-layer-max-capacity`, `--Xlayered-tx-pool-max-prioritized` and `--Xlayered-tx-pool-max-future-by-sender` just drop the `X` and keep the same behavior ### Additions and Improvements +- Layered transaction pool implementation is now stable and enabled by default. If you want still to use the legacy implementation, use `--tx-pool=legacy` [#5772](https://github.com/hyperledger/besu) ### Bug Fixes -- do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) +- do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) ### Download Links diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 9ccf10df966..2538a1d7056 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -46,7 +46,6 @@ import org.hyperledger.besu.chainimport.RlpBlockImporter; import org.hyperledger.besu.cli.config.EthNetworkConfig; import org.hyperledger.besu.cli.config.NetworkName; -import org.hyperledger.besu.cli.converter.FractionConverter; import org.hyperledger.besu.cli.converter.MetricCategoryConverter; import org.hyperledger.besu.cli.converter.PercentageConverter; import org.hyperledger.besu.cli.custom.CorsAllowedOriginsProperty; @@ -59,6 +58,7 @@ import org.hyperledger.besu.cli.options.stable.LoggingLevelOption; import org.hyperledger.besu.cli.options.stable.NodePrivateKeyFileOption; import org.hyperledger.besu.cli.options.stable.P2PTLSConfigOptions; +import org.hyperledger.besu.cli.options.stable.TransactionPoolOptions; import org.hyperledger.besu.cli.options.unstable.ChainPruningOptions; import org.hyperledger.besu.cli.options.unstable.DnsOptions; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; @@ -73,7 +73,6 @@ import org.hyperledger.besu.cli.options.unstable.PrivacyPluginOptions; import org.hyperledger.besu.cli.options.unstable.RPCOptions; import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions; -import org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions; import org.hyperledger.besu.cli.presynctasks.PreSynchronizationTaskRunner; import org.hyperledger.besu.cli.presynctasks.PrivateDatabaseMigrationPreSyncTask; import org.hyperledger.besu.cli.subcommands.PasswordSubCommand; @@ -127,6 +126,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.mainnet.FrontierTargetingGasLimitCalculator; import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration; @@ -280,7 +280,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable { final SynchronizerOptions unstableSynchronizerOptions = SynchronizerOptions.create(); final EthProtocolOptions unstableEthProtocolOptions = EthProtocolOptions.create(); final MetricsCLIOptions unstableMetricsCLIOptions = MetricsCLIOptions.create(); - final TransactionPoolOptions unstableTransactionPoolOptions = TransactionPoolOptions.create(); + final org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions + unstableTransactionPoolOptions = + org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions.create(); private final DnsOptions unstableDnsOptions = DnsOptions.create(); private final MiningOptions unstableMiningOptions = MiningOptions.create(); private final NatOptions unstableNatOptions = NatOptions.create(); @@ -298,6 +300,10 @@ public class BesuCommand implements DefaultCommandValues, Runnable { NodePrivateKeyFileOption.create(); private final LoggingLevelOption loggingLevelOption = LoggingLevelOption.create(); + @CommandLine.ArgGroup(validate = false, heading = "@|bold Tx Pool Common Options|@%n") + final org.hyperledger.besu.cli.options.stable.TransactionPoolOptions + stableTransactionPoolOptions = TransactionPoolOptions.create(); + private final RunnerBuilder runnerBuilder; private final BesuController.Builder controllerBuilderFactory; private final BesuPluginContextImpl besuPluginContext; @@ -454,10 +460,8 @@ static class P2PDiscoveryOptionGroup { "The maximum percentage of P2P connections that can be initiated remotely. Must be between 0 and 100 inclusive. (default: ${DEFAULT-VALUE})", arity = "1", converter = PercentageConverter.class) - private final Integer maxRemoteConnectionsPercentage = - Fraction.fromFloat(DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED) - .toPercentage() - .getValue(); + private final Percentage maxRemoteConnectionsPercentage = + Fraction.fromFloat(DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED).toPercentage(); @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. @CommandLine.Option( @@ -1111,13 +1115,6 @@ static class MinerOptionGroup { arity = "1") private final Wei minTransactionGasPrice = DEFAULT_MIN_TRANSACTION_GAS_PRICE; - @Option( - names = {"--rpc-tx-feecap"}, - description = - "Maximum transaction fees (in Wei) accepted for transaction submitted through RPC (default: ${DEFAULT-VALUE})", - arity = "1") - private final Wei txFeeCap = DEFAULT_RPC_TX_FEE_CAP; - @Option( names = {"--min-block-occupancy-ratio"}, description = "Minimum occupancy ratio for a mined block (default: ${DEFAULT-VALUE})", @@ -1209,75 +1206,6 @@ static class PermissionsOptionGroup { "Sets target gas limit per block. If set, each block's gas limit will approach this setting over time if the current gas limit is different.") private final Long targetGasLimit = null; - // Tx Pool Option Group - @CommandLine.ArgGroup(validate = false, heading = "@|bold Tx Pool Options|@%n") - TxPoolOptionGroup txPoolOptionGroup = new TxPoolOptionGroup(); - - static class TxPoolOptionGroup { - @CommandLine.Option( - names = {"--tx-pool-disable-locals"}, - paramLabel = "", - description = - "Set to true if transactions sent via RPC should have the same checks and not be prioritized over remote ones (default: ${DEFAULT-VALUE})", - fallbackValue = "true", - arity = "0..1") - private Boolean disableLocalTxs = TransactionPoolConfiguration.DEFAULT_DISABLE_LOCAL_TXS; - - @CommandLine.Option( - names = {"--tx-pool-enable-save-restore"}, - paramLabel = "", - description = - "Set to true to enable saving the txpool content to file on shutdown and reloading it on startup (default: ${DEFAULT-VALUE})", - fallbackValue = "true", - arity = "0..1") - private Boolean saveRestoreEnabled = TransactionPoolConfiguration.DEFAULT_ENABLE_SAVE_RESTORE; - - @CommandLine.Option( - names = {"--tx-pool-limit-by-account-percentage"}, - paramLabel = "", - converter = FractionConverter.class, - description = - "Maximum portion of the transaction pool which a single account may occupy with future transactions (default: ${DEFAULT-VALUE})", - arity = "1") - private Float txPoolLimitByAccountPercentage = - TransactionPoolConfiguration.DEFAULT_LIMIT_TX_POOL_BY_ACCOUNT_PERCENTAGE; - - @CommandLine.Option( - names = {"--tx-pool-save-file"}, - paramLabel = "", - description = - "If saving the txpool content is enabled, define a custom path for the save file (default: ${DEFAULT-VALUE} in the data-dir)", - arity = "1") - private File saveFile = TransactionPoolConfiguration.DEFAULT_SAVE_FILE; - - @Option( - names = {"--tx-pool-max-size"}, - paramLabel = MANDATORY_INTEGER_FORMAT_HELP, - description = - "Maximum number of pending transactions that will be kept in the transaction pool (default: ${DEFAULT-VALUE})", - arity = "1") - private final Integer txPoolMaxSize = - TransactionPoolConfiguration.DEFAULT_MAX_PENDING_TRANSACTIONS; - - @Option( - names = {"--tx-pool-retention-hours"}, - paramLabel = MANDATORY_INTEGER_FORMAT_HELP, - description = - "Maximum retention period of pending transactions in hours (default: ${DEFAULT-VALUE})", - arity = "1") - private final Integer pendingTxRetentionPeriod = - TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS; - - @Option( - names = {"--tx-pool-price-bump"}, - paramLabel = MANDATORY_INTEGER_FORMAT_HELP, - converter = PercentageConverter.class, - description = - "Price bump percentage to replace an already existing transaction (default: ${DEFAULT-VALUE})", - arity = "1") - private final Integer priceBump = TransactionPoolConfiguration.DEFAULT_PRICE_BUMP.getValue(); - } - @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. @Option( names = {"--key-value-storage"}, @@ -1906,10 +1834,15 @@ private void validateOptions() { validateRpcOptionsParams(); validateChainDataPruningParams(); validatePostMergeCheckpointBlockRequirements(); + validateTransactionPoolOptions(); p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine); pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine); } + private void validateTransactionPoolOptions() { + stableTransactionPoolOptions.validate(commandLine); + } + private void validateRequiredOptions() { commandLine .getCommandSpec() @@ -2987,28 +2920,14 @@ private SynchronizerConfiguration buildSyncConfig() { } private TransactionPoolConfiguration buildTransactionPoolConfiguration() { - return unstableTransactionPoolOptions - .toDomainObject() - .enableSaveRestore(txPoolOptionGroup.saveRestoreEnabled) - .disableLocalTransactions(txPoolOptionGroup.disableLocalTxs) - .txPoolLimitByAccountPercentage(txPoolOptionGroup.txPoolLimitByAccountPercentage) - .txPoolMaxSize(txPoolOptionGroup.txPoolMaxSize) - .pendingTxRetentionPeriod(txPoolOptionGroup.pendingTxRetentionPeriod) - .priceBump(Percentage.fromInt(txPoolOptionGroup.priceBump)) - .txFeeCap(txFeeCap) - .saveFile(dataPath.resolve(txPoolOptionGroup.saveFile.getPath()).toFile()) + final var stableTxPoolOption = stableTransactionPoolOptions.toDomainObject(); + return ImmutableTransactionPoolConfiguration.builder() + .from(stableTxPoolOption) + .unstable(unstableTransactionPoolOptions.toDomainObject()) + .saveFile((dataPath.resolve(stableTxPoolOption.getSaveFile().getPath()).toFile())) .build(); } - /** - * Return the file where to save txpool content if the relative option is enabled. - * - * @return the save file - */ - public File getSaveFile() { - return txPoolOptionGroup.saveFile; - } - private boolean isPruningEnabled() { return pruningEnabled; } @@ -3613,9 +3532,7 @@ private String generateConfigurationOverview() { builder.setHighSpecEnabled(); } - if (buildTransactionPoolConfiguration().getLayeredTxPoolEnabled()) { - builder.setLayeredTxPoolEnabled(); - } + builder.setTxPoolImplementation(buildTransactionPoolConfiguration().getTxPoolImplementation()); return builder.build(); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java b/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java index 2cd374a2f57..5bd1d84a298 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.cli; import org.hyperledger.besu.BesuInfo; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.util.log.FramedLogMessage; import org.hyperledger.besu.util.platform.PlatformDetector; @@ -47,7 +48,7 @@ public class ConfigurationOverviewBuilder { private Collection engineApis; private String engineJwtFilePath; private boolean isHighSpec = false; - private boolean isLayeredTxPool = false; + private TransactionPoolConfiguration.Implementation txPoolImplementation; private Map environment; /** @@ -167,12 +168,14 @@ public ConfigurationOverviewBuilder setHighSpecEnabled() { } /** - * Sets experimental layered txpool enabled. + * Sets the txpool implementation in use. * + * @param implementation the txpool implementation * @return the builder */ - public ConfigurationOverviewBuilder setLayeredTxPoolEnabled() { - isLayeredTxPool = true; + public ConfigurationOverviewBuilder setTxPoolImplementation( + final TransactionPoolConfiguration.Implementation implementation) { + txPoolImplementation = implementation; return this; } @@ -251,9 +254,7 @@ public String build() { lines.add("Experimental high spec configuration enabled"); } - if (isLayeredTxPool) { - lines.add("Experimental layered transaction pool configuration enabled"); - } + lines.add("Using " + txPoolImplementation + " transaction pool implementation"); lines.add(""); lines.add("Host:"); diff --git a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java index 887e6120419..8b837268327 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java @@ -16,7 +16,6 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; -import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration; import org.hyperledger.besu.nat.NatMethod; @@ -61,9 +60,6 @@ public interface DefaultCommandValues { String MANDATORY_NODE_ID_FORMAT_HELP = ""; /** The constant DEFAULT_MIN_TRANSACTION_GAS_PRICE. */ Wei DEFAULT_MIN_TRANSACTION_GAS_PRICE = Wei.of(1000); - /** The constant DEFAULT_RPC_TX_FEE_CAP. */ - Wei DEFAULT_RPC_TX_FEE_CAP = TransactionPoolConfiguration.DEFAULT_RPC_TX_FEE_CAP; - /** The constant DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO. */ Double DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO = 0.8; /** The constant DEFAULT_EXTRA_DATA. */ diff --git a/besu/src/main/java/org/hyperledger/besu/cli/converter/DurationMillisConverter.java b/besu/src/main/java/org/hyperledger/besu/cli/converter/DurationMillisConverter.java new file mode 100644 index 00000000000..bfaffa8826a --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/converter/DurationMillisConverter.java @@ -0,0 +1,44 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.converter; + +import org.hyperledger.besu.cli.converter.exception.DurationConversionException; + +import java.time.Duration; + +import picocli.CommandLine; + +/** The Duration (milliseconds) Cli type converter. */ +public class DurationMillisConverter + implements CommandLine.ITypeConverter, TypeFormatter { + + @Override + public Duration convert(final String value) throws DurationConversionException { + try { + final long millis = Long.parseLong(value); + if (millis < 0) { + throw new DurationConversionException(millis); + } + return Duration.ofMillis(Long.parseLong(value)); + } catch (NullPointerException | IllegalArgumentException e) { + throw new DurationConversionException(value); + } + } + + @Override + public String format(final Duration value) { + return Long.toString(value.toMillis()); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/converter/FractionConverter.java b/besu/src/main/java/org/hyperledger/besu/cli/converter/FractionConverter.java index 969a6be8e9e..64edf7cd9ce 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/converter/FractionConverter.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/converter/FractionConverter.java @@ -20,12 +20,12 @@ import picocli.CommandLine; /** The Fraction converter to convert floats in CLI. */ -public class FractionConverter implements CommandLine.ITypeConverter { +public class FractionConverter implements CommandLine.ITypeConverter { @Override - public Float convert(final String value) throws FractionConversionException { + public Fraction convert(final String value) throws FractionConversionException { try { - return Fraction.fromString(value).getValue(); + return Fraction.fromString(value); } catch (final NullPointerException | IllegalArgumentException e) { throw new FractionConversionException(value); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/converter/PercentageConverter.java b/besu/src/main/java/org/hyperledger/besu/cli/converter/PercentageConverter.java index 23a2d94d33d..410ec83a21d 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/converter/PercentageConverter.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/converter/PercentageConverter.java @@ -20,12 +20,12 @@ import picocli.CommandLine; /** The Percentage Cli type converter. */ -public class PercentageConverter implements CommandLine.ITypeConverter { +public class PercentageConverter implements CommandLine.ITypeConverter { @Override - public Integer convert(final String value) throws PercentageConversionException { + public Percentage convert(final String value) throws PercentageConversionException { try { - return Percentage.fromString(value).getValue(); + return Percentage.fromString(value); } catch (NullPointerException | IllegalArgumentException e) { throw new PercentageConversionException(value); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/converter/TypeFormatter.java b/besu/src/main/java/org/hyperledger/besu/cli/converter/TypeFormatter.java new file mode 100644 index 00000000000..59658d135ac --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/converter/TypeFormatter.java @@ -0,0 +1,31 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.converter; + +/** + * This interface can be used to give a converter the capability to format the converted value back + * to its CLI form + * + * @param the type of the CLI converted runtime value + */ +public interface TypeFormatter { + /** + * Format a converted value back to its CLI form + * + * @param value the converted value + * @return the textual CLI form of the value + */ + String format(V value); +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/converter/exception/DurationConversionException.java b/besu/src/main/java/org/hyperledger/besu/cli/converter/exception/DurationConversionException.java new file mode 100644 index 00000000000..cd56d06188c --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/converter/exception/DurationConversionException.java @@ -0,0 +1,39 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.converter.exception; + +import static java.lang.String.format; + +/** The custom Duration conversion exception. */ +public final class DurationConversionException extends Exception { + + /** + * Instantiates a new Duration conversion exception for malformed value. + * + * @param value the value + */ + public DurationConversionException(final String value) { + super(format("'%s' is not a long", value)); + } + + /** + * Instantiates a new Duration conversion exception for negative value. + * + * @param value the millis + */ + public DurationConversionException(final long value) { + super(format("negative value '%d' is not allowed", value)); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/OptionParser.java b/besu/src/main/java/org/hyperledger/besu/cli/options/OptionParser.java index 73161742f90..003ad8846e8 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/OptionParser.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/OptionParser.java @@ -16,6 +16,11 @@ import static com.google.common.base.Preconditions.checkArgument; +import org.hyperledger.besu.datatypes.Wei; + +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Iterator; import com.google.common.base.Splitter; @@ -96,4 +101,44 @@ public static String format(final float value) { public static String format(final UInt256 value) { return value.toBigInteger().toString(10); } + + /** + * Format Wei to string. + * + * @param value the value + * @return the string + */ + public static String format(final Wei value) { + return format(value.toUInt256()); + } + + /** + * Format any object to string. This implementation tries to find an existing format method, in + * this class, that matches the type of the passed object, and if not found just invoke, to string + * on the passed object + * + * @param value the object + * @return the string + */ + public static String format(final Object value) { + Method formatMethod; + try { + formatMethod = OptionParser.class.getMethod("format", value.getClass()); + } catch (NoSuchMethodException e) { + try { + // maybe a primitive version of the method exists + formatMethod = + OptionParser.class.getMethod( + "format", MethodType.methodType(value.getClass()).unwrap().returnType()); + } catch (NoSuchMethodException ex) { + return value.toString(); + } + } + + try { + return (String) formatMethod.invoke(null, value); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptions.java new file mode 100644 index 00000000000..6353618d24d --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptions.java @@ -0,0 +1,263 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.options.stable; + +import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_DOUBLE_FORMAT_HELP; +import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_INTEGER_FORMAT_HELP; +import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_LONG_FORMAT_HELP; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LEGACY; + +import org.hyperledger.besu.cli.converter.FractionConverter; +import org.hyperledger.besu.cli.converter.PercentageConverter; +import org.hyperledger.besu.cli.options.CLIOptions; +import org.hyperledger.besu.cli.util.CommandLineUtils; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.util.number.Fraction; +import org.hyperledger.besu.util.number.Percentage; + +import java.io.File; +import java.util.List; + +import picocli.CommandLine; + +/** The Transaction pool Cli stable options. */ +public class TransactionPoolOptions implements CLIOptions { + private static final String TX_POOL_IMPLEMENTATION = "--tx-pool"; + private static final String TX_POOL_DISABLE_LOCALS = "--tx-pool-disable-locals"; + private static final String TX_POOL_ENABLE_SAVE_RESTORE = "--tx-pool-enable-save-restore"; + private static final String TX_POOL_SAVE_FILE = "--tx-pool-save-file"; + private static final String TX_POOL_PRICE_BUMP = "--tx-pool-price-bump"; + private static final String RPC_TX_FEECAP = "--rpc-tx-feecap"; + private static final String STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG = + "--strict-tx-replay-protection-enabled"; + + @CommandLine.Option( + names = {TX_POOL_IMPLEMENTATION}, + paramLabel = "", + description = "The Transaction Pool implementation to use(default: ${DEFAULT-VALUE})", + arity = "0..1") + private TransactionPoolConfiguration.Implementation txPoolImplementation = LAYERED; + + @CommandLine.Option( + names = {TX_POOL_DISABLE_LOCALS}, + paramLabel = "", + description = + "Set to true if transactions sent via RPC should have the same checks and not be prioritized over remote ones (default: ${DEFAULT-VALUE})", + fallbackValue = "true", + arity = "0..1") + private Boolean disableLocalTxs = TransactionPoolConfiguration.DEFAULT_DISABLE_LOCAL_TXS; + + @CommandLine.Option( + names = {TX_POOL_ENABLE_SAVE_RESTORE}, + paramLabel = "", + description = + "Set to true to enable saving the txpool content to file on shutdown and reloading it on startup (default: ${DEFAULT-VALUE})", + fallbackValue = "true", + arity = "0..1") + private Boolean saveRestoreEnabled = TransactionPoolConfiguration.DEFAULT_ENABLE_SAVE_RESTORE; + + @CommandLine.Option( + names = {TX_POOL_SAVE_FILE}, + paramLabel = "", + description = + "If saving the txpool content is enabled, define a custom path for the save file (default: ${DEFAULT-VALUE} in the data-dir)", + arity = "1") + private File saveFile = TransactionPoolConfiguration.DEFAULT_SAVE_FILE; + + @CommandLine.Option( + names = {TX_POOL_PRICE_BUMP}, + paramLabel = "", + converter = PercentageConverter.class, + description = + "Price bump percentage to replace an already existing transaction (default: ${DEFAULT-VALUE})", + arity = "1") + private Percentage priceBump = TransactionPoolConfiguration.DEFAULT_PRICE_BUMP; + + @CommandLine.Option( + names = {RPC_TX_FEECAP}, + description = + "Maximum transaction fees (in Wei) accepted for transaction submitted through RPC (default: ${DEFAULT-VALUE})", + arity = "1") + private Wei txFeeCap = TransactionPoolConfiguration.DEFAULT_RPC_TX_FEE_CAP; + + @CommandLine.Option( + names = {STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG}, + paramLabel = "", + description = + "Require transactions submitted via JSON-RPC to use replay protection in accordance with EIP-155 (default: ${DEFAULT-VALUE})", + fallbackValue = "true", + arity = "0..1") + private Boolean strictTxReplayProtectionEnabled = false; + + @CommandLine.ArgGroup( + validate = false, + heading = "@|bold Tx Pool Layered Implementation Options|@%n") + private final Layered layeredOptions = new Layered(); + + static class Layered { + private static final String TX_POOL_LAYER_MAX_CAPACITY = "--tx-pool-layer-max-capacity"; + private static final String TX_POOL_MAX_PRIORITIZED = "--tx-pool-max-prioritized"; + private static final String TX_POOL_MAX_FUTURE_BY_SENDER = "--tx-pool-max-future-by-sender"; + + @CommandLine.Option( + names = {TX_POOL_LAYER_MAX_CAPACITY}, + paramLabel = MANDATORY_LONG_FORMAT_HELP, + description = + "Max amount of memory space, in bytes, that any layer within the transaction pool could occupy (default: ${DEFAULT-VALUE})", + arity = "1") + Long txPoolLayerMaxCapacity = + TransactionPoolConfiguration.DEFAULT_PENDING_TRANSACTIONS_LAYER_MAX_CAPACITY_BYTES; + + @CommandLine.Option( + names = {TX_POOL_MAX_PRIORITIZED}, + paramLabel = MANDATORY_INTEGER_FORMAT_HELP, + description = + "Max number of pending transactions that are prioritized and thus kept sorted (default: ${DEFAULT-VALUE})", + arity = "1") + Integer txPoolMaxPrioritized = + TransactionPoolConfiguration.DEFAULT_MAX_PRIORITIZED_TRANSACTIONS; + + @CommandLine.Option( + names = {TX_POOL_MAX_FUTURE_BY_SENDER}, + paramLabel = MANDATORY_INTEGER_FORMAT_HELP, + description = + "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.ArgGroup( + validate = false, + heading = "@|bold Tx Pool Legacy Implementation Options|@%n") + private final Legacy legacyOptions = new Legacy(); + + static class Legacy { + private static final String TX_POOL_RETENTION_HOURS = "--tx-pool-retention-hours"; + private static final String TX_POOL_LIMIT_BY_ACCOUNT_PERCENTAGE = + "--tx-pool-limit-by-account-percentage"; + private static final String TX_POOL_MAX_SIZE = "--tx-pool-max-size"; + + @CommandLine.Option( + names = {TX_POOL_RETENTION_HOURS}, + paramLabel = MANDATORY_INTEGER_FORMAT_HELP, + description = + "Maximum retention period of pending transactions in hours (default: ${DEFAULT-VALUE})", + arity = "1") + Integer pendingTxRetentionPeriod = TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS; + + @CommandLine.Option( + names = {TX_POOL_LIMIT_BY_ACCOUNT_PERCENTAGE}, + paramLabel = MANDATORY_DOUBLE_FORMAT_HELP, + converter = FractionConverter.class, + description = + "Maximum portion of the transaction pool which a single account may occupy with future transactions (default: ${DEFAULT-VALUE})", + arity = "1") + Fraction txPoolLimitByAccountPercentage = + TransactionPoolConfiguration.DEFAULT_LIMIT_TX_POOL_BY_ACCOUNT_PERCENTAGE; + + @CommandLine.Option( + names = {TX_POOL_MAX_SIZE}, + paramLabel = MANDATORY_INTEGER_FORMAT_HELP, + description = + "Maximum number of pending transactions that will be kept in the transaction pool (default: ${DEFAULT-VALUE})", + arity = "1") + Integer txPoolMaxSize = TransactionPoolConfiguration.DEFAULT_MAX_PENDING_TRANSACTIONS; + } + + private TransactionPoolOptions() {} + + /** + * Create transaction pool options. + * + * @return the transaction pool options + */ + public static TransactionPoolOptions create() { + return new TransactionPoolOptions(); + } + + /** + * Create Transaction Pool Options from Transaction Pool Configuration. + * + * @param config the Transaction Pool Configuration + * @return the transaction pool options + */ + public static TransactionPoolOptions fromConfig(final TransactionPoolConfiguration config) { + final TransactionPoolOptions options = TransactionPoolOptions.create(); + options.txPoolImplementation = config.getTxPoolImplementation(); + options.saveRestoreEnabled = config.getEnableSaveRestore(); + options.disableLocalTxs = config.getDisableLocalTransactions(); + options.priceBump = config.getPriceBump(); + options.txFeeCap = config.getTxFeeCap(); + options.saveFile = config.getSaveFile(); + options.strictTxReplayProtectionEnabled = config.getStrictTransactionReplayProtectionEnabled(); + options.layeredOptions.txPoolLayerMaxCapacity = + config.getPendingTransactionsLayerMaxCapacityBytes(); + options.layeredOptions.txPoolMaxPrioritized = config.getMaxPrioritizedTransactions(); + options.layeredOptions.txPoolMaxFutureBySender = config.getMaxFutureBySender(); + options.legacyOptions.txPoolLimitByAccountPercentage = + config.getTxPoolLimitByAccountPercentage(); + options.legacyOptions.txPoolMaxSize = config.getTxPoolMaxSize(); + options.legacyOptions.pendingTxRetentionPeriod = config.getPendingTxRetentionPeriod(); + + return options; + } + + /** + * Validate that there are no inconsistencies in the specified options. For example that the + * options are valid for the selected implementation. + * + * @param commandLine the full commandLine to check all the options specified by the user + */ + public void validate(final CommandLine commandLine) { + CommandLineUtils.failIfOptionDoesntMeetRequirement( + commandLine, + "Could not use legacy transaction pool options with layered implementation", + !txPoolImplementation.equals(LAYERED), + CommandLineUtils.getCLIOptionNames(Legacy.class)); + + CommandLineUtils.failIfOptionDoesntMeetRequirement( + commandLine, + "Could not use layered transaction pool options with legacy implementation", + !txPoolImplementation.equals(LEGACY), + CommandLineUtils.getCLIOptionNames(Layered.class)); + } + + @Override + public TransactionPoolConfiguration toDomainObject() { + return ImmutableTransactionPoolConfiguration.builder() + .txPoolImplementation(txPoolImplementation) + .enableSaveRestore(saveRestoreEnabled) + .disableLocalTransactions(disableLocalTxs) + .priceBump(priceBump) + .txFeeCap(txFeeCap) + .saveFile(saveFile) + .strictTransactionReplayProtectionEnabled(strictTxReplayProtectionEnabled) + .pendingTransactionsLayerMaxCapacityBytes(layeredOptions.txPoolLayerMaxCapacity) + .maxPrioritizedTransactions(layeredOptions.txPoolMaxPrioritized) + .maxFutureBySender(layeredOptions.txPoolMaxFutureBySender) + .txPoolLimitByAccountPercentage(legacyOptions.txPoolLimitByAccountPercentage) + .txPoolMaxSize(legacyOptions.txPoolMaxSize) + .pendingTxRetentionPeriod(legacyOptions.pendingTxRetentionPeriod) + .build(); + } + + @Override + public List getCLIOptions() { + return CommandLineUtils.getCLIOptions(this, new TransactionPoolOptions()); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptions.java index e199966c25f..cb7994b947f 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptions.java @@ -14,50 +14,25 @@ */ package org.hyperledger.besu.cli.options.unstable; +import org.hyperledger.besu.cli.converter.DurationMillisConverter; import org.hyperledger.besu.cli.options.CLIOptions; -import org.hyperledger.besu.cli.options.OptionParser; +import org.hyperledger.besu.cli.util.CommandLineUtils; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import java.time.Duration; -import java.util.Arrays; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import picocli.CommandLine; -/** The Transaction pool Cli options. */ -public class TransactionPoolOptions - implements CLIOptions { - private static final Logger LOG = LoggerFactory.getLogger(TransactionPoolOptions.class); - +/** The Transaction pool Cli unstable options. */ +public class TransactionPoolOptions implements CLIOptions { private static final String TX_MESSAGE_KEEP_ALIVE_SEC_FLAG = "--Xincoming-tx-messages-keep-alive-seconds"; private static final String ETH65_TX_ANNOUNCED_BUFFERING_PERIOD_FLAG = "--Xeth65-tx-announced-buffering-period-milliseconds"; - private static final String STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG = - "--strict-tx-replay-protection-enabled"; - - private static final String LAYERED_TX_POOL_ENABLED_FLAG = "--Xlayered-tx-pool"; - private static final String LAYERED_TX_POOL_LAYER_MAX_CAPACITY = - "--Xlayered-tx-pool-layer-max-capacity"; - private static final String LAYERED_TX_POOL_MAX_PRIORITIZED = - "--Xlayered-tx-pool-max-prioritized"; - private static final String LAYERED_TX_POOL_MAX_FUTURE_BY_SENDER = - "--Xlayered-tx-pool-max-future-by-sender"; - - @CommandLine.Option( - names = {STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG}, - paramLabel = "", - description = - "Require transactions submitted via JSON-RPC to use replay protection in accordance with EIP-155 (default: ${DEFAULT-VALUE})", - fallbackValue = "true", - arity = "0..1") - private Boolean strictTxReplayProtectionEnabled = false; - @CommandLine.Option( names = {TX_MESSAGE_KEEP_ALIVE_SEC_FLAG}, paramLabel = "", @@ -66,56 +41,18 @@ public class TransactionPoolOptions "Keep alive of incoming transaction messages in seconds (default: ${DEFAULT-VALUE})", arity = "1") private Integer txMessageKeepAliveSeconds = - TransactionPoolConfiguration.DEFAULT_TX_MSG_KEEP_ALIVE; + TransactionPoolConfiguration.Unstable.DEFAULT_TX_MSG_KEEP_ALIVE; @CommandLine.Option( names = {ETH65_TX_ANNOUNCED_BUFFERING_PERIOD_FLAG}, paramLabel = "", + converter = DurationMillisConverter.class, hidden = true, description = "The period for which the announced transactions remain in the buffer before being requested from the peers in milliseconds (default: ${DEFAULT-VALUE})", arity = "1") - private long eth65TrxAnnouncedBufferingPeriod = - TransactionPoolConfiguration.ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD.toMillis(); - - @CommandLine.Option( - names = {LAYERED_TX_POOL_ENABLED_FLAG}, - paramLabel = "", - hidden = true, - description = "Enable the Layered Transaction Pool (default: ${DEFAULT-VALUE})", - arity = "0..1") - private Boolean layeredTxPoolEnabled = - TransactionPoolConfiguration.DEFAULT_LAYERED_TX_POOL_ENABLED; - - @CommandLine.Option( - names = {LAYERED_TX_POOL_LAYER_MAX_CAPACITY}, - paramLabel = "", - hidden = true, - description = - "Max amount of memory space, in bytes, that any layer within the transaction pool could occupy (default: ${DEFAULT-VALUE})", - arity = "1") - private long layeredTxPoolLayerMaxCapacity = - TransactionPoolConfiguration.DEFAULT_PENDING_TRANSACTIONS_LAYER_MAX_CAPACITY_BYTES; - - @CommandLine.Option( - names = {LAYERED_TX_POOL_MAX_PRIORITIZED}, - paramLabel = "", - hidden = true, - description = - "Max number of pending transactions that are prioritized and thus kept sorted (default: ${DEFAULT-VALUE})", - arity = "1") - private int layeredTxPoolMaxPrioritized = - TransactionPoolConfiguration.DEFAULT_MAX_PRIORITIZED_TRANSACTIONS; - - @CommandLine.Option( - names = {LAYERED_TX_POOL_MAX_FUTURE_BY_SENDER}, - paramLabel = "", - hidden = true, - description = - "Max number of future pending transactions allowed for a single sender (default: ${DEFAULT-VALUE})", - arity = "1") - private int layeredTxPoolMaxFutureBySender = - TransactionPoolConfiguration.DEFAULT_MAX_FUTURE_BY_SENDER; + private Duration eth65TrxAnnouncedBufferingPeriod = + TransactionPoolConfiguration.Unstable.ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD; private TransactionPoolOptions() {} @@ -134,51 +71,24 @@ public static TransactionPoolOptions create() { * @param config the Transaction Pool Configuration * @return the transaction pool options */ - public static TransactionPoolOptions fromConfig(final TransactionPoolConfiguration config) { + public static TransactionPoolOptions fromConfig( + final TransactionPoolConfiguration.Unstable config) { final TransactionPoolOptions options = TransactionPoolOptions.create(); options.txMessageKeepAliveSeconds = config.getTxMessageKeepAliveSeconds(); - options.eth65TrxAnnouncedBufferingPeriod = - config.getEth65TrxAnnouncedBufferingPeriod().toMillis(); - options.strictTxReplayProtectionEnabled = config.getStrictTransactionReplayProtectionEnabled(); - options.layeredTxPoolEnabled = config.getLayeredTxPoolEnabled(); - options.layeredTxPoolLayerMaxCapacity = config.getPendingTransactionsLayerMaxCapacityBytes(); - options.layeredTxPoolMaxPrioritized = config.getMaxPrioritizedTransactions(); - options.layeredTxPoolMaxFutureBySender = config.getMaxFutureBySender(); + options.eth65TrxAnnouncedBufferingPeriod = config.getEth65TrxAnnouncedBufferingPeriod(); return options; } @Override - public ImmutableTransactionPoolConfiguration.Builder toDomainObject() { - if (layeredTxPoolEnabled) { - LOG.warn( - "Layered transaction pool enabled, ignoring settings for " - + "--tx-pool-max-size and --tx-pool-limit-by-account-percentage"); - } - - return ImmutableTransactionPoolConfiguration.builder() - .strictTransactionReplayProtectionEnabled(strictTxReplayProtectionEnabled) + public TransactionPoolConfiguration.Unstable toDomainObject() { + return ImmutableTransactionPoolConfiguration.Unstable.builder() .txMessageKeepAliveSeconds(txMessageKeepAliveSeconds) - .eth65TrxAnnouncedBufferingPeriod(Duration.ofMillis(eth65TrxAnnouncedBufferingPeriod)) - .layeredTxPoolEnabled(layeredTxPoolEnabled) - .pendingTransactionsLayerMaxCapacityBytes(layeredTxPoolLayerMaxCapacity) - .maxPrioritizedTransactions(layeredTxPoolMaxPrioritized) - .maxFutureBySender(layeredTxPoolMaxFutureBySender); + .eth65TrxAnnouncedBufferingPeriod(eth65TrxAnnouncedBufferingPeriod) + .build(); } @Override public List getCLIOptions() { - return Arrays.asList( - STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG + "=" + strictTxReplayProtectionEnabled, - TX_MESSAGE_KEEP_ALIVE_SEC_FLAG, - OptionParser.format(txMessageKeepAliveSeconds), - ETH65_TX_ANNOUNCED_BUFFERING_PERIOD_FLAG, - OptionParser.format(eth65TrxAnnouncedBufferingPeriod), - LAYERED_TX_POOL_ENABLED_FLAG + "=" + layeredTxPoolEnabled, - LAYERED_TX_POOL_LAYER_MAX_CAPACITY, - OptionParser.format(layeredTxPoolLayerMaxCapacity), - LAYERED_TX_POOL_MAX_PRIORITIZED, - OptionParser.format(layeredTxPoolMaxPrioritized), - LAYERED_TX_POOL_MAX_FUTURE_BY_SENDER, - OptionParser.format(layeredTxPoolMaxFutureBySender)); + return CommandLineUtils.getCLIOptions(this, new TransactionPoolOptions()); } } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java b/besu/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java index 5c191bb4fce..0115420005e 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java @@ -14,10 +14,17 @@ */ package org.hyperledger.besu.cli.util; +import org.hyperledger.besu.cli.converter.TypeFormatter; +import org.hyperledger.besu.cli.options.OptionParser; import org.hyperledger.besu.util.StringUtils; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import com.google.common.base.Strings; @@ -124,6 +131,103 @@ public static void failIfOptionDoesntMeetRequirement( } } + /** + * Return all the option names declared in a class. Note this will recursively check in any inner + * option class if present. + * + * @param optClass the class to look for options + * @return a list of option names found in the class + */ + public static List getCLIOptionNames(final Class optClass) { + final List cliOpts = new ArrayList<>(); + final Field[] fields = optClass.getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + Annotation ann = field.getAnnotation(CommandLine.Option.class); + if (ann != null) { + final var optAnn = CommandLine.Option.class.cast(ann); + cliOpts.add(optAnn.names()[0]); + } else { + ann = field.getAnnotation(CommandLine.ArgGroup.class); + if (ann != null) { + cliOpts.addAll(getCLIOptionNames(field.getType())); + } + } + } + return cliOpts; + } + + /** + * Converts the runtime options into their CLI representation. Options with a value equals to its + * default are not included in the result since redundant. Note this will recursively check in any + * inner option class if present. + * + * @param currOptions the actual runtime options + * @param defaults the default option values + * @return a list of CLI arguments + */ + public static List getCLIOptions(final Object currOptions, final Object defaults) { + final List cliOpts = new ArrayList<>(); + final Field[] fields = currOptions.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + Annotation ann = field.getAnnotation(CommandLine.Option.class); + if (ann != null) { + try { + var optVal = field.get(currOptions); + if (!Objects.equals(optVal, field.get(defaults))) { + var optAnn = CommandLine.Option.class.cast(ann); + cliOpts.add(optAnn.names()[0]); + final var optConverter = optAnn.converter(); + cliOpts.add(formatValue(optConverter, optVal)); + } + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } else { + ann = field.getAnnotation(CommandLine.ArgGroup.class); + if (ann != null) { + try { + cliOpts.addAll(getCLIOptions(field.get(currOptions), field.get(defaults))); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + } + return cliOpts; + } + + /** + * There are different ways to format an option value back to its CLI form, the first is to use a + * {@link TypeFormatter} if present, otherwise the formatting it is delegated to {@link + * OptionParser#format(Object)} + * + * @param optConverter the list of converter types for the option + * @param optVal the value of the options + * @return a string with the CLI form of the value + */ + @SuppressWarnings("unchecked") + private static String formatValue( + final Class>[] optConverter, final Object optVal) { + return Arrays.stream(optConverter) + .filter(c -> Arrays.stream(c.getInterfaces()).anyMatch(i -> i.equals(TypeFormatter.class))) + .findFirst() + .map( + ctf -> { + try { + return (TypeFormatter) ctf.getDeclaredConstructor().newInstance(); + } catch (InstantiationException + | IllegalAccessException + | InvocationTargetException + | NoSuchMethodException e) { + throw new RuntimeException(e); + } + }) + .map(tf -> tf.format(optVal)) + .orElseGet(() -> OptionParser.format(optVal)); + } + private static String getAffectedOptions( final CommandLine commandLine, final List dependentOptionsNames) { return commandLine.getCommandSpec().options().stream() diff --git a/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigFileDefaultProvider.java b/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigFileDefaultProvider.java index ec9ee7d593f..9ec3f1ef640 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigFileDefaultProvider.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigFileDefaultProvider.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.cli.util; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.util.number.Percentage; import java.io.File; import java.io.IOException; @@ -89,6 +90,8 @@ private String getConfigurationValue(final OptionSpec optionSpec) { defaultValue = getNumericEntryAsString(optionSpec); } else if (optionSpec.type().equals(Float.class) || optionSpec.type().equals(float.class)) { defaultValue = getNumericEntryAsString(optionSpec); + } else if (optionSpec.type().equals(Percentage.class)) { + defaultValue = getNumericEntryAsString(optionSpec); } else { // else will be treated as String defaultValue = getEntryAsString(optionSpec); } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 3376d2b7001..553220c9431 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -58,7 +58,6 @@ import org.hyperledger.besu.BesuInfo; import org.hyperledger.besu.cli.config.EthNetworkConfig; -import org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; @@ -4597,192 +4596,6 @@ public void errorIsRaisedIfStaticNodesAreNotAllowed() throws IOException { .contains(staticNodeURI.toString(), "not in nodes-allowlist"); } - @Test - public void disableLocalsDefault() { - parseCommand(); - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getDisableLocalTransactions()).isFalse(); - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void disableLocalsOn() { - parseCommand("--tx-pool-disable-locals=true"); - - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getDisableLocalTransactions()).isTrue(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void disableLocalsOff() { - parseCommand("--tx-pool-disable-locals=false"); - - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getDisableLocalTransactions()).isFalse(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void saveToFileDisabledByDefault() { - parseCommand(); - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getEnableSaveRestore()).isFalse(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void saveToFileEnabledDefaultPath() { - parseCommand("--tx-pool-enable-save-restore=true"); - - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getEnableSaveRestore()).isTrue(); - assertThat(transactionPoolConfigCaptor.getValue().getSaveFile()) - .hasName(TransactionPoolConfiguration.DEFAULT_SAVE_FILE_NAME); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void saveToFileEnabledCustomPath() { - parseCommand("--tx-pool-enable-save-restore=true", "--tx-pool-save-file=my.save.file"); - - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getEnableSaveRestore()).isTrue(); - assertThat(transactionPoolConfigCaptor.getValue().getSaveFile()).hasName("my.save.file"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void senderLimitedTxPool_derived() { - parseCommand("--tx-pool-limit-by-account-percentage=0.002"); - - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getTxPoolMaxFutureTransactionByAccount()) - .isEqualTo(9); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void senderLimitedTxPoolFloor_derived() { - parseCommand("--tx-pool-limit-by-account-percentage=0.0001"); - - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getTxPoolMaxFutureTransactionByAccount()) - .isEqualTo(1); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void senderLimitedTxPoolCeiling_violated() { - TestBesuCommand commandTest = parseCommand("--tx-pool-limit-by-account-percentage=1.00002341"); - - TransactionPoolOptions txPoolOption = commandTest.getTransactionPoolOptions(); - - final TransactionPoolConfiguration config = txPoolOption.toDomainObject().build(); - assertThat(config.getTxPoolLimitByAccountPercentage()) - .isEqualTo(TransactionPoolConfiguration.DEFAULT_LIMIT_TX_POOL_BY_ACCOUNT_PERCENTAGE); - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains("Invalid value for option '--tx-pool-limit-by-account-percentage'"); - } - - @Test - public void pendingTransactionRetentionPeriod() { - final int pendingTxRetentionHours = 999; - parseCommand("--tx-pool-retention-hours", String.valueOf(pendingTxRetentionHours)); - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getPendingTxRetentionPeriod()) - .isEqualTo(pendingTxRetentionHours); - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void transactionPoolPriceBump() { - final Percentage priceBump = Percentage.fromInt(13); - parseCommand("--tx-pool-price-bump", priceBump.toString()); - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getPriceBump()).isEqualTo(priceBump); - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void invalidTansactionPoolPriceBumpShouldFail() { - parseCommand("--tx-pool-price-bump", "101"); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains( - "Invalid value for option '--tx-pool-price-bump'", - "should be a number between 0 and 100 inclusive"); - } - - @Test - public void transactionPoolTxFeeCap() { - final Wei txFeeCap = Wei.fromEth(2); - parseCommand("--rpc-tx-feecap", txFeeCap.toDecimalString()); - verify(mockControllerBuilder) - .transactionPoolConfiguration(transactionPoolConfigCaptor.capture()); - assertThat(transactionPoolConfigCaptor.getValue().getTxFeeCap()).isEqualTo(txFeeCap); - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void invalidTansactionPoolTxFeeCapShouldFail() { - parseCommand("--rpc-tx-feecap", "abcd"); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains("Invalid value for option '--rpc-tx-feecap'", "cannot convert 'abcd' to Wei"); - } - - @Test - public void txMessageKeepAliveSecondsWithInvalidInputShouldFail() { - parseCommand("--Xincoming-tx-messages-keep-alive-seconds", "acbd"); - - Mockito.verifyNoInteractions(mockRunnerBuilder); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains( - "Invalid value for option '--Xincoming-tx-messages-keep-alive-seconds': 'acbd' is not an int"); - } - - @Test - public void eth65TrxAnnouncedBufferingPeriodWithInvalidInputShouldFail() { - parseCommand("--Xeth65-tx-announced-buffering-period-milliseconds", "acbd"); - - Mockito.verifyNoInteractions(mockRunnerBuilder); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains( - "Invalid value for option '--Xeth65-tx-announced-buffering-period-milliseconds': 'acbd' is not a long"); - } - @Test public void tomlThatHasInvalidOptions() throws IOException { final URL configFile = this.getClass().getResource("/complete_config.toml"); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index fc6f013b2da..d089ceaceb7 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -519,7 +519,12 @@ public EthProtocolOptions getEthProtocolOptions() { return unstableEthProtocolOptions; } - public TransactionPoolOptions getTransactionPoolOptions() { + public org.hyperledger.besu.cli.options.stable.TransactionPoolOptions + getStableTransactionPoolOptions() { + return stableTransactionPoolOptions; + } + + public TransactionPoolOptions getUnstableTransactionPoolOptions() { return unstableTransactionPoolOptions; } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java index 33ed9bc2d16..4fff2b36f58 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java @@ -15,6 +15,8 @@ package org.hyperledger.besu.cli; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LEGACY; import static org.mockito.Mockito.mock; import java.math.BigInteger; @@ -145,14 +147,16 @@ void setHighSpecEnabled() { } @Test - void setLayeredTxPoolEnabled() { - final String layeredTxPoolDisabled = builder.build(); - assertThat(layeredTxPoolDisabled) - .doesNotContain("Experimental layered transaction pool configuration enabled"); - - builder.setLayeredTxPoolEnabled(); - final String layeredTxPoolEnabled = builder.build(); - assertThat(layeredTxPoolEnabled) - .contains("Experimental layered transaction pool configuration enabled"); + void setTxPoolImplementationLayered() { + builder.setTxPoolImplementation(LAYERED); + final String layeredTxPoolSelected = builder.build(); + assertThat(layeredTxPoolSelected).contains("Using LAYERED transaction pool implementation"); + } + + @Test + void setTxPoolImplementationLegacy() { + builder.setTxPoolImplementation(LEGACY); + final String legacyTxPoolSelected = builder.build(); + assertThat(legacyTxPoolSelected).contains("Using LEGACY transaction pool implementation"); } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/converter/FractionConverterTest.java b/besu/src/test/java/org/hyperledger/besu/cli/converter/FractionConverterTest.java index 022bca1ec27..611109274d5 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/converter/FractionConverterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/converter/FractionConverterTest.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.catchThrowable; import org.hyperledger.besu.cli.converter.exception.FractionConversionException; +import org.hyperledger.besu.util.number.Fraction; import org.junit.Test; import org.junit.runner.RunWith; @@ -30,9 +31,9 @@ public class FractionConverterTest { @Test public void assertThatConvertHandlesProperlyAValidString() throws FractionConversionException { - final float fraction = fractionConverter.convert("0.58"); + final Fraction fraction = fractionConverter.convert("0.58"); assertThat(fraction).isNotNull(); - assertThat(fraction).isEqualTo(0.58f); + assertThat(fraction.getValue()).isEqualTo(0.58f); } @Test diff --git a/besu/src/test/java/org/hyperledger/besu/cli/converter/PercentageConverterTest.java b/besu/src/test/java/org/hyperledger/besu/cli/converter/PercentageConverterTest.java index 6fc6f9dc7e7..829a4ef35f6 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/converter/PercentageConverterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/converter/PercentageConverterTest.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.catchThrowable; import org.hyperledger.besu.cli.converter.exception.PercentageConversionException; +import org.hyperledger.besu.util.number.Percentage; import org.junit.Test; import org.junit.runner.RunWith; @@ -30,9 +31,9 @@ public class PercentageConverterTest { @Test public void assertThatConvertHandlesProperlyAValidString() throws PercentageConversionException { - final int percentage = percentageConverter.convert("58"); + final Percentage percentage = percentageConverter.convert("58"); assertThat(percentage).isNotNull(); - assertThat(percentage).isEqualTo(58); + assertThat(percentage.getValue()).isEqualTo(58); } @Test diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java index 91d7e35c39c..ef7da0c7669 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.List; +import java.util.function.Consumer; import org.junit.Test; @@ -87,9 +88,9 @@ public void defaultValues() { .isEqualTo(defaultOptions); } - abstract D createDefaultDomainObject(); + protected abstract D createDefaultDomainObject(); - abstract D createCustomizedDomainObject(); + protected abstract D createCustomizedDomainObject(); protected List getFieldsWithComputedDefaults() { return Collections.emptyList(); @@ -99,7 +100,25 @@ protected List getFieldsToIgnore() { return Collections.emptyList(); } - abstract T optionsFromDomainObject(D domainObject); + protected abstract T optionsFromDomainObject(D domainObject); - abstract T getOptionsFromBesuCommand(final TestBesuCommand besuCommand); + protected abstract T getOptionsFromBesuCommand(final TestBesuCommand besuCommand); + + protected void internalTestSuccess(final Consumer assertion, final String... args) { + final TestBesuCommand cmd = parseCommand(args); + + final T options = getOptionsFromBesuCommand(cmd); + final D config = options.toDomainObject(); + assertion.accept(config); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + + protected void internalTestFailure(final String errorMsg, final String... args) { + parseCommand(args); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).contains(errorMsg); + } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/EthProtocolOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/EthProtocolOptionsTest.java index 1dc6f0329fb..9d1d696ab43 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/EthProtocolOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/EthProtocolOptionsTest.java @@ -165,12 +165,12 @@ public void parsesValidEthMinProtocol() { } @Override - EthProtocolConfiguration createDefaultDomainObject() { + protected EthProtocolConfiguration createDefaultDomainObject() { return EthProtocolConfiguration.builder().build(); } @Override - EthProtocolConfiguration createCustomizedDomainObject() { + protected EthProtocolConfiguration createCustomizedDomainObject() { return EthProtocolConfiguration.builder() .maxMessageSize(EthProtocolConfiguration.DEFAULT_MAX_MESSAGE_SIZE * 2) .maxGetBlockHeaders(EthProtocolConfiguration.DEFAULT_MAX_GET_BLOCK_HEADERS + 2) @@ -184,12 +184,13 @@ EthProtocolConfiguration createCustomizedDomainObject() { } @Override - EthProtocolOptions optionsFromDomainObject(final EthProtocolConfiguration domainObject) { + protected EthProtocolOptions optionsFromDomainObject( + final EthProtocolConfiguration domainObject) { return EthProtocolOptions.fromConfig(domainObject); } @Override - EthProtocolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { + protected EthProtocolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { return besuCommand.getEthProtocolOptions(); } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsCLIOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsCLIOptionsTest.java index 5bcaaa553fc..8044770a9b4 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsCLIOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsCLIOptionsTest.java @@ -25,24 +25,25 @@ public class MetricsCLIOptionsTest extends AbstractCLIOptionsTest { @Override - MetricsConfiguration.Builder createDefaultDomainObject() { + protected MetricsConfiguration.Builder createDefaultDomainObject() { return MetricsConfiguration.builder(); } @Override - MetricsConfiguration.Builder createCustomizedDomainObject() { + protected MetricsConfiguration.Builder createCustomizedDomainObject() { return MetricsConfiguration.builder() .timersEnabled(!MetricsConfiguration.DEFAULT_METRICS_TIMERS_ENABLED) .idleTimeout(MetricsConfiguration.DEFAULT_METRICS_IDLE_TIMEOUT_SECONDS); } @Override - MetricsCLIOptions optionsFromDomainObject(final MetricsConfiguration.Builder domainObject) { + protected MetricsCLIOptions optionsFromDomainObject( + final MetricsConfiguration.Builder domainObject) { return MetricsCLIOptions.fromConfiguration(domainObject.build()); } @Override - MetricsCLIOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { + protected MetricsCLIOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { return besuCommand.getMetricsCLIOptions(); } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java index c59747dac73..a2cbdc5942b 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java @@ -165,12 +165,12 @@ public void checkFilterByForkIdSetToFalse() { } @Override - NetworkingConfiguration createDefaultDomainObject() { + protected NetworkingConfiguration createDefaultDomainObject() { return NetworkingConfiguration.create(); } @Override - NetworkingConfiguration createCustomizedDomainObject() { + protected NetworkingConfiguration createCustomizedDomainObject() { final NetworkingConfiguration config = NetworkingConfiguration.create(); config.setInitiateConnectionsFrequency( NetworkingConfiguration.DEFAULT_INITIATE_CONNECTIONS_FREQUENCY_SEC + 10); @@ -181,12 +181,12 @@ NetworkingConfiguration createCustomizedDomainObject() { } @Override - NetworkingOptions optionsFromDomainObject(final NetworkingConfiguration domainObject) { + protected NetworkingOptions optionsFromDomainObject(final NetworkingConfiguration domainObject) { return NetworkingOptions.fromConfig(domainObject); } @Override - NetworkingOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { + protected NetworkingOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { return besuCommand.getNetworkingOptions(); } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/OptionParserTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/OptionParserTest.java index 7dbb3958c2c..db5e69e174b 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/OptionParserTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/OptionParserTest.java @@ -104,4 +104,25 @@ public void format_negativeLong() { final String expected = "-1233"; assertThat(OptionParser.format(input)).isEqualTo(expected); } + + @Test + public void format_object_int() { + final Object input = 1233; + final String expected = "1233"; + assertThat(OptionParser.format(input)).isEqualTo(expected); + } + + @Test + public void format_object_Integer() { + final Object input = Integer.valueOf(1233); + final String expected = "1233"; + assertThat(OptionParser.format(input)).isEqualTo(expected); + } + + @Test + public void format_object_uint256() { + final Object input = UInt256.valueOf(new BigInteger("123456789", 10)); + final String expected = "123456789"; + assertThat(OptionParser.format(input)).isEqualTo(expected); + } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/SynchronizerOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/SynchronizerOptionsTest.java index affb5a9d4d3..0e814a07e26 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/SynchronizerOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/SynchronizerOptionsTest.java @@ -31,12 +31,12 @@ public class SynchronizerOptionsTest extends AbstractCLIOptionsTest { @Override - SynchronizerConfiguration.Builder createDefaultDomainObject() { + protected SynchronizerConfiguration.Builder createDefaultDomainObject() { return SynchronizerConfiguration.builder(); } @Override - SynchronizerConfiguration.Builder createCustomizedDomainObject() { + protected SynchronizerConfiguration.Builder createCustomizedDomainObject() { return SynchronizerConfiguration.builder() .fastSyncPivotDistance(SynchronizerConfiguration.DEFAULT_PIVOT_DISTANCE_FROM_HEAD + 10) .fastSyncFullValidationRate(SynchronizerConfiguration.DEFAULT_FULL_VALIDATION_RATE / 2) @@ -87,7 +87,7 @@ protected List getFieldsWithComputedDefaults() { } @Override - SynchronizerOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { + protected SynchronizerOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { return besuCommand.getSynchronizerOptions(); } @@ -97,7 +97,7 @@ protected List getFieldsToIgnore() { } @Override - SynchronizerOptions optionsFromDomainObject( + protected SynchronizerOptions optionsFromDomainObject( final SynchronizerConfiguration.Builder domainObject) { return SynchronizerOptions.fromConfig(domainObject.build()); } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java deleted file mode 100644 index 5a235524c6a..00000000000 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.cli.options; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.assertj.core.api.Assertions.assertThat; - -import org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions; -import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; -import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; - -import java.time.Duration; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class TransactionPoolOptionsTest - extends AbstractCLIOptionsTest< - ImmutableTransactionPoolConfiguration.Builder, TransactionPoolOptions> { - - @Test - public void strictTxReplayProtection_enabled() { - final TestBesuCommand cmd = parseCommand("--strict-tx-replay-protection-enabled"); - - final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd); - final TransactionPoolConfiguration config = options.toDomainObject().build(); - assertThat(config.getStrictTransactionReplayProtectionEnabled()).isTrue(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void strictTxReplayProtection_enabledWithBooleanArg() { - final TestBesuCommand cmd = parseCommand("--strict-tx-replay-protection-enabled=true"); - - final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd); - final TransactionPoolConfiguration config = options.toDomainObject().build(); - assertThat(config.getStrictTransactionReplayProtectionEnabled()).isTrue(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void strictTxReplayProtection_disabled() { - final TestBesuCommand cmd = parseCommand("--strict-tx-replay-protection-enabled=false"); - - final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd); - final TransactionPoolConfiguration config = options.toDomainObject().build(); - assertThat(config.getStrictTransactionReplayProtectionEnabled()).isFalse(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void strictTxReplayProtection_default() { - final TestBesuCommand cmd = parseCommand(); - - final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd); - final TransactionPoolConfiguration config = options.toDomainObject().build(); - assertThat(config.getStrictTransactionReplayProtectionEnabled()).isFalse(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void txMessageKeepAliveSeconds() { - final int txMessageKeepAliveSeconds = 999; - final TestBesuCommand cmd = - parseCommand( - "--Xincoming-tx-messages-keep-alive-seconds", - String.valueOf(txMessageKeepAliveSeconds)); - - final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd); - final TransactionPoolConfiguration config = options.toDomainObject().build(); - assertThat(config.getTxMessageKeepAliveSeconds()).isEqualTo(txMessageKeepAliveSeconds); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void eth65TrxAnnouncedBufferingPeriod() { - final long eth65TrxAnnouncedBufferingPeriod = 999; - final TestBesuCommand cmd = - parseCommand( - "--Xeth65-tx-announced-buffering-period-milliseconds", - String.valueOf(eth65TrxAnnouncedBufferingPeriod)); - - final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd); - final TransactionPoolConfiguration config = options.toDomainObject().build(); - assertThat(config.getEth65TrxAnnouncedBufferingPeriod()) - .hasMillis(eth65TrxAnnouncedBufferingPeriod); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Override - ImmutableTransactionPoolConfiguration.Builder createDefaultDomainObject() { - final ImmutableTransactionPoolConfiguration defaultValue = - ImmutableTransactionPoolConfiguration.builder().build(); - return ImmutableTransactionPoolConfiguration.builder() - .strictTransactionReplayProtectionEnabled(false) - .txMessageKeepAliveSeconds(defaultValue.getTxMessageKeepAliveSeconds()) - .eth65TrxAnnouncedBufferingPeriod(defaultValue.getEth65TrxAnnouncedBufferingPeriod()) - .layeredTxPoolEnabled(defaultValue.getLayeredTxPoolEnabled()) - .pendingTransactionsLayerMaxCapacityBytes( - defaultValue.getPendingTransactionsLayerMaxCapacityBytes()) - .maxPrioritizedTransactions(defaultValue.getMaxPrioritizedTransactions()) - .maxFutureBySender(defaultValue.getMaxFutureBySender()); - } - - @Override - ImmutableTransactionPoolConfiguration.Builder createCustomizedDomainObject() { - return ImmutableTransactionPoolConfiguration.builder() - .strictTransactionReplayProtectionEnabled(true) - .txMessageKeepAliveSeconds(TransactionPoolConfiguration.DEFAULT_TX_MSG_KEEP_ALIVE + 1) - .eth65TrxAnnouncedBufferingPeriod( - TransactionPoolConfiguration.ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD.plus( - Duration.ofMillis(100))) - .layeredTxPoolEnabled(true) - .pendingTransactionsLayerMaxCapacityBytes(1_000_000L) - .maxPrioritizedTransactions(1000) - .maxFutureBySender(10); - } - - @Override - TransactionPoolOptions optionsFromDomainObject( - final ImmutableTransactionPoolConfiguration.Builder domainObject) { - return TransactionPoolOptions.fromConfig(domainObject.build()); - } - - @Override - TransactionPoolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { - return besuCommand.getTransactionPoolOptions(); - } -} diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptionsTest.java new file mode 100644 index 00000000000..1f0705e9948 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptionsTest.java @@ -0,0 +1,243 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.options.stable; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LEGACY; + +import org.hyperledger.besu.cli.options.AbstractCLIOptionsTest; +import org.hyperledger.besu.cli.options.OptionParser; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.util.number.Percentage; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class TransactionPoolOptionsTest + extends AbstractCLIOptionsTest { + + @Test + public void strictTxReplayProtection_enabled() { + internalTestSuccess( + config -> assertThat(config.getStrictTransactionReplayProtectionEnabled()).isTrue(), + "--strict-tx-replay-protection-enabled"); + } + + @Test + public void strictTxReplayProtection_enabledWithBooleanArg() { + internalTestSuccess( + config -> assertThat(config.getStrictTransactionReplayProtectionEnabled()).isTrue(), + "--strict-tx-replay-protection-enabled=true"); + } + + @Test + public void strictTxReplayProtection_disabled() { + internalTestSuccess( + config -> assertThat(config.getStrictTransactionReplayProtectionEnabled()).isFalse(), + "--strict-tx-replay-protection-enabled=false"); + } + + @Test + public void strictTxReplayProtection_default() { + internalTestSuccess( + config -> assertThat(config.getStrictTransactionReplayProtectionEnabled()).isFalse()); + } + + @Test + public void pendingTransactionRetentionPeriod() { + final int pendingTxRetentionHours = 999; + internalTestSuccess( + config -> + assertThat(config.getPendingTxRetentionPeriod()).isEqualTo(pendingTxRetentionHours), + "--tx-pool-retention-hours", + String.valueOf(pendingTxRetentionHours), + "--tx-pool=legacy"); + } + + @Test + public void disableLocalsDefault() { + internalTestSuccess(config -> assertThat(config.getDisableLocalTransactions()).isFalse()); + } + + @Test + public void disableLocalsOn() { + internalTestSuccess( + config -> assertThat(config.getDisableLocalTransactions()).isTrue(), + "--tx-pool-disable-locals=true"); + } + + @Test + public void disableLocalsOff() { + internalTestSuccess( + config -> assertThat(config.getDisableLocalTransactions()).isFalse(), + "--tx-pool-disable-locals=false"); + } + + @Test + public void saveToFileDisabledByDefault() { + internalTestSuccess(config -> assertThat(config.getEnableSaveRestore()).isFalse()); + } + + @Test + public void saveToFileEnabledDefaultPath() { + internalTestSuccess( + config -> assertThat(config.getEnableSaveRestore()).isTrue(), + "--tx-pool-enable-save-restore=true"); + } + + @Test + public void saveToFileEnabledCustomPath() { + internalTestSuccess( + config -> { + assertThat(config.getEnableSaveRestore()).isTrue(); + assertThat(config.getSaveFile()).hasName("my.save.file"); + }, + "--tx-pool-enable-save-restore=true", + "--tx-pool-save-file=my.save.file"); + } + + @Test + public void senderLimited_derived() { + internalTestSuccess( + config -> assertThat(config.getTxPoolMaxFutureTransactionByAccount()).isEqualTo(9), + "--tx-pool-limit-by-account-percentage=0.002", + "--tx-pool=legacy"); + } + + @Test + public void senderLimitedFloor_derived() { + internalTestSuccess( + config -> assertThat(config.getTxPoolMaxFutureTransactionByAccount()).isEqualTo(1), + "--tx-pool-limit-by-account-percentage=0.0001", + "--tx-pool=legacy"); + } + + @Test + public void senderLimitedCeiling_violated() { + internalTestFailure( + "Invalid value for option '--tx-pool-limit-by-account-percentage'", + "--tx-pool-limit-by-account-percentage=1.00002341", + "--tx-pool=legacy"); + } + + @Test + public void priceBump() { + final Percentage priceBump = Percentage.fromInt(13); + internalTestSuccess( + config -> assertThat(config.getPriceBump()).isEqualTo(priceBump), + "--tx-pool-price-bump", + priceBump.toString()); + } + + @Test + public void invalidPriceBumpShouldFail() { + internalTestFailure( + "Invalid value: 101, should be a number between 0 and 100 inclusive", + "--tx-pool-price-bump", + "101"); + } + + @Test + public void txFeeCap() { + final Wei txFeeCap = Wei.fromEth(2); + internalTestSuccess( + config -> assertThat(config.getTxFeeCap()).isEqualTo(txFeeCap), + "--rpc-tx-feecap", + OptionParser.format(txFeeCap)); + } + + @Test + public void invalidTxFeeCapShouldFail() { + internalTestFailure( + "Invalid value for option '--rpc-tx-feecap'", + "cannot convert 'abcd' to Wei", + "--rpc-tx-feecap", + "abcd"); + } + + @Test + public void selectLayeredImplementationByDefault() { + internalTestSuccess(config -> assertThat(config.getTxPoolImplementation()).isEqualTo(LAYERED)); + } + + @Test + public void selectLayeredImplementationByArg() { + internalTestSuccess( + config -> assertThat(config.getTxPoolImplementation()).isEqualTo(LAYERED), + "--tx-pool=layered"); + } + + @Test + public void selectLegacyImplementationByArg() { + internalTestSuccess( + config -> assertThat(config.getTxPoolImplementation()).isEqualTo(LEGACY), + "--tx-pool=legacy"); + } + + @Test + public void failIfLegacyOptionsWhenLayeredSelectedByDefault() { + internalTestFailure( + "Could not use legacy transaction pool options with layered implementation", + "--tx-pool-max-size=1000"); + } + + @Test + public void failIfLegacyOptionsWhenLayeredSelectedByArg() { + internalTestFailure( + "Could not use legacy transaction pool options with layered implementation", + "--tx-pool=layered", + "--tx-pool-max-size=1000"); + } + + @Test + public void failIfLayeredOptionsWhenLegacySelectedByArg() { + internalTestFailure( + "Could not use layered transaction pool options with legacy implementation", + "--tx-pool=legacy", + "--tx-pool-max-prioritized=1000"); + } + + @Override + protected TransactionPoolConfiguration createDefaultDomainObject() { + return TransactionPoolConfiguration.DEFAULT; + } + + @Override + protected TransactionPoolConfiguration createCustomizedDomainObject() { + return ImmutableTransactionPoolConfiguration.builder() + .strictTransactionReplayProtectionEnabled(true) + .txPoolImplementation(LAYERED) + .pendingTransactionsLayerMaxCapacityBytes(1_000_000L) + .maxPrioritizedTransactions(1000) + .maxFutureBySender(10) + .build(); + } + + @Override + protected TransactionPoolOptions optionsFromDomainObject( + final TransactionPoolConfiguration domainObject) { + return TransactionPoolOptions.fromConfig(domainObject); + } + + @Override + protected TransactionPoolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { + return besuCommand.getStableTransactionPoolOptions(); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptionsTest.java new file mode 100644 index 00000000000..4fc44f05167 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptionsTest.java @@ -0,0 +1,105 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.options.unstable; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.cli.converter.DurationMillisConverter; +import org.hyperledger.besu.cli.options.AbstractCLIOptionsTest; +import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; + +import java.time.Duration; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class TransactionPoolOptionsTest + extends AbstractCLIOptionsTest { + + @Test + public void txMessageKeepAliveSeconds() { + final int txMessageKeepAliveSeconds = 999; + internalTestSuccess( + config -> + assertThat(config.getTxMessageKeepAliveSeconds()).isEqualTo(txMessageKeepAliveSeconds), + "--Xincoming-tx-messages-keep-alive-seconds", + String.valueOf(txMessageKeepAliveSeconds)); + } + + @Test + public void txMessageKeepAliveSecondsWithInvalidInputShouldFail() { + internalTestFailure( + "Invalid value for option '--Xincoming-tx-messages-keep-alive-seconds': 'acbd' is not an int", + "--Xincoming-tx-messages-keep-alive-seconds", + "acbd"); + } + + @Test + public void eth65TrxAnnouncedBufferingPeriod() { + final Duration eth65TrxAnnouncedBufferingPeriod = Duration.ofMillis(999); + internalTestSuccess( + config -> + assertThat(config.getEth65TrxAnnouncedBufferingPeriod()) + .isEqualTo(eth65TrxAnnouncedBufferingPeriod), + "--Xeth65-tx-announced-buffering-period-milliseconds", + new DurationMillisConverter().format(eth65TrxAnnouncedBufferingPeriod)); + } + + @Test + public void eth65TrxAnnouncedBufferingPeriodWithInvalidInputShouldFail() { + internalTestFailure( + "Invalid value for option '--Xeth65-tx-announced-buffering-period-milliseconds': cannot convert 'acbd' to Duration (org.hyperledger.besu.cli.converter.exception.DurationConversionException: 'acbd' is not a long)", + "--Xeth65-tx-announced-buffering-period-milliseconds", + "acbd"); + } + + @Test + public void eth65TrxAnnouncedBufferingPeriodWithInvalidInputShouldFail2() { + internalTestFailure( + "Invalid value for option '--Xeth65-tx-announced-buffering-period-milliseconds': cannot convert '-1' to Duration (org.hyperledger.besu.cli.converter.exception.DurationConversionException: negative value '-1' is not allowed)", + "--Xeth65-tx-announced-buffering-period-milliseconds", + "-1"); + } + + @Override + protected TransactionPoolConfiguration.Unstable createDefaultDomainObject() { + return TransactionPoolConfiguration.Unstable.DEFAULT; + } + + @Override + protected TransactionPoolConfiguration.Unstable createCustomizedDomainObject() { + return ImmutableTransactionPoolConfiguration.Unstable.builder() + .txMessageKeepAliveSeconds( + TransactionPoolConfiguration.Unstable.DEFAULT_TX_MSG_KEEP_ALIVE + 1) + .eth65TrxAnnouncedBufferingPeriod( + TransactionPoolConfiguration.Unstable.ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD.plus( + Duration.ofMillis(100))) + .build(); + } + + @Override + protected TransactionPoolOptions optionsFromDomainObject( + final TransactionPoolConfiguration.Unstable domainObject) { + return TransactionPoolOptions.fromConfig(domainObject); + } + + @Override + protected TransactionPoolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { + return besuCommand.getUnstableTransactionPoolOptions(); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java index fd35430e273..c7c6466e602 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.controller; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -55,6 +54,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.math.BigInteger; @@ -85,16 +85,17 @@ public class BesuControllerBuilderTest { @Mock SynchronizerConfiguration synchronizerConfiguration; @Mock EthProtocolConfiguration ethProtocolConfiguration; @Mock MiningParameters miningParameters; - @Mock ObservableMetricsSystem observableMetricsSystem; @Mock PrivacyParameters privacyParameters; @Mock Clock clock; - @Mock TransactionPoolConfiguration poolConfiguration; @Mock StorageProvider storageProvider; @Mock GasLimitCalculator gasLimitCalculator; @Mock WorldStateStorage worldStateStorage; @Mock WorldStateArchive worldStateArchive; @Mock BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage; @Mock WorldStatePreimageStorage worldStatePreimageStorage; + private final TransactionPoolConfiguration poolConfiguration = + TransactionPoolConfiguration.DEFAULT; + private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); BigInteger networkId = BigInteger.ONE; @@ -127,10 +128,6 @@ public void setup() { when(synchronizerConfiguration.getBlockPropagationRange()).thenReturn(Range.closed(1L, 2L)); - when(observableMetricsSystem.createLabelledCounter( - any(), anyString(), anyString(), anyString())) - .thenReturn(labels -> null); - when(storageProvider.createWorldStateStorage(DataStorageFormat.FOREST)) .thenReturn(worldStateStorage); when(storageProvider.createWorldStatePreimageStorage()).thenReturn(worldStatePreimageStorage); diff --git a/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java index 15fb3fd3ec2..b1f59554af3 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java @@ -18,7 +18,6 @@ import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -58,6 +57,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.math.BigInteger; @@ -90,10 +90,8 @@ public class MergeBesuControllerBuilderTest { @Mock EthProtocolConfiguration ethProtocolConfiguration; @Mock CheckpointConfigOptions checkpointConfigOptions; @Mock MiningParameters miningParameters; - @Mock ObservableMetricsSystem observableMetricsSystem; @Mock PrivacyParameters privacyParameters; @Mock Clock clock; - @Mock TransactionPoolConfiguration poolConfiguration; @Mock StorageProvider storageProvider; @Mock GasLimitCalculator gasLimitCalculator; @Mock WorldStateStorage worldStateStorage; @@ -102,6 +100,9 @@ public class MergeBesuControllerBuilderTest { BigInteger networkId = BigInteger.ONE; private final BlockHeaderTestFixture headerGenerator = new BlockHeaderTestFixture(); private final BaseFeeMarket feeMarket = new LondonFeeMarket(0, Optional.of(Wei.of(42))); + private final TransactionPoolConfiguration poolConfiguration = + TransactionPoolConfiguration.DEFAULT; + private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); @Rule public final TemporaryFolder tempDirRule = new TemporaryFolder(); @@ -134,10 +135,6 @@ public void setup() { when(synchronizerConfiguration.getBlockPropagationRange()).thenReturn(Range.closed(1L, 2L)); - when(observableMetricsSystem.createLabelledCounter( - any(), anyString(), anyString(), anyString())) - .thenReturn(labels -> null); - when(storageProvider.createWorldStateStorage(DataStorageFormat.FOREST)) .thenReturn(worldStateStorage); when(storageProvider.createWorldStatePreimageStorage()).thenReturn(worldStatePreimageStorage); diff --git a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java index 395abeb22d6..585f138027e 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java @@ -17,7 +17,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -53,6 +52,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.math.BigInteger; @@ -80,16 +80,17 @@ public class QbftBesuControllerBuilderTest { @Mock private EthProtocolConfiguration ethProtocolConfiguration; @Mock CheckpointConfigOptions checkpointConfigOptions; @Mock private MiningParameters miningParameters; - @Mock private ObservableMetricsSystem observableMetricsSystem; @Mock private PrivacyParameters privacyParameters; @Mock private Clock clock; - @Mock private TransactionPoolConfiguration poolConfiguration; @Mock private StorageProvider storageProvider; @Mock private GasLimitCalculator gasLimitCalculator; @Mock private WorldStateStorage worldStateStorage; @Mock private WorldStatePreimageStorage worldStatePreimageStorage; private static final BigInteger networkId = BigInteger.ONE; private static final NodeKey nodeKey = NodeKeyUtils.generate(); + private final TransactionPoolConfiguration poolConfiguration = + TransactionPoolConfiguration.DEFAULT; + private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); @Rule public final TemporaryFolder tempDirRule = new TemporaryFolder(); @@ -120,9 +121,7 @@ public void setup() { when(synchronizerConfiguration.getDownloaderParallelism()).thenReturn(1); when(synchronizerConfiguration.getTransactionsParallelism()).thenReturn(1); when(synchronizerConfiguration.getComputationParallelism()).thenReturn(1); - when(observableMetricsSystem.createLabelledCounter( - any(), anyString(), anyString(), anyString())) - .thenReturn(labels -> null); + when(synchronizerConfiguration.getBlockPropagationRange()).thenReturn(Range.closed(1L, 2L)); // qbft prepForBuild setup diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index 459346dc537..e88acec6dc9 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -170,16 +170,21 @@ privacy-onchain-groups-enabled=false privacy-flexible-groups-enabled=false # Transaction Pool -tx-pool-retention-hours=999 +tx-pool="layered" tx-pool-price-bump=13 -tx-pool-max-size=1234 -tx-pool-limit-by-account-percentage=0.017 -Xincoming-tx-messages-keep-alive-seconds=60 rpc-tx-feecap=2000000000000000000 strict-tx-replay-protection-enabled=true tx-pool-disable-locals=false tx-pool-enable-save-restore=true tx-pool-save-file="txpool.dump" +## Layered +tx-pool-layer-max-capacity=12345678 +tx-pool-max-prioritized=9876 +tx-pool-max-future-by-sender=321 +## Legacy +tx-pool-retention-hours=999 +tx-pool-max-size=1234 +tx-pool-limit-by-account-percentage=0.017 # Revert Reason revert-reason-enabled=false diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java index 95f1d24f220..d118a186af1 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java @@ -76,6 +76,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.StubMetricsSystem; import org.hyperledger.besu.testutil.TestClock; +import org.hyperledger.besu.util.number.Fraction; import java.time.ZoneId; import java.util.ArrayList; @@ -161,7 +162,7 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper { private final TransactionPoolConfiguration poolConf = ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(10) - .txPoolLimitByAccountPercentage(100.0f) + .txPoolLimitByAccountPercentage(Fraction.fromPercentage(100)) .build(); private final BaseFeePendingTransactionsSorter transactions = new BaseFeePendingTransactionsSorter( diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java index c0e68efd706..261c3d5f895 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.testutil.TestClock; +import org.hyperledger.besu.util.number.Fraction; import java.time.ZoneId; import java.util.function.Function; @@ -64,7 +65,7 @@ protected TransactionPool createTransactionPool() { final TransactionPoolConfiguration poolConf = ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(5) - .txPoolLimitByAccountPercentage(1) + .txPoolLimitByAccountPercentage(Fraction.fromFloat(1f)) .build(); final PendingTransactions pendingTransactions = diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java index 82cb1b0d89b..252f7f03655 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.testutil.TestClock; +import org.hyperledger.besu.util.number.Fraction; import java.time.ZoneId; import java.util.List; @@ -72,7 +73,7 @@ protected TransactionPool createTransactionPool() { final TransactionPoolConfiguration poolConf = ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(5) - .txPoolLimitByAccountPercentage(1) + .txPoolLimitByAccountPercentage(Fraction.fromFloat(1f)) .build(); final PendingTransactions pendingTransactions = new BaseFeePendingTransactionsSorter( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessor.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessor.java index 4717e2d9e1d..ede1b60beb1 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessor.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessor.java @@ -101,8 +101,12 @@ private void processNewPooledTransactionHashesMessage( .getScheduler() .scheduleFutureTaskWithFixedDelay( new FetcherCreatorTask(peer), - transactionPoolConfiguration.getEth65TrxAnnouncedBufferingPeriod(), - transactionPoolConfiguration.getEth65TrxAnnouncedBufferingPeriod()); + transactionPoolConfiguration + .getUnstable() + .getEth65TrxAnnouncedBufferingPeriod(), + transactionPoolConfiguration + .getUnstable() + .getEth65TrxAnnouncedBufferingPeriod()); return new BufferedGetPooledTransactionsFromPeerFetcher( ethContext, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolConfiguration.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolConfiguration.java index ddcb06f8a9d..fbab05d2337 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolConfiguration.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolConfiguration.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.eth.transactions; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.util.number.Fraction; import org.hyperledger.besu.util.number.Percentage; import java.io.File; @@ -24,16 +25,41 @@ @Value.Immutable @Value.Style(allParameters = true) +@Value.Enclosing public interface TransactionPoolConfiguration { + + @Value.Immutable + interface Unstable { + Duration ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD = Duration.ofMillis(500); + int DEFAULT_TX_MSG_KEEP_ALIVE = 60; + + TransactionPoolConfiguration.Unstable DEFAULT = + ImmutableTransactionPoolConfiguration.Unstable.builder().build(); + + @Value.Default + default Duration getEth65TrxAnnouncedBufferingPeriod() { + return ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD; + } + + @Value.Default + default int getTxMessageKeepAliveSeconds() { + return DEFAULT_TX_MSG_KEEP_ALIVE; + } + } + + enum Implementation { + LEGACY, + LAYERED; + } + String DEFAULT_SAVE_FILE_NAME = "txpool.dump"; - int DEFAULT_TX_MSG_KEEP_ALIVE = 60; + int DEFAULT_MAX_PENDING_TRANSACTIONS = 4096; - float DEFAULT_LIMIT_TX_POOL_BY_ACCOUNT_PERCENTAGE = 0.001f; // 0.1% + Fraction DEFAULT_LIMIT_TX_POOL_BY_ACCOUNT_PERCENTAGE = Fraction.fromFloat(0.001f); // 0.1% int DEFAULT_TX_RETENTION_HOURS = 13; boolean DEFAULT_STRICT_TX_REPLAY_PROTECTION_ENABLED = false; Percentage DEFAULT_PRICE_BUMP = Percentage.fromInt(10); Wei DEFAULT_RPC_TX_FEE_CAP = Wei.fromEth(1); - Duration ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD = Duration.ofMillis(500); boolean DEFAULT_DISABLE_LOCAL_TXS = false; boolean DEFAULT_ENABLE_SAVE_RESTORE = false; @@ -41,7 +67,7 @@ public interface TransactionPoolConfiguration { long DEFAULT_PENDING_TRANSACTIONS_LAYER_MAX_CAPACITY_BYTES = 50_000_000L; int DEFAULT_MAX_PRIORITIZED_TRANSACTIONS = 2000; int DEFAULT_MAX_FUTURE_BY_SENDER = 200; - boolean DEFAULT_LAYERED_TX_POOL_ENABLED = false; + Implementation DEFAULT_TX_POOL_IMPLEMENTATION = Implementation.LAYERED; TransactionPoolConfiguration DEFAULT = ImmutableTransactionPoolConfiguration.builder().build(); @@ -51,13 +77,13 @@ default int getTxPoolMaxSize() { } @Value.Default - default float getTxPoolLimitByAccountPercentage() { + default Fraction getTxPoolLimitByAccountPercentage() { return DEFAULT_LIMIT_TX_POOL_BY_ACCOUNT_PERCENTAGE; } @Value.Derived default int getTxPoolMaxFutureTransactionByAccount() { - return (int) Math.ceil(getTxPoolLimitByAccountPercentage() * getTxPoolMaxSize()); + return (int) Math.ceil(getTxPoolLimitByAccountPercentage().getValue() * getTxPoolMaxSize()); } @Value.Default @@ -65,21 +91,11 @@ default int getPendingTxRetentionPeriod() { return DEFAULT_TX_RETENTION_HOURS; } - @Value.Default - default int getTxMessageKeepAliveSeconds() { - return DEFAULT_TX_MSG_KEEP_ALIVE; - } - @Value.Default default Percentage getPriceBump() { return DEFAULT_PRICE_BUMP; } - @Value.Default - default Duration getEth65TrxAnnouncedBufferingPeriod() { - return ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD; - } - @Value.Default default Wei getTxFeeCap() { return DEFAULT_RPC_TX_FEE_CAP; @@ -106,8 +122,8 @@ default File getSaveFile() { } @Value.Default - default Boolean getLayeredTxPoolEnabled() { - return DEFAULT_LAYERED_TX_POOL_ENABLED; + default Implementation getTxPoolImplementation() { + return DEFAULT_TX_POOL_IMPLEMENTATION; } @Value.Default @@ -124,4 +140,9 @@ default int getMaxPrioritizedTransactions() { default int getMaxFutureBySender() { return DEFAULT_MAX_FUTURE_BY_SENDER; } + + @Value.Default + default Unstable getUnstable() { + return Unstable.DEFAULT; + } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactory.java index 16a05922864..08d2aae5169 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactory.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.eth.transactions; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED; + import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -31,7 +33,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.sorter.BaseFeePendingTransactionsSorter; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.plugin.services.BesuEvents; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -115,7 +117,7 @@ static TransactionPool createTransactionPool( new TransactionsMessageHandler( ethContext.getScheduler(), new TransactionsMessageProcessor(transactionTracker, transactionPool, metrics), - transactionPoolConfiguration.getTxMessageKeepAliveSeconds()); + transactionPoolConfiguration.getUnstable().getTxMessageKeepAliveSeconds()); final NewPooledTransactionHashesMessageHandler pooledTransactionsMessageHandler = new NewPooledTransactionHashesMessageHandler( @@ -126,7 +128,7 @@ static TransactionPool createTransactionPool( transactionPoolConfiguration, ethContext, metrics), - transactionPoolConfiguration.getTxMessageKeepAliveSeconds()); + transactionPoolConfiguration.getUnstable().getTxMessageKeepAliveSeconds()); subscribeTransactionHandlers( protocolContext, @@ -194,8 +196,7 @@ private static PendingTransactions createPendingTransactions( protocolSchedule.anyMatch( scheduledSpec -> scheduledSpec.spec().getFeeMarket().implementsBaseFee()); - if (transactionPoolConfiguration.getLayeredTxPoolEnabled()) { - LOG.info("Using layered transaction pool"); + if (transactionPoolConfiguration.getTxPoolImplementation().equals(LAYERED)) { return createLayeredPendingTransactions( protocolSchedule, protocolContext, @@ -263,11 +264,10 @@ private static PendingTransactions createLayeredPendingTransactions( final AbstractPrioritizedTransactions pendingTransactionsSorter; if (isFeeMarketImplementBaseFee) { - final BaseFeeMarket baseFeeMarket = - (BaseFeeMarket) - protocolSchedule - .getByBlockHeader(protocolContext.getBlockchain().getChainHeadHeader()) - .getFeeMarket(); + final FeeMarket feeMarket = + protocolSchedule + .getByBlockHeader(protocolContext.getBlockchain().getChainHeadHeader()) + .getFeeMarket(); pendingTransactionsSorter = new BaseFeePrioritizedTransactions( @@ -276,7 +276,7 @@ private static PendingTransactions createLayeredPendingTransactions( readyTransactions, metrics, transactionReplacementTester, - baseFeeMarket); + feeMarket); } else { pendingTransactionsSorter = new GasPricePrioritizedTransactions( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractTransactionsLayer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractTransactionsLayer.java index b7fea830a7b..0feae3168de 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractTransactionsLayer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractTransactionsLayer.java @@ -330,6 +330,7 @@ protected void replaced(final PendingTransaction replacedTx) { decreaseSpaceUsed(replacedTx); metrics.incrementRemoved(replacedTx.isReceivedFromLocalSource(), REPLACED.label(), name()); internalReplaced(replacedTx); + notifyTransactionDropped(replacedTx); } protected abstract void internalReplaced(final PendingTransaction replacedTx); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactions.java index e95d431bc6d..b715f4c324c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactions.java @@ -50,10 +50,10 @@ public BaseFeePrioritizedTransactions( final TransactionPoolMetrics metrics, final BiFunction transactionReplacementTester, - final BaseFeeMarket baseFeeMarket) { + final FeeMarket feeMarket) { super(poolConfig, nextLayer, metrics, transactionReplacementTester); this.nextBlockBaseFee = - Optional.of(calculateNextBlockBaseFee(baseFeeMarket, chainHeadHeaderSupplier.get())); + Optional.of(calculateNextBlockBaseFee(feeMarket, chainHeadHeaderSupplier.get())); } @Override @@ -71,8 +71,7 @@ protected int compareByFee(final PendingTransaction pt1, final PendingTransactio @Override protected void internalBlockAdded(final BlockHeader blockHeader, final FeeMarket feeMarket) { - final BaseFeeMarket baseFeeMarket = (BaseFeeMarket) feeMarket; - final Wei newNextBlockBaseFee = calculateNextBlockBaseFee(baseFeeMarket, blockHeader); + final Wei newNextBlockBaseFee = calculateNextBlockBaseFee(feeMarket, blockHeader); LOG.atTrace() .setMessage("Updating base fee from {} to {}") @@ -85,13 +84,16 @@ protected void internalBlockAdded(final BlockHeader blockHeader, final FeeMarket orderByFee.addAll(pendingTransactions.values()); } - private Wei calculateNextBlockBaseFee( - final BaseFeeMarket baseFeeMarket, final BlockHeader blockHeader) { - return baseFeeMarket.computeBaseFee( - blockHeader.getNumber() + 1, - blockHeader.getBaseFee().orElse(Wei.ZERO), - blockHeader.getGasUsed(), - baseFeeMarket.targetGasUsed(blockHeader)); + private Wei calculateNextBlockBaseFee(final FeeMarket feeMarket, final BlockHeader blockHeader) { + if (feeMarket.implementsBaseFee()) { + final var baseFeeMarket = (BaseFeeMarket) feeMarket; + return baseFeeMarket.computeBaseFee( + blockHeader.getNumber() + 1, + blockHeader.getBaseFee().orElse(Wei.ZERO), + blockHeader.getGasUsed(), + baseFeeMarket.targetGasUsed(blockHeader)); + } + return Wei.ZERO; } @Override diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessorTest.java index 4b137ca3937..5c3f08ddfa1 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessorTest.java @@ -21,6 +21,7 @@ import static org.hyperledger.besu.ethereum.eth.encoding.TransactionAnnouncementDecoder.getDecoder; import static org.hyperledger.besu.ethereum.eth.encoding.TransactionAnnouncementEncoder.getEncoder; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Answers.RETURNS_DEEP_STUBS; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -66,7 +67,10 @@ public class NewPooledTransactionHashesMessageProcessorTest { @Mock private TransactionPool transactionPool; - @Mock private TransactionPoolConfiguration transactionPoolConfiguration; + + @Mock(answer = RETURNS_DEEP_STUBS) + private TransactionPoolConfiguration transactionPoolConfiguration; + @Mock private PeerTransactionTracker transactionTracker; @Mock private EthPeer peer1; @Mock private EthContext ethContext; @@ -88,7 +92,7 @@ public class NewPooledTransactionHashesMessageProcessorTest { @BeforeEach public void setup() { metricsSystem = new StubMetricsSystem(); - when(transactionPoolConfiguration.getEth65TrxAnnouncedBufferingPeriod()) + when(transactionPoolConfiguration.getUnstable().getEth65TrxAnnouncedBufferingPeriod()) .thenReturn(Duration.ofMillis(500)); messageHandler = new NewPooledTransactionHashesMessageProcessor( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index 78641da086d..fb56be15f8a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.eth.transactions; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED; import static org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule.DEFAULT_CHAIN_ID; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; @@ -41,6 +42,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; +import org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredPendingTransactions; import org.hyperledger.besu.ethereum.eth.transactions.sorter.BaseFeePendingTransactionsSorter; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.forkid.ForkIdManager; @@ -242,8 +244,11 @@ private void setupInitialSyncPhase(final boolean hasInitialSyncPhase) { new MiningParameters.Builder().minTransactionGasPrice(Wei.ONE).build(), ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(1) - .txMessageKeepAliveSeconds(1) .pendingTxRetentionPeriod(1) + .unstable( + ImmutableTransactionPoolConfiguration.Unstable.builder() + .txMessageKeepAliveSeconds(1) + .build()) .build(), peerTransactionTracker, transactionsMessageSender, @@ -267,10 +272,12 @@ private void setupInitialSyncPhase(final boolean hasInitialSyncPhase) { } @Test - public void createTransactionPool_shouldUseBaseFeePendingTransactionsSorter_whenLondonEnabled() { + public void + createLegacyTransactionPool_shouldUseBaseFeePendingTransactionsSorter_whenLondonEnabled() { setupScheduleWith(new StubGenesisConfigOptions().londonBlock(0)); - final TransactionPool pool = createTransactionPool(); + final TransactionPool pool = + createTransactionPool(TransactionPoolConfiguration.Implementation.LEGACY); assertThat(pool.pendingTransactionsImplementation()) .isEqualTo(BaseFeePendingTransactionsSorter.class); @@ -278,15 +285,42 @@ public void createTransactionPool_shouldUseBaseFeePendingTransactionsSorter_when @Test public void - createTransactionPool_shouldUseGasPricePendingTransactionsSorter_whenLondonNotEnabled() { + createLegacyTransactionPool_shouldUseGasPricePendingTransactionsSorter_whenLondonNotEnabled() { setupScheduleWith(new StubGenesisConfigOptions().berlinBlock(0)); - final TransactionPool pool = createTransactionPool(); + final TransactionPool pool = + createTransactionPool(TransactionPoolConfiguration.Implementation.LEGACY); assertThat(pool.pendingTransactionsImplementation()) .isEqualTo(GasPricePendingTransactionsSorter.class); } + @Test + public void + createLayeredTransactionPool_shouldUseBaseFeePendingTransactionsSorter_whenLondonEnabled() { + setupScheduleWith(new StubGenesisConfigOptions().londonBlock(0)); + + final TransactionPool pool = createTransactionPool(LAYERED); + + assertThat(pool.pendingTransactionsImplementation()) + .isEqualTo(LayeredPendingTransactions.class); + + assertThat(pool.logStats()).startsWith("Basefee Prioritized"); + } + + @Test + public void + createLayeredTransactionPool_shouldUseGasPricePendingTransactionsSorter_whenLondonNotEnabled() { + setupScheduleWith(new StubGenesisConfigOptions().berlinBlock(0)); + + final TransactionPool pool = createTransactionPool(LAYERED); + + assertThat(pool.pendingTransactionsImplementation()) + .isEqualTo(LayeredPendingTransactions.class); + + assertThat(pool.logStats()).startsWith("GasPrice Prioritized"); + } + private void setupScheduleWith(final StubGenesisConfigOptions config) { schedule = new ProtocolScheduleBuilder( @@ -305,7 +339,8 @@ private void setupScheduleWith(final StubGenesisConfigOptions config) { syncState = new SyncState(blockchain, ethPeers, true, Optional.empty()); } - private TransactionPool createTransactionPool() { + private TransactionPool createTransactionPool( + final TransactionPoolConfiguration.Implementation implementation) { final TransactionPool txPool = TransactionPoolFactory.createTransactionPool( schedule, @@ -316,9 +351,13 @@ private TransactionPool createTransactionPool() { syncState, new MiningParameters.Builder().minTransactionGasPrice(Wei.ONE).build(), ImmutableTransactionPoolConfiguration.builder() + .txPoolImplementation(implementation) .txPoolMaxSize(1) - .txMessageKeepAliveSeconds(1) .pendingTxRetentionPeriod(1) + .unstable( + ImmutableTransactionPoolConfiguration.Unstable.builder() + .txMessageKeepAliveSeconds(1) + .build()) .build()); txPool.setEnabled(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLegacyTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLegacyTest.java index e2e2946f3c9..cc40d47aec0 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLegacyTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLegacyTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.testutil.TestClock; +import org.hyperledger.besu.util.number.Fraction; import java.math.BigInteger; import java.time.ZoneId; @@ -57,7 +58,7 @@ protected PendingTransactions createPendingTransactionsSorter() { return new GasPricePendingTransactionsSorter( ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(MAX_TRANSACTIONS) - .txPoolLimitByAccountPercentage(1) + .txPoolLimitByAccountPercentage(Fraction.fromFloat(1.0f)) .build(), TestClock.system(ZoneId.systemDefault()), metricsSystem, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java index fc03f9805ce..e546684ffdc 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java @@ -42,6 +42,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.testutil.TestClock; +import org.hyperledger.besu.util.number.Fraction; import java.math.BigInteger; import java.time.ZoneId; @@ -63,7 +64,7 @@ protected PendingTransactions createPendingTransactionsSorter() { return new BaseFeePendingTransactionsSorter( ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(MAX_TRANSACTIONS) - .txPoolLimitByAccountPercentage(1) + .txPoolLimitByAccountPercentage(Fraction.fromFloat(1.0f)) .build(), TestClock.system(ZoneId.systemDefault()), metricsSystem, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java index 6b2318f0086..1aff575f2e5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java @@ -45,6 +45,7 @@ import org.hyperledger.besu.metrics.StubMetricsSystem; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.testutil.TestClock; +import org.hyperledger.besu.util.number.Fraction; import java.time.Clock; import java.time.temporal.ChronoUnit; @@ -80,13 +81,14 @@ public abstract class AbstractPendingTransactionsTestBase { getPendingTransactions( ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(MAX_TRANSACTIONS) - .txPoolLimitByAccountPercentage(1.0f) + .txPoolLimitByAccountPercentage(Fraction.fromFloat(1.0f)) .build(), Optional.empty()); private final TransactionPoolConfiguration senderLimitedConfig = ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(MAX_TRANSACTIONS) - .txPoolLimitByAccountPercentage(LIMITED_TRANSACTIONS_BY_SENDER_PERCENTAGE) + .txPoolLimitByAccountPercentage( + Fraction.fromFloat(LIMITED_TRANSACTIONS_BY_SENDER_PERCENTAGE)) .build(); protected PendingTransactions senderLimitedTransactions = getPendingTransactions(senderLimitedConfig, Optional.empty()); @@ -622,7 +624,7 @@ public void shouldEvictMultipleOldTransactions() { ImmutableTransactionPoolConfiguration.builder() .pendingTxRetentionPeriod(maxTransactionRetentionHours) .txPoolMaxSize(MAX_TRANSACTIONS) - .txPoolLimitByAccountPercentage(1) + .txPoolLimitByAccountPercentage(Fraction.fromFloat(1.0f)) .build(), Optional.of(clock)); @@ -644,7 +646,7 @@ public void shouldEvictSingleOldTransaction() { ImmutableTransactionPoolConfiguration.builder() .pendingTxRetentionPeriod(1) .txPoolMaxSize(MAX_TRANSACTIONS) - .txPoolLimitByAccountPercentage(1.0f) + .txPoolLimitByAccountPercentage(Fraction.fromFloat(1.0f)) .build(), Optional.of(clock)); evictSingleTransactions.addRemoteTransaction(transaction1, Optional.empty()); @@ -662,7 +664,7 @@ public void shouldEvictExclusivelyOldTransactions() { ImmutableTransactionPoolConfiguration.builder() .pendingTxRetentionPeriod(2) .txPoolMaxSize(MAX_TRANSACTIONS) - .txPoolLimitByAccountPercentage(1.0f) + .txPoolLimitByAccountPercentage(Fraction.fromFloat(1.0f)) .build(), Optional.of(clock)); diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java index 52cc2a3ce04..1f2af463a97 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java @@ -65,6 +65,7 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.util.Subscribers; +import org.hyperledger.besu.util.number.Fraction; import java.util.Collections; import java.util.Optional; @@ -227,7 +228,7 @@ private boolean buildContext( final TransactionPoolConfiguration transactionPoolConfiguration = ImmutableTransactionPoolConfiguration.builder() - .txPoolLimitByAccountPercentage(0.004f) + .txPoolLimitByAccountPercentage(Fraction.fromFloat(0.004f)) .build(); transactionPool = From 832f02e5289c9f5217e3ac8249d86cfee1ce9f99 Mon Sep 17 00:00:00 2001 From: ahamlat Date: Mon, 11 Sep 2023 13:21:59 +0200 Subject: [PATCH 15/34] Fix issue 5824 - Duplicate key errors in EthScheduler-Transactions (#5857) Fix issue 5824 - Duplicate key errors in EthScheduler-Transactions Signed-off-by: Ameziane H Signed-off-by: garyschulte --- CHANGELOG.md | 2 ++ .../eth/transactions/TransactionPool.java | 3 ++- .../TransactionPoolLondonTest.java | 21 +++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ed641a1b06..5eab7194849 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ - Layered transaction pool implementation is now stable and enabled by default. If you want still to use the legacy implementation, use `--tx-pool=legacy` [#5772](https://github.com/hyperledger/besu) ### Bug Fixes +- do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) +- fix duplicate key errors in EthScheduler-Transactions [#5857](https://github.com/hyperledger/besu/pull/5857) - do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) ### Download Links diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java index 41978bcb932..9f5cc273b29 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java @@ -218,7 +218,8 @@ public Map> addRemoteTransactio addedTransactions.add(transaction); } return result; - })); + }, + (transaction1, transaction2) -> transaction1)); LOG_FOR_REPLAY .atTrace() diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java index e546684ffdc..2f151cac80d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolLondonTest.java @@ -18,6 +18,7 @@ import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.mockito.Mockito.when; import org.hyperledger.besu.config.StubGenesisConfigOptions; @@ -54,6 +55,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +@SuppressWarnings("unchecked") public class TransactionPoolLondonTest extends AbstractTransactionPoolTest { private static final Wei BASE_FEE_FLOOR = Wei.of(7L); @@ -253,6 +255,25 @@ public void shouldAcceptLocal1559TxsWhenMaxFeePerGasIsAtLeastEqualToMinMinGasPri .isEqualTo(1); } + @Test + public void addRemoteTransactionsShouldAllowDuplicates() { + final Transaction transaction1 = createTransaction(1, Wei.of(7L)); + final Transaction transaction2 = createTransaction(2, Wei.of(7L)); + final Transaction transaction3 = createTransaction(2, Wei.of(7L)); + final Transaction transaction4 = createTransaction(3, Wei.of(7L)); + + givenTransactionIsValid(transaction1); + givenTransactionIsValid(transaction2); + givenTransactionIsValid(transaction3); + givenTransactionIsValid(transaction4); + + assertThatCode( + () -> + transactionPool.addRemoteTransactions( + List.of(transaction1, transaction2, transaction3, transaction4))) + .doesNotThrowAnyException(); + } + private int add1559TxAndGetPendingTxsCount( final Wei genesisBaseFee, final Wei minGasPrice, From 5032e7350d184c0edb8134377d0853bf39970f4d Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Wed, 13 Sep 2023 15:03:31 +1000 Subject: [PATCH 16/34] updated gradle verification metadata (#5870) * removed old artefacts [skip ci] * works with compileTestJava * restored metadata needed for codeQL and trusted-artifacts block for javadoc/sources Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane Signed-off-by: garyschulte --- gradle/verification-metadata.xml | 670 +------------------------------ 1 file changed, 10 insertions(+), 660 deletions(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 82f6b48f02c..19dd9582b90 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -84,11 +84,6 @@ - - - - - @@ -104,11 +99,6 @@ - - - - - @@ -139,11 +129,6 @@ - - - - - @@ -184,11 +169,6 @@ - - - - - @@ -346,11 +326,6 @@ - - - - - @@ -362,11 +337,6 @@ - - - - - @@ -451,22 +421,6 @@ - - - - - - - - - - - - - - - - @@ -514,9 +468,6 @@ - - - @@ -834,14 +785,6 @@ - - - - - - - - @@ -884,11 +827,6 @@ - - - - - @@ -1205,14 +1143,6 @@ - - - - - - - - @@ -1463,17 +1393,6 @@ - - - - - - - - - - - @@ -2571,14 +2490,6 @@ - - - - - - - - @@ -2587,14 +2498,6 @@ - - - - - - - - @@ -2603,14 +2506,6 @@ - - - - - - - - @@ -2619,14 +2514,6 @@ - - - - - - - - @@ -2635,14 +2522,6 @@ - - - - - - - - @@ -2651,14 +2530,6 @@ - - - - - - - - @@ -2667,14 +2538,6 @@ - - - - - - - - @@ -2683,14 +2546,6 @@ - - - - - - - - @@ -2699,14 +2554,6 @@ - - - - - - - - @@ -2715,14 +2562,6 @@ - - - - - - - - @@ -2731,14 +2570,6 @@ - - - - - - - - @@ -2747,14 +2578,6 @@ - - - - - - - - @@ -2763,14 +2586,6 @@ - - - - - - - - @@ -2779,14 +2594,6 @@ - - - - - - - - @@ -2795,14 +2602,6 @@ - - - - - - - - @@ -2856,11 +2655,6 @@ - - - - - @@ -2889,14 +2683,6 @@ - - - - - - - - @@ -2905,14 +2691,6 @@ - - - - - - - - @@ -2921,11 +2699,6 @@ - - - - - @@ -3036,14 +2809,6 @@ - - - - - - - - @@ -3223,14 +2988,6 @@ - - - - - - - - @@ -3252,22 +3009,6 @@ - - - - - - - - - - - - - - - - @@ -3276,37 +3017,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3671,38 +3386,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3711,30 +3394,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -3743,46 +3402,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3791,22 +3410,6 @@ - - - - - - - - - - - - - - - - @@ -3815,14 +3418,6 @@ - - - - - - - - @@ -3878,22 +3473,6 @@ - - - - - - - - - - - - - - - - @@ -3918,14 +3497,6 @@ - - - - - - - - @@ -3934,22 +3505,6 @@ - - - - - - - - - - - - - - - - @@ -4374,16 +3929,16 @@ - - - - - + + + + + @@ -4472,16 +4027,16 @@ - - - - - + + + + + @@ -4503,14 +4058,6 @@ - - - - - - - - @@ -4519,11 +4066,6 @@ - - - - - @@ -4614,17 +4156,6 @@ - - - - - - - - - - - @@ -4636,17 +4167,6 @@ - - - - - - - - - - - @@ -4658,17 +4178,6 @@ - - - - - - - - - - - @@ -4680,17 +4189,6 @@ - - - - - - - - - - - @@ -4702,17 +4200,6 @@ - - - - - - - - - - - @@ -4724,17 +4211,6 @@ - - - - - - - - - - - @@ -4994,24 +4470,11 @@ - - - - - - - - - - - - - @@ -5020,17 +4483,6 @@ - - - - - - - - - - - @@ -5042,17 +4494,6 @@ - - - - - - - - - - - @@ -5376,39 +4817,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5554,11 +4962,6 @@ - - - - - @@ -5569,14 +4972,6 @@ - - - - - - - - @@ -5609,14 +5004,6 @@ - - - - - - - - @@ -5625,14 +5012,6 @@ - - - - - - - - @@ -5641,19 +5020,6 @@ - - - - - - - - - - - - - @@ -5662,14 +5028,6 @@ - - - - - - - - @@ -5723,14 +5081,6 @@ - - - - - - - - From 951b09d99fe35ea55610be0b33ce115f932b04ba Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Wed, 13 Sep 2023 15:34:04 +1000 Subject: [PATCH 17/34] [4844] Add encodingContext to TransactionEncoder and TransactionDecoder (#5820) * Add decode type to TransactionDecoder * Refactoring TransactionDecoder * Invert methods order * Use Transaction encoder instead of writeTo * Move enter and leave list to inner method as pr suggestion * Size calculation should use opaque bytes instead of rlp --------- Signed-off-by: Gabriel-Trintinalia Co-authored-by: Sally MacFarlane Signed-off-by: garyschulte --- .../engine/AbstractEngineNewPayload.java | 3 +- .../internal/results/BlockResultFactory.java | 13 +- .../EngineGetPayloadBodiesResultV1.java | 5 +- .../results/TransactionPendingResult.java | 5 +- .../api/util/DomainObjectDecodeUtils.java | 3 +- .../engine/EngineNewPayloadV3Test.java | 55 ++++ .../api/util/DomainObjectDecodeUtilsTest.java | 6 +- .../besu/ethereum/core/Transaction.java | 21 +- .../AccessListTransactionDecoder.java | 74 +++++ .../AccessListTransactionEncoder.java | 109 +++++++ .../BlobPooledTransactionDecoder.java | 50 ++++ .../BlobPooledTransactionEncoder.java | 47 ++++ .../core/encoding/BlobTransactionDecoder.java | 47 ++-- .../core/encoding/BlobTransactionEncoder.java | 35 +-- .../encoding/EIP1559TransactionDecoder.java | 74 +++++ .../encoding/EIP1559TransactionEncoder.java | 41 +++ .../core/encoding/EncodingContext.java | 41 +++ .../encoding/FrontierTransactionDecoder.java | 76 +++++ .../encoding/FrontierTransactionEncoder.java | 36 +++ .../core/encoding/TransactionDecoder.java | 265 ++++++++---------- .../core/encoding/TransactionEncoder.java | 206 +++++--------- .../besu/ethereum/mainnet/BodyValidation.java | 7 +- .../encoding/BlobTransactionEncodingTest.java | 41 +-- .../encoding/TransactionRLPDecoderTest.java | 27 +- .../encoding/TransactionRLPEncoderTest.java | 24 +- .../besu/ethereum/core/encoding/blob2.txt | 1 + .../besu/ethereum/eth/manager/EthServer.java | 5 +- .../messages/PooledTransactionsMessage.java | 14 +- 28 files changed, 920 insertions(+), 411 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionDecoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionEncoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionDecoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionEncoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionDecoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionEncoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EncodingContext.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionDecoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionEncoder.java create mode 100644 ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob2.txt diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index b7b42d696ca..7b5d6f852ad 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -50,6 +50,7 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Withdrawal; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; @@ -170,7 +171,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) transactions = blockParam.getTransactions().stream() .map(Bytes::fromHexString) - .map(TransactionDecoder::decodeOpaqueBytes) + .map(in -> TransactionDecoder.decodeOpaqueBytes(in, EncodingContext.BLOCK_BODY)) .collect(Collectors.toList()); } catch (final RLPException | IllegalArgumentException e) { return respondWithInvalid( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java index 2d52c31b093..9ec3acd7f76 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockValueCalculator; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import java.util.ArrayList; @@ -95,7 +96,9 @@ public BlockResult transactionComplete(final Block block) { public EngineGetPayloadResultV1 payloadTransactionCompleteV1(final Block block) { final List txs = block.getBody().getTransactions().stream() - .map(TransactionEncoder::encodeOpaqueBytes) + .map( + transaction -> + TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) .map(Bytes::toHexString) .collect(Collectors.toList()); @@ -106,7 +109,9 @@ public EngineGetPayloadResultV2 payloadTransactionCompleteV2( final BlockWithReceipts blockWithReceipts) { final List txs = blockWithReceipts.getBlock().getBody().getTransactions().stream() - .map(TransactionEncoder::encodeOpaqueBytes) + .map( + transaction -> + TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) .map(Bytes::toHexString) .collect(Collectors.toList()); @@ -132,7 +137,9 @@ public EngineGetPayloadResultV3 payloadTransactionCompleteV3( final BlockWithReceipts blockWithReceipts) { final List txs = blockWithReceipts.getBlock().getBody().getTransactions().stream() - .map(TransactionEncoder::encodeOpaqueBytes) + .map( + transaction -> + TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) .map(Bytes::toHexString) .collect(Collectors.toList()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java index 4358230ee09..f4e9a12e27d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import java.util.Collections; @@ -52,7 +53,9 @@ public static class PayloadBody { public PayloadBody(final BlockBody blockBody) { this.transactions = blockBody.getTransactions().stream() - .map(TransactionEncoder::encodeOpaqueBytes) + .map( + transaction -> + TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) .map(Bytes::toHexString) .collect(Collectors.toList()); this.withdrawals = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java index a8a4603d5c2..04ac00580ce 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import java.util.List; @@ -99,7 +100,9 @@ public TransactionPendingResult(final Transaction transaction) { this.input = transaction.getPayload().toString(); this.nonce = Quantity.create(transaction.getNonce()); this.publicKey = transaction.getPublicKey().orElse(null); - this.raw = TransactionEncoder.encodeOpaqueBytes(transaction).toString(); + this.raw = + TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.POOLED_TRANSACTION) + .toString(); this.to = transaction.getTo().map(Address::toHexString).orElse(null); this.type = transactionType.equals(TransactionType.FRONTIER) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java index 8c4c0d453e0..7ea2de0c016 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.rlp.RLPException; @@ -27,7 +28,7 @@ public static Transaction decodeRawTransaction(final String rawTransaction) throws InvalidJsonRpcRequestException { try { Bytes txnBytes = Bytes.fromHexString(rawTransaction); - return TransactionDecoder.decodeOpaqueBytes(txnBytes); + return TransactionDecoder.decodeOpaqueBytes(txnBytes, EncodingContext.POOLED_TRANSACTION); } catch (final IllegalArgumentException e) { throw new InvalidJsonRpcRequestException("Invalid raw transaction hex", e); } catch (final RLPException r) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java index 56cecbfb7db..d1984a5795e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java @@ -23,7 +23,13 @@ import static org.mockito.Mockito.verify; 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.Address; import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingOutputs; import org.hyperledger.besu.ethereum.BlockProcessingResult; @@ -35,18 +41,26 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePayloadStatusResult; +import org.hyperledger.besu.ethereum.core.BlobTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Deposit; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.core.Withdrawal; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; +import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; +import java.math.BigInteger; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.Supplier; +import com.google.common.base.Suppliers; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.BeforeEach; @@ -56,6 +70,9 @@ @ExtendWith(MockitoExtension.class) public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + protected static final KeyPair senderKeys = SIGNATURE_ALGORITHM.get().generateKeyPair(); public EngineNewPayloadV3Test() {} @@ -194,4 +211,42 @@ public void shouldValidateExcessBlobGasCorrectly() { assertThat(jsonRpcError.getData()).isEqualTo("Missing blob gas fields"); verify(engineCallListener, times(1)).executionEngineCalled(); } + + @Test + public void shouldRejectTransactionsWithFullBlobs() { + + Bytes transactionWithBlobsBytes = + TransactionEncoder.encodeOpaqueBytes( + createTransactionWithBlobs(), EncodingContext.POOLED_TRANSACTION); + + List transactions = List.of(transactionWithBlobsBytes.toString()); + + BlockHeader mockHeader = + setupValidPayload( + new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), + Optional.empty(), + Optional.empty()); + var resp = resp(mockEnginePayload(mockHeader, transactions)); + + EnginePayloadStatusResult res = fromSuccessResp(resp); + assertThat(res.getStatusAsString()).isEqualTo(INVALID.name()); + assertThat(res.getError()).isEqualTo("Failed to decode transactions from block parameter"); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + private Transaction createTransactionWithBlobs() { + BlobTestFixture blobTestFixture = new BlobTestFixture(); + BlobsWithCommitments bwc = blobTestFixture.createBlobsWithCommitments(1); + + return new TransactionTestFixture() + .to(Optional.of(Address.fromHexString("0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"))) + .type(TransactionType.BLOB) + .chainId(Optional.of(BigInteger.ONE)) + .maxFeePerGas(Optional.of(Wei.of(15))) + .maxFeePerBlobGas(Optional.of(Wei.of(128))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1))) + .blobsWithCommitments(Optional.of(bwc)) + .versionedHashes(Optional.of(bwc.getVersionedHashes())) + .createTransaction(senderKeys); + } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java index 64587a1516d..763182da5c5 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; @@ -59,7 +60,7 @@ public class DomainObjectDecodeUtilsTest { @Test public void testAccessListRLPSerDes() { final BytesValueRLPOutput encoded = new BytesValueRLPOutput(); - TransactionEncoder.encodeForWire(accessListTxn, encoded); + TransactionEncoder.encodeRLP(accessListTxn, encoded, EncodingContext.POOLED_TRANSACTION); Transaction decoded = DomainObjectDecodeUtils.decodeRawTransaction(encoded.encoded().toHexString()); Assertions.assertThat(decoded.getAccessList().isPresent()).isTrue(); @@ -68,7 +69,8 @@ public void testAccessListRLPSerDes() { @Test public void testAccessList2718OpaqueSerDes() { - final Bytes encoded = TransactionEncoder.encodeOpaqueBytes(accessListTxn); + final Bytes encoded = + TransactionEncoder.encodeOpaqueBytes(accessListTxn, EncodingContext.POOLED_TRANSACTION); Transaction decoded = DomainObjectDecodeUtils.decodeRawTransaction(encoded.toString()); Assertions.assertThat(decoded.getAccessList().isPresent()).isTrue(); Assertions.assertThat(decoded.getAccessList().map(List::size).get()).isEqualTo(1); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 827c9241b5e..a7cad4b8d85 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -35,7 +35,9 @@ 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.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; @@ -126,7 +128,7 @@ public static Transaction readFrom(final Bytes rlpBytes) { } public static Transaction readFrom(final RLPInput rlpInput) { - return TransactionDecoder.decodeForWire(rlpInput); + return TransactionDecoder.decodeRLP(rlpInput, EncodingContext.BLOCK_BODY); } /** @@ -613,7 +615,7 @@ private Bytes32 getOrComputeSenderRecoveryHash() { * @param out the output to write the transaction to */ public void writeTo(final RLPOutput out) { - TransactionEncoder.encodeForWire(this, out); + TransactionEncoder.encodeRLP(this, out, EncodingContext.BLOCK_BODY); } @Override @@ -676,18 +678,17 @@ public int getSize() { } private void memoizeHashAndSize() { - final Bytes bytes = TransactionEncoder.encodeOpaqueBytes(this); + final Bytes bytes = TransactionEncoder.encodeOpaqueBytes(this, EncodingContext.BLOCK_BODY); hash = Hash.hash(bytes); - if (transactionType.supportsBlob()) { if (getBlobsWithCommitments().isPresent()) { - size = bytes.size(); + final Bytes pooledBytes = + TransactionEncoder.encodeOpaqueBytes(this, EncodingContext.POOLED_TRANSACTION); + size = pooledBytes.size(); return; } } - final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); - TransactionEncoder.encodeForWire(transactionType, bytes, rlpOutput); - size = rlpOutput.encodedSize(); + size = bytes.size(); } /** @@ -968,7 +969,7 @@ private static void eip1559PreimageFields( rlpOutput.writeBytes(to.map(Bytes::copy).orElse(Bytes.EMPTY)); rlpOutput.writeUInt256Scalar(value); rlpOutput.writeBytes(payload); - TransactionEncoder.writeAccessList(rlpOutput, accessList); + AccessListTransactionEncoder.writeAccessList(rlpOutput, accessList); } private static Bytes blobPreimage( @@ -1019,7 +1020,7 @@ private static Bytes accessListPreimage( RLP.encode( rlpOutput -> { rlpOutput.startList(); - TransactionEncoder.encodeAccessListInner( + AccessListTransactionEncoder.encodeAccessListInner( chainId, nonce, gasPrice, gasLimit, to, value, payload, accessList, rlpOutput); rlpOutput.endList(); }); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionDecoder.java new file mode 100644 index 00000000000..477ad57fe60 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionDecoder.java @@ -0,0 +1,74 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +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.TransactionType; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPInput; + +import java.math.BigInteger; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; + +class AccessListTransactionDecoder { + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + + public static Transaction decode(final RLPInput rlpInput) { + rlpInput.enterList(); + final Transaction.Builder preSignatureTransactionBuilder = + Transaction.builder() + .type(TransactionType.ACCESS_LIST) + .chainId(BigInteger.valueOf(rlpInput.readLongScalar())) + .nonce(rlpInput.readLongScalar()) + .gasPrice(Wei.of(rlpInput.readUInt256Scalar())) + .gasLimit(rlpInput.readLongScalar()) + .to( + rlpInput.readBytes( + addressBytes -> addressBytes.size() == 0 ? null : Address.wrap(addressBytes))) + .value(Wei.of(rlpInput.readUInt256Scalar())) + .payload(rlpInput.readBytes()) + .accessList( + rlpInput.readList( + accessListEntryRLPInput -> { + accessListEntryRLPInput.enterList(); + final AccessListEntry accessListEntry = + new AccessListEntry( + Address.wrap(accessListEntryRLPInput.readBytes()), + accessListEntryRLPInput.readList(RLPInput::readBytes32)); + accessListEntryRLPInput.leaveList(); + return accessListEntry; + })); + final byte recId = (byte) rlpInput.readIntScalar(); + final Transaction transaction = + preSignatureTransactionBuilder + .signature( + SIGNATURE_ALGORITHM + .get() + .createSignature( + rlpInput.readUInt256Scalar().toUnsignedBigInteger(), + rlpInput.readUInt256Scalar().toUnsignedBigInteger(), + recId)) + .build(); + rlpInput.leaveList(); + return transaction; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionEncoder.java new file mode 100644 index 00000000000..b539ee931cc --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionEncoder.java @@ -0,0 +1,109 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +import static org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignature; + +import org.hyperledger.besu.datatypes.AccessListEntry; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +import java.math.BigInteger; +import java.util.List; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; + +public class AccessListTransactionEncoder { + + public static void encode(final Transaction transaction, final RLPOutput rlpOutput) { + rlpOutput.startList(); + encodeAccessListInner( + transaction.getChainId(), + transaction.getNonce(), + transaction.getGasPrice().orElseThrow(), + transaction.getGasLimit(), + transaction.getTo(), + transaction.getValue(), + transaction.getPayload(), + transaction + .getAccessList() + .orElseThrow( + () -> + new IllegalStateException( + "Developer error: access list should be guaranteed to be present")), + rlpOutput); + rlpOutput.writeIntScalar(transaction.getSignature().getRecId()); + writeSignature(transaction, rlpOutput); + rlpOutput.endList(); + } + + public static void encodeAccessListInner( + final Optional chainId, + final long nonce, + final Wei gasPrice, + final long gasLimit, + final Optional

to, + final Wei value, + final Bytes payload, + final List accessList, + final RLPOutput rlpOutput) { + rlpOutput.writeBigIntegerScalar(chainId.orElseThrow()); + rlpOutput.writeLongScalar(nonce); + rlpOutput.writeUInt256Scalar(gasPrice); + rlpOutput.writeLongScalar(gasLimit); + rlpOutput.writeBytes(to.map(Bytes::copy).orElse(Bytes.EMPTY)); + rlpOutput.writeUInt256Scalar(value); + rlpOutput.writeBytes(payload); + /* + Access List encoding should look like this + where hex strings represent raw bytes + [ + [ + "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", + [ + "0x0000000000000000000000000000000000000000000000000000000000000003", + "0x0000000000000000000000000000000000000000000000000000000000000007" + ] + ], + [ + "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + [] + ] + ] */ + writeAccessList(rlpOutput, Optional.of(accessList)); + } + + public static void writeAccessList( + final RLPOutput out, final Optional> accessListEntries) { + if (accessListEntries.isEmpty()) { + out.writeEmptyList(); + } else { + out.writeList( + accessListEntries.get(), + (accessListEntry, accessListEntryRLPOutput) -> { + accessListEntryRLPOutput.startList(); + out.writeBytes(accessListEntry.address()); + out.writeList( + accessListEntry.storageKeys(), + (storageKeyBytes, storageKeyBytesRLPOutput) -> + storageKeyBytesRLPOutput.writeBytes(storageKeyBytes)); + accessListEntryRLPOutput.endList(); + }); + } + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionDecoder.java new file mode 100644 index 00000000000..8f2efde53f8 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionDecoder.java @@ -0,0 +1,50 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPInput; + +import java.util.List; + +/** + * Class responsible for decoding blob transactions from the transaction pool. Blob transactions + * have two network representations. During transaction gossip responses (PooledTransactions), the + * EIP-2718 TransactionPayload of the blob transaction is wrapped to become: rlp([tx_payload_body, + * blobs, commitments, proofs]). + */ +public class BlobPooledTransactionDecoder { + + /** + * Decodes a blob transaction from the provided RLP input. + * + * @param input the RLP input to decode + * @return the decoded transaction + */ + public static Transaction decode(final RLPInput input) { + input.enterList(); + final Transaction.Builder builder = Transaction.builder(); + BlobTransactionDecoder.readTransactionPayloadInner(builder, input); + List blobs = input.readList(Blob::readFrom); + List commitments = input.readList(KZGCommitment::readFrom); + List proofs = input.readList(KZGProof::readFrom); + input.leaveList(); + builder.kzgBlobs(commitments, blobs, proofs); + return builder.build(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionEncoder.java new file mode 100644 index 00000000000..b47a406102d --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionEncoder.java @@ -0,0 +1,47 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +import static org.slf4j.LoggerFactory.getLogger; + +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +import java.security.InvalidParameterException; + +import org.slf4j.Logger; + +public class BlobPooledTransactionEncoder { + private static final Logger LOG = getLogger(BlobPooledTransactionEncoder.class); + static final String NO_BLOBS_ERROR = + "Transaction with no blobsWithCommitments cannot be encoded for Pooled Transaction"; + + public static void encode(final Transaction transaction, final RLPOutput out) { + LOG.trace("Encoding transaction with blobs {}", transaction); + var blobsWithCommitments = transaction.getBlobsWithCommitments(); + if (blobsWithCommitments.isEmpty() || blobsWithCommitments.get().getBlobs().isEmpty()) { + throw new InvalidParameterException(NO_BLOBS_ERROR); + } + out.startList(); + BlobTransactionEncoder.encode(transaction, out); + out.writeList(blobsWithCommitments.get().getBlobs(), Blob::writeTo); + out.writeList(blobsWithCommitments.get().getKzgCommitments(), KZGCommitment::writeTo); + out.writeList(blobsWithCommitments.get().getKzgProofs(), KZGProof::writeTo); + out.endList(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java index 9a3f9649516..4e556ad1f98 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java @@ -18,16 +18,12 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.AccessListEntry; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Blob; -import org.hyperledger.besu.datatypes.KZGCommitment; -import org.hyperledger.besu.datatypes.KZGProof; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.RLPInput; -import java.util.List; import java.util.function.Supplier; import com.google.common.base.Suppliers; @@ -36,17 +32,15 @@ public class BlobTransactionDecoder { private static final Supplier SIGNATURE_ALGORITHM = Suppliers.memoize(SignatureAlgorithmFactory::getInstance); - static Transaction decode(final RLPInput input) { + /** + * Decodes a blob transaction from the provided RLP input. + * + * @param input the RLP input to decode + * @return the decoded transaction + */ + public static Transaction decode(final RLPInput input) { Transaction transaction; - - input.enterList(); - // BlobTransactionNetworkWrapper - if (input.nextIsList()) { - transaction = readNetworkWrapperInner(input); - } else { - transaction = readTransactionPayload(input); - } - input.leaveList(); + transaction = readTransactionPayload(input); return transaction; } @@ -56,8 +50,17 @@ private static Transaction readTransactionPayload(final RLPInput input) { return builder.build(); } - private static void readTransactionPayloadInner( - final Transaction.Builder builder, final RLPInput input) { + /** + * Reads the payload of a blob transaction from the provided RLP input. + * + *

[chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, + * access_list, max_fee_per_blob_gas, blob_versioned_hashes, y_parity, r, s] + * + * @param builder the transaction builder + * @param input the RLP input to read from + */ + static void readTransactionPayloadInner(final Transaction.Builder builder, final RLPInput input) { + input.enterList(); builder .type(TransactionType.BLOB) .chainId(input.readBigIntegerScalar()) @@ -91,18 +94,6 @@ private static void readTransactionPayloadInner( input.readUInt256Scalar().toUnsignedBigInteger(), input.readUInt256Scalar().toUnsignedBigInteger(), recId)); - } - - private static Transaction readNetworkWrapperInner(final RLPInput input) { - final Transaction.Builder builder = Transaction.builder(); - input.enterList(); - readTransactionPayloadInner(builder, input); input.leaveList(); - - List blobs = input.readList(Blob::readFrom); - List commitments = input.readList(KZGCommitment::readFrom); - List proofs = input.readList(KZGProof::readFrom); - builder.kzgBlobs(commitments, blobs, proofs); - return builder.build(); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncoder.java index 6df9baed920..73b7593d9b8 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncoder.java @@ -14,25 +14,17 @@ */ package org.hyperledger.besu.ethereum.core.encoding; -import static org.slf4j.LoggerFactory.getLogger; - -import org.hyperledger.besu.datatypes.Blob; -import org.hyperledger.besu.datatypes.KZGCommitment; -import org.hyperledger.besu.datatypes.KZGProof; import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPOutput; import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.slf4j.Logger; public class BlobTransactionEncoder { - private static final Logger LOG = getLogger(BlobTransactionEncoder.class); - public static void encodeEIP4844(final Transaction transaction, final RLPOutput out) { + public static void encode(final Transaction transaction, final RLPOutput out) { out.startList(); out.writeBigIntegerScalar(transaction.getChainId().orElseThrow()); out.writeLongScalar(transaction.getNonce()); @@ -42,7 +34,7 @@ public static void encodeEIP4844(final Transaction transaction, final RLPOutput out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); out.writeUInt256Scalar(transaction.getValue()); out.writeBytes(transaction.getPayload()); - TransactionEncoder.writeAccessList(out, transaction.getAccessList()); + AccessListTransactionEncoder.writeAccessList(out, transaction.getAccessList()); out.writeUInt256Scalar(transaction.getMaxFeePerBlobGas().orElseThrow()); out.startList(); transaction @@ -57,29 +49,6 @@ public static void encodeEIP4844(final Transaction transaction, final RLPOutput out.endList(); } - private static void encodeEIP4844Network(final Transaction transaction, final RLPOutput out) { - LOG.trace("Encoding transaction with blobs {}", transaction); - out.startList(); - var blobsWithCommitments = transaction.getBlobsWithCommitments().orElseThrow(); - encodeEIP4844(transaction, out); - - out.writeList(blobsWithCommitments.getBlobs(), Blob::writeTo); - out.writeList(blobsWithCommitments.getKzgCommitments(), KZGCommitment::writeTo); - out.writeList(blobsWithCommitments.getKzgProofs(), KZGProof::writeTo); - out.endList(); - } - - public static void encodeForWireNetwork( - final Transaction transaction, final RLPOutput rlpOutput) { - rlpOutput.writeBytes(encodeOpaqueBytesNetwork(transaction)); - } - - private static Bytes encodeOpaqueBytesNetwork(final Transaction transaction) { - return Bytes.concatenate( - Bytes.of(transaction.getType().getSerializedType()), - RLP.encode(rlpOutput -> encodeEIP4844Network(transaction, rlpOutput))); - } - public static void writeBlobVersionedHashes( final RLPOutput rlpOutput, final List versionedHashes) { rlpOutput.writeList(versionedHashes, (h, out) -> out.writeBytes(h.toBytes())); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionDecoder.java new file mode 100644 index 00000000000..35a549409e7 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionDecoder.java @@ -0,0 +1,74 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +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.TransactionType; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPInput; + +import java.math.BigInteger; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; + +public class EIP1559TransactionDecoder { + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + + public static Transaction decode(final RLPInput input) { + input.enterList(); + final BigInteger chainId = input.readBigIntegerScalar(); + final Transaction.Builder builder = + Transaction.builder() + .type(TransactionType.EIP1559) + .chainId(chainId) + .nonce(input.readLongScalar()) + .maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar())) + .maxFeePerGas(Wei.of(input.readUInt256Scalar())) + .gasLimit(input.readLongScalar()) + .to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v))) + .value(Wei.of(input.readUInt256Scalar())) + .payload(input.readBytes()) + .accessList( + input.readList( + accessListEntryRLPInput -> { + accessListEntryRLPInput.enterList(); + final AccessListEntry accessListEntry = + new AccessListEntry( + Address.wrap(accessListEntryRLPInput.readBytes()), + accessListEntryRLPInput.readList(RLPInput::readBytes32)); + accessListEntryRLPInput.leaveList(); + return accessListEntry; + })); + final byte recId = (byte) input.readIntScalar(); + final Transaction transaction = + builder + .signature( + SIGNATURE_ALGORITHM + .get() + .createSignature( + input.readUInt256Scalar().toUnsignedBigInteger(), + input.readUInt256Scalar().toUnsignedBigInteger(), + recId)) + .build(); + input.leaveList(); + return transaction; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionEncoder.java new file mode 100644 index 00000000000..3d061beff84 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionEncoder.java @@ -0,0 +1,41 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.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.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +import org.apache.tuweni.bytes.Bytes; + +public class EIP1559TransactionEncoder { + + public static void encode(final Transaction transaction, final RLPOutput out) { + out.startList(); + out.writeBigIntegerScalar(transaction.getChainId().orElseThrow()); + out.writeLongScalar(transaction.getNonce()); + out.writeUInt256Scalar(transaction.getMaxPriorityFeePerGas().orElseThrow()); + out.writeUInt256Scalar(transaction.getMaxFeePerGas().orElseThrow()); + out.writeLongScalar(transaction.getGasLimit()); + out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); + out.writeUInt256Scalar(transaction.getValue()); + out.writeBytes(transaction.getPayload()); + writeAccessList(out, transaction.getAccessList()); + writeSignatureAndRecoveryId(transaction, out); + out.endList(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EncodingContext.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EncodingContext.java new file mode 100644 index 00000000000..b94289aeb9f --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EncodingContext.java @@ -0,0 +1,41 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +/** + * Enum representing the context in which a transaction is being encoded. This context is used to + * determine the appropriate encoding strategy for a transaction. + * + *

The context can be one of the following: + * + *

    + *
  • {@link #BLOCK_BODY}: The transaction is part of a block body. This context is used when + * encoding transactions for inclusion in a block. + *
  • {@link #POOLED_TRANSACTION}: The transaction is part of a transaction pool. This context is + * used when encoding transactions that are currently in the transaction pool, waiting to be + * included in a block. It is also used when encoding transactions for RPC calls related to + * the transaction pool. + *
+ */ +public enum EncodingContext { + /** Represents the context where the transaction is part of a block body. */ + BLOCK_BODY, + + /** + * Represents the context where the transaction is part of a transaction pool. This context is + * also used when encoding transactions for RPC calls related to the transaction pool. + */ + POOLED_TRANSACTION, +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionDecoder.java new file mode 100644 index 00000000000..8cfd8b93b51 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionDecoder.java @@ -0,0 +1,76 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_BASE; +import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_MIN; +import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_UNPROTECTED_V_BASE; +import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_UNPROTECTED_V_BASE_PLUS_1; +import static org.hyperledger.besu.ethereum.core.Transaction.TWO; + +import org.hyperledger.besu.crypto.SECPSignature; +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.Wei; +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 FrontierTransactionDecoder { + // Supplier for the signature algorithm + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + + public static Transaction decode(final RLPInput input) { + input.enterList(); + final Transaction.Builder builder = + Transaction.builder() + .type(TransactionType.FRONTIER) + .nonce(input.readLongScalar()) + .gasPrice(Wei.of(input.readUInt256Scalar())) + .gasLimit(input.readLongScalar()) + .to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v))) + .value(Wei.of(input.readUInt256Scalar())) + .payload(input.readBytes()); + + final BigInteger v = input.readBigIntegerScalar(); + final byte recId; + Optional chainId = Optional.empty(); + if (v.equals(REPLAY_UNPROTECTED_V_BASE) || v.equals(REPLAY_UNPROTECTED_V_BASE_PLUS_1)) { + recId = v.subtract(REPLAY_UNPROTECTED_V_BASE).byteValueExact(); + } else if (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0) { + chainId = Optional.of(v.subtract(REPLAY_PROTECTED_V_BASE).divide(TWO)); + recId = v.subtract(TWO.multiply(chainId.get()).add(REPLAY_PROTECTED_V_BASE)).byteValueExact(); + } else { + throw new RuntimeException( + String.format("An unsupported encoded `v` value of %s was found", v)); + } + final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger(); + final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger(); + final SECPSignature signature = SIGNATURE_ALGORITHM.get().createSignature(r, s, recId); + + input.leaveList(); + + chainId.ifPresent(builder::chainId); + return builder.signature(signature).build(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionEncoder.java new file mode 100644 index 00000000000..0c5f61f5454 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionEncoder.java @@ -0,0 +1,36 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +import static org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignatureAndV; + +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +import org.apache.tuweni.bytes.Bytes; + +public class FrontierTransactionEncoder { + public static void encode(final Transaction transaction, final RLPOutput out) { + out.startList(); + out.writeLongScalar(transaction.getNonce()); + out.writeUInt256Scalar(transaction.getGasPrice().orElseThrow()); + out.writeLongScalar(transaction.getGasLimit()); + out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); + out.writeUInt256Scalar(transaction.getValue()); + out.writeBytes(transaction.getPayload()); + writeSignatureAndV(transaction, out); + out.endList(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java index 88ccf58b803..fe6687cdb5c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java @@ -15,28 +15,14 @@ package org.hyperledger.besu.ethereum.core.encoding; import static com.google.common.base.Preconditions.checkNotNull; -import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_BASE; -import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_MIN; -import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_UNPROTECTED_V_BASE; -import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_UNPROTECTED_V_BASE_PLUS_1; -import static org.hyperledger.besu.ethereum.core.Transaction.TWO; - -import org.hyperledger.besu.crypto.SECPSignature; -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.TransactionType; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.RLP; 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; import com.google.common.collect.ImmutableMap; import org.apache.tuweni.bytes.Bytes; @@ -50,154 +36,143 @@ interface Decoder { private static final ImmutableMap TYPED_TRANSACTION_DECODERS = ImmutableMap.of( TransactionType.ACCESS_LIST, - TransactionDecoder::decodeAccessList, + AccessListTransactionDecoder::decode, TransactionType.EIP1559, - TransactionDecoder::decodeEIP1559, + EIP1559TransactionDecoder::decode, TransactionType.BLOB, BlobTransactionDecoder::decode); - private static final Supplier SIGNATURE_ALGORITHM = - Suppliers.memoize(SignatureAlgorithmFactory::getInstance); - - public static Transaction decodeForWire(final RLPInput rlpInput) { - if (rlpInput.nextIsList()) { - return decodeFrontier(rlpInput); + private static final ImmutableMap POOLED_TRANSACTION_DECODERS = + ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionDecoder::decode); + + /** + * Decodes an RLP input into a transaction. If the input represents a typed transaction, it uses + * the appropriate decoder for that type. Otherwise, it uses the frontier decoder. + * + * @param rlpInput the RLP input + * @return the decoded transaction + */ + public static Transaction decodeRLP( + final RLPInput rlpInput, final EncodingContext encodingContext) { + if (isTypedTransaction(rlpInput)) { + return decodeTypedTransaction(rlpInput, encodingContext); } else { - final Bytes typedTransactionBytes = rlpInput.readBytes(); - final TransactionType transactionType = - TransactionType.of(typedTransactionBytes.get(0) & 0xff); - return getDecoder(transactionType).decode(RLP.input(typedTransactionBytes.slice(1))); + return FrontierTransactionDecoder.decode(rlpInput); } } - public static Transaction decodeOpaqueBytes(final Bytes input) { - final TransactionType transactionType; - try { - transactionType = TransactionType.of(input.get(0)); - } catch (final IllegalArgumentException __) { - return decodeForWire(RLP.input(input)); - } - return getDecoder(transactionType).decode(RLP.input(input.slice(1))); + /** + * Decodes a typed transaction from an RLP input. It first reads the transaction type from the + * input, then uses the appropriate decoder for that type. + * + * @param rlpInput the RLP input + * @return the decoded transaction + */ + private static Transaction decodeTypedTransaction( + final RLPInput rlpInput, final EncodingContext context) { + // Read the typed transaction bytes from the RLP input + final Bytes typedTransactionBytes = rlpInput.readBytes(); + + // Determine the transaction type from the typed transaction bytes + TransactionType transactionType = + getTransactionType(typedTransactionBytes) + .orElseThrow((() -> new IllegalArgumentException("Unsupported transaction type"))); + return decodeTypedTransaction(typedTransactionBytes, transactionType, context); } - private static Decoder getDecoder(final TransactionType transactionType) { - return checkNotNull( - TYPED_TRANSACTION_DECODERS.get(transactionType), - "Developer Error. A supported transaction type %s has no associated decoding logic", - transactionType); + /** + * Decodes a typed transaction. The method first slices the transaction bytes to exclude the + * transaction type, then uses the appropriate decoder for the transaction type to decode the + * remaining bytes. + * + * @param transactionBytes the transaction bytes + * @param transactionType the type of the transaction + * @param context the encoding context + * @return the decoded transaction + */ + private static Transaction decodeTypedTransaction( + final Bytes transactionBytes, + final TransactionType transactionType, + final EncodingContext context) { + // Slice the transaction bytes to exclude the transaction type and prepare for decoding + final RLPInput transactionInput = RLP.input(transactionBytes.slice(1)); + // Use the appropriate decoder for the transaction type to decode the remaining bytes + return getDecoder(transactionType, context).decode(transactionInput); } - static Transaction decodeFrontier(final RLPInput input) { - input.enterList(); - final Transaction.Builder builder = - Transaction.builder() - .type(TransactionType.FRONTIER) - .nonce(input.readLongScalar()) - .gasPrice(Wei.of(input.readUInt256Scalar())) - .gasLimit(input.readLongScalar()) - .to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v))) - .value(Wei.of(input.readUInt256Scalar())) - .payload(input.readBytes()); - - final BigInteger v = input.readBigIntegerScalar(); - final byte recId; - Optional chainId = Optional.empty(); - if (v.equals(REPLAY_UNPROTECTED_V_BASE) || v.equals(REPLAY_UNPROTECTED_V_BASE_PLUS_1)) { - recId = v.subtract(REPLAY_UNPROTECTED_V_BASE).byteValueExact(); - } else if (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0) { - chainId = Optional.of(v.subtract(REPLAY_PROTECTED_V_BASE).divide(TWO)); - recId = v.subtract(TWO.multiply(chainId.get()).add(REPLAY_PROTECTED_V_BASE)).byteValueExact(); + /** + * Decodes a transaction from opaque bytes. The method first determines the transaction type from + * the bytes. If the type is present, it delegates the decoding process to the appropriate decoder + * for that type. If the type is not present, it decodes the bytes as an RLP input. + * + * @param opaqueBytes the opaque bytes + * @param context the encoding context + * @return the decoded transaction + */ + public static Transaction decodeOpaqueBytes( + final Bytes opaqueBytes, final EncodingContext context) { + var transactionType = getTransactionType(opaqueBytes); + if (transactionType.isPresent()) { + return decodeTypedTransaction(opaqueBytes, transactionType.get(), context); } else { - throw new RuntimeException( - String.format("An unsupported encoded `v` value of %s was found", v)); + // If the transaction type is not present, decode the opaque bytes as RLP + return decodeRLP(RLP.input(opaqueBytes), context); } - final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger(); - final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger(); - final SECPSignature signature = SIGNATURE_ALGORITHM.get().createSignature(r, s, recId); - - input.leaveList(); + } - chainId.ifPresent(builder::chainId); - return builder.signature(signature).build(); + /** + * Retrieves the transaction type from the provided bytes. The method attempts to extract the + * first byte from the input bytes and interpret it as a transaction type. If the byte does not + * correspond to a valid transaction type, the method returns an empty Optional. + * + * @param opaqueBytes the bytes from which to extract the transaction type + * @return an Optional containing the TransactionType if the first byte of the input corresponds + * to a valid transaction type, or an empty Optional if it does not + */ + private static Optional getTransactionType(final Bytes opaqueBytes) { + try { + byte transactionTypeByte = opaqueBytes.get(0); + return Optional.of(TransactionType.of(transactionTypeByte)); + } catch (IllegalArgumentException ex) { + return Optional.empty(); + } } - private static Transaction decodeAccessList(final RLPInput rlpInput) { - rlpInput.enterList(); - final Transaction.Builder preSignatureTransactionBuilder = - Transaction.builder() - .type(TransactionType.ACCESS_LIST) - .chainId(BigInteger.valueOf(rlpInput.readLongScalar())) - .nonce(rlpInput.readLongScalar()) - .gasPrice(Wei.of(rlpInput.readUInt256Scalar())) - .gasLimit(rlpInput.readLongScalar()) - .to( - rlpInput.readBytes( - addressBytes -> addressBytes.size() == 0 ? null : Address.wrap(addressBytes))) - .value(Wei.of(rlpInput.readUInt256Scalar())) - .payload(rlpInput.readBytes()) - .accessList( - rlpInput.readList( - accessListEntryRLPInput -> { - accessListEntryRLPInput.enterList(); - final AccessListEntry accessListEntry = - new AccessListEntry( - Address.wrap(accessListEntryRLPInput.readBytes()), - accessListEntryRLPInput.readList(RLPInput::readBytes32)); - accessListEntryRLPInput.leaveList(); - return accessListEntry; - })); - final byte recId = (byte) rlpInput.readIntScalar(); - final Transaction transaction = - preSignatureTransactionBuilder - .signature( - SIGNATURE_ALGORITHM - .get() - .createSignature( - rlpInput.readUInt256Scalar().toUnsignedBigInteger(), - rlpInput.readUInt256Scalar().toUnsignedBigInteger(), - recId)) - .build(); - rlpInput.leaveList(); - return transaction; + /** + * Checks if the given RLP input is a typed transaction. + * + *

See EIP-2718 + * + *

If it starts with a value in the range [0, 0x7f] then it is a new transaction type + * + *

if it starts with a value in the range [0xc0, 0xfe] then it is a legacy transaction type + * + * @param rlpInput the RLP input + * @return true if the RLP input is a typed transaction, false otherwise + */ + private static boolean isTypedTransaction(final RLPInput rlpInput) { + return !rlpInput.nextIsList(); } - static Transaction decodeEIP1559(final RLPInput input) { - input.enterList(); - final BigInteger chainId = input.readBigIntegerScalar(); - final Transaction.Builder builder = - Transaction.builder() - .type(TransactionType.EIP1559) - .chainId(chainId) - .nonce(input.readLongScalar()) - .maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar())) - .maxFeePerGas(Wei.of(input.readUInt256Scalar())) - .gasLimit(input.readLongScalar()) - .to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v))) - .value(Wei.of(input.readUInt256Scalar())) - .payload(input.readBytes()) - .accessList( - input.readList( - accessListEntryRLPInput -> { - accessListEntryRLPInput.enterList(); - final AccessListEntry accessListEntry = - new AccessListEntry( - Address.wrap(accessListEntryRLPInput.readBytes()), - accessListEntryRLPInput.readList(RLPInput::readBytes32)); - accessListEntryRLPInput.leaveList(); - return accessListEntry; - })); - final byte recId = (byte) input.readIntScalar(); - final Transaction transaction = - builder - .signature( - SIGNATURE_ALGORITHM - .get() - .createSignature( - input.readUInt256Scalar().toUnsignedBigInteger(), - input.readUInt256Scalar().toUnsignedBigInteger(), - recId)) - .build(); - input.leaveList(); - return transaction; + /** + * Gets the decoder for a given transaction type and encoding context. If the context is + * POOLED_TRANSACTION, it uses the network decoder for the type. Otherwise, it uses the typed + * decoder. + * + * @param transactionType the transaction type + * @param encodingContext the encoding context + * @return the decoder + */ + private static Decoder getDecoder( + final TransactionType transactionType, final EncodingContext encodingContext) { + if (encodingContext.equals(EncodingContext.POOLED_TRANSACTION)) { + if (POOLED_TRANSACTION_DECODERS.containsKey(transactionType)) { + return POOLED_TRANSACTION_DECODERS.get(transactionType); + } + } + return checkNotNull( + TYPED_TRANSACTION_DECODERS.get(transactionType), + "Developer Error. A supported transaction type %s has no associated decoding logic", + transactionType); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java index 56d76dbae72..20fe75885e4 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java @@ -16,20 +16,13 @@ import static com.google.common.base.Preconditions.checkNotNull; -import org.hyperledger.besu.datatypes.AccessListEntry; -import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.TransactionType; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPOutput; -import java.math.BigInteger; -import java.util.List; -import java.util.Map; -import java.util.Optional; - +import com.google.common.collect.ImmutableMap; import org.apache.tuweni.bytes.Bytes; public class TransactionEncoder { @@ -39,23 +32,42 @@ interface Encoder { void encode(Transaction transaction, RLPOutput output); } - private static final Map TYPED_TRANSACTION_ENCODERS = - Map.of( + private static final ImmutableMap TYPED_TRANSACTION_ENCODERS = + ImmutableMap.of( TransactionType.ACCESS_LIST, - TransactionEncoder::encodeAccessList, + AccessListTransactionEncoder::encode, TransactionType.EIP1559, - TransactionEncoder::encodeEIP1559, + EIP1559TransactionEncoder::encode, TransactionType.BLOB, - BlobTransactionEncoder::encodeEIP4844); - - public static void encodeForWire(final Transaction transaction, final RLPOutput rlpOutput) { - final TransactionType transactionType = - checkNotNull( - transaction.getType(), "Transaction type for %s was not specified.", transaction); - encodeForWire(transactionType, encodeOpaqueBytes(transaction), rlpOutput); + BlobTransactionEncoder::encode); + + private static final ImmutableMap POOLED_TRANSACTION_ENCODERS = + ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode); + + /** + * Encodes a transaction into RLP format. + * + * @param transaction the transaction to encode + * @param rlpOutput the RLP output stream + * @param encodingContext the encoding context + */ + public static void encodeRLP( + final Transaction transaction, + final RLPOutput rlpOutput, + final EncodingContext encodingContext) { + final TransactionType transactionType = getTransactionType(transaction); + Bytes opaqueBytes = encodeOpaqueBytes(transaction, encodingContext); + encodeRLP(transactionType, opaqueBytes, rlpOutput); } - public static void encodeForWire( + /** + * Encodes a transaction into RLP format. + * + * @param transactionType the type of the transaction + * @param opaqueBytes the bytes of the transaction + * @param rlpOutput the RLP output stream + */ + public static void encodeRLP( final TransactionType transactionType, final Bytes opaqueBytes, final RLPOutput rlpOutput) { checkNotNull(transactionType, "Transaction type was not specified."); if (TransactionType.FRONTIER.equals(transactionType)) { @@ -65,142 +77,58 @@ public static void encodeForWire( } } - public static Bytes encodeOpaqueBytes(final Transaction transaction) { - final TransactionType transactionType = - checkNotNull( - transaction.getType(), "Transaction type for %s was not specified.", transaction); + /** + * Encodes a transaction into opaque bytes. + * + * @param transaction the transaction to encode + * @param encodingContext the encoding context + * @return the encoded transaction as bytes + */ + public static Bytes encodeOpaqueBytes( + final Transaction transaction, final EncodingContext encodingContext) { + final TransactionType transactionType = getTransactionType(transaction); if (TransactionType.FRONTIER.equals(transactionType)) { - return RLP.encode(rlpOutput -> encodeFrontier(transaction, rlpOutput)); + return RLP.encode(rlpOutput -> FrontierTransactionEncoder.encode(transaction, rlpOutput)); } else { - final Encoder encoder = - checkNotNull( - TYPED_TRANSACTION_ENCODERS.get(transactionType), - "Developer Error. A supported transaction type %s has no associated encoding logic", - transactionType); + final Encoder encoder = getEncoder(transactionType, encodingContext); final BytesValueRLPOutput out = new BytesValueRLPOutput(); - out.writeByte(transactionType.getSerializedType()); + out.writeByte(transaction.getType().getSerializedType()); encoder.encode(transaction, out); return out.encoded(); } } - static void encodeFrontier(final Transaction transaction, final RLPOutput out) { - out.startList(); - out.writeLongScalar(transaction.getNonce()); - out.writeUInt256Scalar(transaction.getGasPrice().orElseThrow()); - out.writeLongScalar(transaction.getGasLimit()); - out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); - out.writeUInt256Scalar(transaction.getValue()); - out.writeBytes(transaction.getPayload()); - writeSignatureAndV(transaction, out); - out.endList(); - } - - static void encodeAccessList(final Transaction transaction, final RLPOutput rlpOutput) { - rlpOutput.startList(); - encodeAccessListInner( - transaction.getChainId(), - transaction.getNonce(), - transaction.getGasPrice().orElseThrow(), - transaction.getGasLimit(), - transaction.getTo(), - transaction.getValue(), - transaction.getPayload(), - transaction - .getAccessList() - .orElseThrow( - () -> - new IllegalStateException( - "Developer error: access list should be guaranteed to be present")), - rlpOutput); - rlpOutput.writeIntScalar(transaction.getSignature().getRecId()); - writeSignature(transaction, rlpOutput); - rlpOutput.endList(); - } - - public static void encodeAccessListInner( - final Optional chainId, - final long nonce, - final Wei gasPrice, - final long gasLimit, - final Optional

to, - final Wei value, - final Bytes payload, - final List accessList, - final RLPOutput rlpOutput) { - rlpOutput.writeBigIntegerScalar(chainId.orElseThrow()); - rlpOutput.writeLongScalar(nonce); - rlpOutput.writeUInt256Scalar(gasPrice); - rlpOutput.writeLongScalar(gasLimit); - rlpOutput.writeBytes(to.map(Bytes::copy).orElse(Bytes.EMPTY)); - rlpOutput.writeUInt256Scalar(value); - rlpOutput.writeBytes(payload); - /* - Access List encoding should look like this - where hex strings represent raw bytes - [ - [ - "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", - [ - "0x0000000000000000000000000000000000000000000000000000000000000003", - "0x0000000000000000000000000000000000000000000000000000000000000007" - ] - ], - [ - "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", - [] - ] - ] */ - writeAccessList(rlpOutput, Optional.of(accessList)); - } - - static void encodeEIP1559(final Transaction transaction, final RLPOutput out) { - out.startList(); - out.writeBigIntegerScalar(transaction.getChainId().orElseThrow()); - out.writeLongScalar(transaction.getNonce()); - out.writeUInt256Scalar(transaction.getMaxPriorityFeePerGas().orElseThrow()); - out.writeUInt256Scalar(transaction.getMaxFeePerGas().orElseThrow()); - out.writeLongScalar(transaction.getGasLimit()); - out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); - out.writeUInt256Scalar(transaction.getValue()); - out.writeBytes(transaction.getPayload()); - writeAccessList(out, transaction.getAccessList()); - writeSignatureAndRecoveryId(transaction, out); - out.endList(); - } - - public static void writeAccessList( - final RLPOutput out, final Optional> accessListEntries) { - if (accessListEntries.isEmpty()) { - out.writeEmptyList(); - } else { - out.writeList( - accessListEntries.get(), - (accessListEntry, accessListEntryRLPOutput) -> { - accessListEntryRLPOutput.startList(); - out.writeBytes(accessListEntry.address()); - out.writeList( - accessListEntry.storageKeys(), - (storageKeyBytes, storageKeyBytesRLPOutput) -> - storageKeyBytesRLPOutput.writeBytes(storageKeyBytes)); - accessListEntryRLPOutput.endList(); - }); - } - } - - private static void writeSignatureAndV(final Transaction transaction, final RLPOutput out) { + static void writeSignatureAndV(final Transaction transaction, final RLPOutput out) { out.writeBigIntegerScalar(transaction.getV()); writeSignature(transaction, out); } - public static void writeSignatureAndRecoveryId( - final Transaction transaction, final RLPOutput out) { + static void writeSignatureAndRecoveryId(final Transaction transaction, final RLPOutput out) { out.writeIntScalar(transaction.getSignature().getRecId()); writeSignature(transaction, out); } - private static void writeSignature(final Transaction transaction, final RLPOutput out) { + static void writeSignature(final Transaction transaction, final RLPOutput out) { out.writeBigIntegerScalar(transaction.getSignature().getR()); out.writeBigIntegerScalar(transaction.getSignature().getS()); } + + private static TransactionType getTransactionType(final Transaction transaction) { + return checkNotNull( + transaction.getType(), "Transaction type for %s was not specified.", transaction); + } + + private static Encoder getEncoder( + final TransactionType transactionType, final EncodingContext encodingContext) { + + if (encodingContext.equals(EncodingContext.POOLED_TRANSACTION)) { + if (POOLED_TRANSACTION_ENCODERS.containsKey(transactionType)) { + return POOLED_TRANSACTION_ENCODERS.get(transactionType); + } + } + return checkNotNull( + TYPED_TRANSACTION_ENCODERS.get(transactionType), + "Developer Error. A supported transaction type %s has no associated encoding logic", + transactionType); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java index 9fac97eaedf..f806c8d4cd1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.encoding.DepositEncoder; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.WithdrawalEncoder; import org.hyperledger.besu.ethereum.rlp.RLP; @@ -62,7 +63,11 @@ public static Hash transactionsRoot(final List transactions) { IntStream.range(0, transactions.size()) .forEach( - i -> trie.put(indexKey(i), TransactionEncoder.encodeOpaqueBytes(transactions.get(i)))); + i -> + trie.put( + indexKey(i), + TransactionEncoder.encodeOpaqueBytes( + transactions.get(i), EncodingContext.BLOCK_BODY))); return Hash.wrap(trie.getRootHash()); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java index 920582390b8..49461a75303 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; -import org.hyperledger.besu.ethereum.rlp.RLP; import java.io.BufferedReader; import java.io.IOException; @@ -33,7 +32,7 @@ import org.junit.jupiter.params.provider.MethodSource; public class BlobTransactionEncodingTest { - private static Stream provideTypedTransactionBytes() throws IOException { + private static Stream provideOpaqueBytesNoBlobsWithCommitments() { return Stream.of( createArgument( "0x03f89d850120b996ed3685012a1a646085012a1a64608303345094ffb38a7a99e3e2335be83fc74b7faa19d55312418308a80280c085012a1a6460e1a00153a6a1e053cf4c5a09e84088ed8ad7cb53d76c8168f1b82f7cfebfcd06da1a01a007785223eec68459d72265f10bdb30ec3415252a63100605a03142fa211ebbe9a07dbbf9e081fa7b9a01202e4d9ee0e0e513f80efbbab6c784635429905389ce86"), @@ -45,36 +44,44 @@ private static Stream provideTypedTransactionBytes() throws IOExcepti "0x03f897850120b996ed80840bebc200843b9aca078303345094c8d369b164361a8961286cfbab3bc10f962185a88080c08411e1a300e1a0011df88a2971c8a7ac494a7ba37ec1acaa1fc1edeeb38c839b5d1693d47b69b080a032f122f06e5802224db4c8a58fd22c75173a713f63f89936f811c144b9e40129a043a2a872cbfa5727007adf6a48febe5f190d2e4cd5ed6122823fb6ff47ecda32")); } - private static Stream provideTypedTransactionBytesForNetwork() throws IOException { - return Stream.of(createArgumentFromFile("blob1.txt")); + private static Stream provideOpaqueBytesForNetwork() throws IOException { + return Stream.of(createArgumentFromFile("blob2.txt")); } @ParameterizedTest(name = "{index} {0}") - @MethodSource("provideTypedTransactionBytesForNetwork") + @MethodSource("provideOpaqueBytesForNetwork") public void blobTransactionEncodingDecodingForNetWorkTest( final TypedTransactionBytesArgument argument) { Bytes bytes = argument.bytes; // Decode the transaction from the wire using the TransactionDecoder. - final Transaction transaction = TransactionDecoder.decodeForWire(RLP.input(bytes)); + final Transaction transaction = + TransactionDecoder.decodeOpaqueBytes(bytes, EncodingContext.POOLED_TRANSACTION); + + final BytesValueRLPOutput output = new BytesValueRLPOutput(); + TransactionEncoder.encodeRLP(transaction.getType(), bytes, output); final BytesValueRLPOutput bytesValueRLPOutput = new BytesValueRLPOutput(); - BlobTransactionEncoder.encodeForWireNetwork(transaction, bytesValueRLPOutput); - Bytes encodedRLP = bytesValueRLPOutput.encoded(); - assertThat(encodedRLP.size()).isEqualTo(bytes.size()); - assertThat(encodedRLP).isEqualTo(bytes); + TransactionEncoder.encodeRLP( + transaction, bytesValueRLPOutput, EncodingContext.POOLED_TRANSACTION); + assertThat(transaction.getSize()).isEqualTo(bytes.size()); } @ParameterizedTest(name = "{index} {0}") - @MethodSource("provideTypedTransactionBytes") + @MethodSource("provideOpaqueBytesNoBlobsWithCommitments") public void blobTransactionEncodingDecodingTest(final TypedTransactionBytesArgument argument) { Bytes bytes = argument.bytes; // Decode the transaction from the wire using the TransactionDecoder. - final Transaction transaction = TransactionDecoder.decodeForWire(RLP.input(bytes)); - final BytesValueRLPOutput output = new BytesValueRLPOutput(); + final Transaction transaction = + TransactionDecoder.decodeOpaqueBytes(bytes, EncodingContext.BLOCK_BODY); + // Encode the transaction for wire using the TransactionEncoder. - TransactionEncoder.encodeForWire(transaction, output); + Bytes encoded = TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY); // Assert that the encoded transaction matches the original bytes. - assertThat(output.encoded().toHexString()).isEqualTo(bytes.toHexString()); + assertThat(encoded.toHexString()).isEqualTo(bytes.toHexString()); + + final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); + TransactionEncoder.encodeRLP(transaction.getType(), bytes, rlpOutput); + assertThat(transaction.getSize()).isEqualTo(bytes.size()); } private static Arguments createArgumentFromFile(final String path) throws IOException { @@ -96,9 +103,7 @@ private static Arguments createArgumentFromFile(final String path) throws IOExce } private static Arguments createArgument(final String hex) { - BytesValueRLPOutput out = new BytesValueRLPOutput(); - out.writeBytes(Bytes.fromHexString(hex)); - return Arguments.of(new TypedTransactionBytesArgument(out.encoded())); + return Arguments.of(new TypedTransactionBytesArgument(Bytes.fromHexString(hex))); } @SuppressWarnings("UnusedVariable") diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java index 68c21f94abc..245561158b0 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPException; +import org.hyperledger.besu.ethereum.rlp.RLPInput; import java.math.BigInteger; import java.util.Arrays; @@ -44,8 +45,7 @@ class TransactionRLPDecoderTest { @Test void decodeFrontierNominalCase() { - final Transaction transaction = - TransactionDecoder.decodeForWire(RLP.input(Bytes.fromHexString(FRONTIER_TX_RLP))); + final Transaction transaction = decodeRLP(RLP.input(Bytes.fromHexString(FRONTIER_TX_RLP))); assertThat(transaction).isNotNull(); assertThat(transaction.getGasPrice().get()).isEqualByComparingTo(Wei.of(50L)); assertThat(transaction.getMaxPriorityFeePerGas()).isEmpty(); @@ -54,8 +54,7 @@ void decodeFrontierNominalCase() { @Test void decodeEIP1559NominalCase() { - final Transaction transaction = - TransactionDecoder.decodeForWire(RLP.input(Bytes.fromHexString(EIP1559_TX_RLP))); + final Transaction transaction = decodeRLP(RLP.input(Bytes.fromHexString(EIP1559_TX_RLP))); assertThat(transaction).isNotNull(); assertThat(transaction.getMaxPriorityFeePerGas()).hasValue(Wei.of(2L)); assertThat(transaction.getMaxFeePerGas()).hasValue(Wei.of(new BigInteger("5000000000", 10))); @@ -66,15 +65,16 @@ void doesNotDecodeEIP1559WithLargeMaxFeePerGasOrLargeMaxPriorityFeePerGas() { final String txWithBigFees = "0x02f84e0101a1648a5f8b2dcad5ea5ba6b720ff069c1d87c21a4a6a5b3766b39e2c2792367bb066a1ffa5ffaf5b0560d3a9fb186c2ede2ae6751bc0b4fef9107cf36389630b6196a38805800180c0010203"; assertThatThrownBy( - () -> TransactionDecoder.decodeOpaqueBytes(Bytes.fromHexString(txWithBigFees))) + () -> + TransactionDecoder.decodeOpaqueBytes( + Bytes.fromHexString(txWithBigFees), EncodingContext.BLOCK_BODY)) .isInstanceOf(RLPException.class); } @Test void shouldDecodeWithHighNonce() { final Transaction transaction = - TransactionDecoder.decodeForWire( - RLP.input(Bytes.fromHexString(NONCE_64_BIT_MAX_MINUS_2_TX_RLP))); + decodeRLP(RLP.input(Bytes.fromHexString(NONCE_64_BIT_MAX_MINUS_2_TX_RLP))); assertThat(transaction).isNotNull(); assertThat(transaction.getNonce()).isEqualTo(MAX_NONCE - 1); } @@ -94,16 +94,21 @@ void shouldCalculateCorrectTransactionSize(final String rlp_tx, final String ign // Create bytes from String final Bytes bytes = Bytes.fromHexString(rlp_tx); // Decode bytes into a transaction - final Transaction transaction = TransactionDecoder.decodeForWire(RLP.input(bytes)); + final Transaction transaction = decodeRLP(RLP.input(bytes)); + Bytes transactionBytes = + TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.POOLED_TRANSACTION); // Bytes size should be equal to transaction size - assertThat(transaction.getSize()).isEqualTo(bytes.size()); + assertThat(transaction.getSize()).isEqualTo(transactionBytes.size()); } @ParameterizedTest @ValueSource(strings = {FRONTIER_TX_RLP, EIP1559_TX_RLP, NONCE_64_BIT_MAX_MINUS_2_TX_RLP}) void shouldReturnCorrectEncodedBytes(final String txRlp) { - final Transaction transaction = - TransactionDecoder.decodeForWire(RLP.input(Bytes.fromHexString(txRlp))); + final Transaction transaction = decodeRLP(RLP.input(Bytes.fromHexString(txRlp))); assertThat(transaction.encoded()).isEqualTo(Bytes.fromHexString(txRlp)); } + + private Transaction decodeRLP(final RLPInput input) { + return TransactionDecoder.decodeRLP(input, EncodingContext.POOLED_TRANSACTION); + } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java index 4e9f2187e16..fa84bc5ef7a 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.RLP; +import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.Test; @@ -36,19 +37,17 @@ class TransactionRLPEncoderTest { @Test void encodeFrontierTxNominalCase() { - final Transaction transaction = - TransactionDecoder.decodeForWire(RLP.input(Bytes.fromHexString(FRONTIER_TX_RLP))); + final Transaction transaction = decodeRLP(RLP.input(Bytes.fromHexString(FRONTIER_TX_RLP))); final BytesValueRLPOutput output = new BytesValueRLPOutput(); - TransactionEncoder.encodeForWire(transaction, output); + encodeRLP(transaction, output); assertThat(output.encoded().toHexString()).isEqualTo(FRONTIER_TX_RLP); } @Test void encodeEIP1559TxNominalCase() { - final Transaction transaction = - TransactionDecoder.decodeForWire(RLP.input(Bytes.fromHexString(EIP1559_TX_RLP))); + final Transaction transaction = decodeRLP(RLP.input(Bytes.fromHexString(EIP1559_TX_RLP))); final BytesValueRLPOutput output = new BytesValueRLPOutput(); - TransactionEncoder.encodeForWire(transaction, output); + encodeRLP(transaction, output); assertThat(output.encoded().toHexString()).isEqualTo(EIP1559_TX_RLP); } @@ -70,10 +69,17 @@ void blockWithLegacyAndEIP2930TransactionsRoundTrips() { @Test void shouldEncodeWithHighNonce() { final Transaction transaction = - TransactionDecoder.decodeForWire( - RLP.input(Bytes.fromHexString(NONCE_64_BIT_MAX_MINUS_2_TX_RLP))); + decodeRLP(RLP.input(Bytes.fromHexString(NONCE_64_BIT_MAX_MINUS_2_TX_RLP))); final BytesValueRLPOutput output = new BytesValueRLPOutput(); - TransactionEncoder.encodeForWire(transaction, output); + encodeRLP(transaction, output); assertThat(output.encoded().toHexString()).isEqualTo(NONCE_64_BIT_MAX_MINUS_2_TX_RLP); } + + private Transaction decodeRLP(final RLPInput input) { + return TransactionDecoder.decodeRLP(input, EncodingContext.BLOCK_BODY); + } + + private void encodeRLP(final Transaction transaction, final BytesValueRLPOutput output) { + TransactionEncoder.encodeRLP(transaction, output, EncodingContext.BLOCK_BODY); + } } diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob2.txt b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob2.txt new file mode 100644 index 00000000000..c20766e5314 --- /dev/null +++ b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob2.txt @@ -0,0 +1 @@ +0x03fa0200fdf88f0780843b9aca008506fc23ac00830186a09400000000000000000000000000000000000001008080c001e1a0010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401401a0840650aa8f74d2b07f40067dc33b715078d73422f01da17abdbd11e02bbdfda9a04b2260f6022bf53eadb337b3e59514936f7317d872defb891a708ee279bdca90fa020004ba0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1b0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1b0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java index 03301803da6..76346f4152e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java @@ -20,6 +20,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; +import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.messages.BlockBodiesMessage; import org.hyperledger.besu.ethereum.eth.messages.BlockHeadersMessage; @@ -269,8 +271,9 @@ static MessageData constructGetPooledTransactionsResponse( if (maybeTx.isEmpty()) { continue; } + final BytesValueRLPOutput txRlp = new BytesValueRLPOutput(); - maybeTx.get().writeTo(txRlp); + TransactionEncoder.encodeRLP(maybeTx.get(), txRlp, EncodingContext.POOLED_TRANSACTION); final int encodedSize = txRlp.encodedSize(); if (responseSizeEstimate + encodedSize > maxMessageSize) { break; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java index 8f4717bb5c1..8218210164c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java @@ -15,7 +15,9 @@ package org.hyperledger.besu.ethereum.eth.messages; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; +import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; +import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractMessageData; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; @@ -44,11 +46,7 @@ public static PooledTransactionsMessage create(final List transacti out.writeList( transactions, (transaction, rlpOutput) -> { - if (transaction.getType().supportsBlob()) { - BlobTransactionEncoder.encodeForWireNetwork(transaction, rlpOutput); - } else { - transaction.writeTo(rlpOutput); - } + TransactionEncoder.encodeRLP(transaction, rlpOutput, EncodingContext.POOLED_TRANSACTION); }); return new PooledTransactionsMessage(out.encoded()); } @@ -80,7 +78,9 @@ public static PooledTransactionsMessage readFrom(final MessageData message) { public List transactions() { if (pooledTransactions == null) { final BytesValueRLPInput in = new BytesValueRLPInput(getData(), false); - pooledTransactions = in.readList(Transaction::readFrom); + pooledTransactions = + in.readList( + input -> TransactionDecoder.decodeRLP(input, EncodingContext.POOLED_TRANSACTION)); } return pooledTransactions; } From 880914b851849bd560ed1b5e80b7a5be7f761f83 Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:03:37 +1000 Subject: [PATCH 18/34] #5868: fix beacon root address and modulus for devnet 9 (#5871) Signed-off-by: Stefan Signed-off-by: garyschulte --- .../besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java index 8b9cf256aef..7d110fb425b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java @@ -25,9 +25,9 @@ public class ParentBeaconBlockRootHelper { // Modulus use to for the timestamp to store the root - public static final long HISTORICAL_ROOTS_MODULUS = 98304; + public static final long HISTORICAL_ROOTS_MODULUS = 8191; public static final Address BEACON_ROOTS_ADDRESS = - Address.fromHexString("0xbEac00dDB15f3B6d645C48263dC93862413A222D"); + Address.fromHexString("0xBEaC020001c6C8B69E5257f4754e46e25f5dc9cB"); public static void storeParentBeaconBlockRoot( final WorldUpdater worldUpdater, final long timestamp, final Bytes32 root) { From eb2c430af0ac9bc75764f2cfb2c4901e0530989e Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:47:51 +1000 Subject: [PATCH 19/34] payload attributes: fix wrong warning and fail if beacon root is available before cancun (#5872) Signed-off-by: Stefan Co-authored-by: Sally MacFarlane Signed-off-by: garyschulte --- .../methods/engine/AbstractEngineForkchoiceUpdated.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java index cfb28bcc9ef..1cde6c259a0 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java @@ -219,9 +219,14 @@ private boolean isPayloadAttributesValid( return false; } if (payloadAttributes.getTimestamp() < cancunTimestamp) { - LOG.warn("Payload attributes are present before cancun hardfork"); + if (payloadAttributes.getParentBeaconBlockRoot() != null) { + LOG.error( + "Parent beacon block root hash present in payload attributes before cancun hardfork"); + return false; + } } else if (payloadAttributes.getParentBeaconBlockRoot() == null) { - LOG.warn("Parent beacon block root not present in payload attributes after cancun hardfork"); + LOG.error( + "Parent beacon block root hash not present in payload attributes after cancun hardfork"); return false; } if (!getWithdrawalsValidator( From 9ec9fcb982dc16c0596c90148168a48d090d8467 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 13 Sep 2023 09:26:04 -0600 Subject: [PATCH 20/34] Merge MutableAccount and EVMAccount (#5863) Merge MutableAccount and EVMAccount functionalities by removing EVMAccount, all calls to getMutable, and the WrappedEVMAccount that was wrapping non-EVMAccounts in a mutable fashion. Instead, use a MutableAccount in all cases an EVMAccount would have been used. This also tends to reduce a level of layering in many places. Signed-off-by: Danno Ferrin Signed-off-by: garyschulte --- .../blockcreation/AbstractBlockCreator.java | 18 +-- .../vm/EntriesFromIntegrationTest.java | 12 +- .../TransientStorageOperationBenchmark.java | 2 +- .../besu/ethereum/bonsai/BonsaiAccount.java | 29 ++-- .../BonsaiWorldStateUpdateAccumulator.java | 118 ++++++-------- .../besu/ethereum/chain/GenesisState.java | 6 +- .../mainnet/ClassicBlockProcessor.java | 5 +- .../mainnet/MainnetBlockProcessor.java | 6 +- .../mainnet/MainnetProtocolSpecs.java | 4 +- .../mainnet/MainnetTransactionProcessor.java | 14 +- .../mainnet/ParentBeaconBlockRootHelper.java | 6 +- .../mainnet/WithdrawalsProcessor.java | 6 +- ...PrivateGroupRehydrationBlockProcessor.java | 5 +- .../privacy/PrivateStateGenesisAllocator.java | 11 +- .../privacy/PrivateTransactionProcessor.java | 7 +- .../PrivateMigrationBlockProcessor.java | 5 +- .../ethereum/vm/DebugOperationTracer.java | 7 +- ...efaultMutablePrivateWorldStateUpdater.java | 15 +- .../ethereum/core/BlockDataGenerator.java | 48 ++---- .../besu/ethereum/bonsai/LogRollingTests.java | 25 ++- .../MainnetTransactionProcessorTest.java | 11 +- .../mainnet/PrivacyBlockProcessorTest.java | 11 +- .../ethereum/vm/DebugOperationTracerTest.java | 31 ++-- .../DefaultMutableWorldStateTest.java | 152 +++++++++--------- .../hyperledger/besu/evmtool/T8nExecutor.java | 1 - .../ReferenceTestWorldState.java | 2 +- .../besu/evm/account/EvmAccount.java | 28 ---- .../besu/evm/account/MutableAccount.java | 5 + .../besu/evm/fluent/SimpleAccount.java | 30 +++- .../besu/evm/fluent/SimpleWorld.java | 9 +- .../operation/AbstractCreateOperation.java | 2 +- .../besu/evm/operation/SStoreOperation.java | 3 +- .../evm/operation/SelfDestructOperation.java | 5 +- .../processor/ContractCreationProcessor.java | 7 +- .../evm/processor/MessageCallProcessor.java | 15 +- .../evm/worldstate/AbstractWorldUpdater.java | 15 +- .../evm/worldstate/UpdateTrackingAccount.java | 30 +++- .../besu/evm/worldstate/WorldUpdater.java | 15 +- .../evm/worldstate/WrappedEvmAccount.java | 119 -------------- .../AbstractCreateOperationTest.java | 13 +- .../evm/operations/Create2OperationTest.java | 28 ++-- .../evm/operations/CreateOperationTest.java | 46 ++---- .../operations/ExtCodeHashOperationTest.java | 8 +- .../evm/operations/SStoreOperationTest.java | 2 +- .../operations/SelfDestructOperationTest.java | 17 +- .../evm/operations/TStoreOperationTest.java | 2 +- .../besu/evm/testutils/TestCodeExecutor.java | 5 +- .../besu/evm/toy/EvmToyCommand.java | 4 +- .../hyperledger/besu/evm/toy/ToyAccount.java | 30 +++- .../hyperledger/besu/evm/toy/ToyWorld.java | 8 +- .../tracing/ExtendedOperationTracerTest.java | 6 +- 51 files changed, 401 insertions(+), 608 deletions(-) delete mode 100644 evm/src/main/java/org/hyperledger/besu/evm/account/EvmAccount.java delete mode 100644 evm/src/main/java/org/hyperledger/besu/evm/worldstate/WrappedEvmAccount.java diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index cde0b95bbb7..80037c8c6c1 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -50,7 +50,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; @@ -190,10 +190,10 @@ protected BlockCreationResult createBlock( final List ommers = maybeOmmers.orElse(selectOmmers()); - if (maybeParentBeaconBlockRoot.isPresent()) { - ParentBeaconBlockRootHelper.storeParentBeaconBlockRoot( - disposableWorldState.updater(), timestamp, maybeParentBeaconBlockRoot.get()); - } + maybeParentBeaconBlockRoot.ifPresent( + bytes32 -> + ParentBeaconBlockRootHelper.storeParentBeaconBlockRoot( + disposableWorldState.updater(), timestamp, bytes32)); throwIfStopped(); final TransactionSelectionResults transactionResults = @@ -466,9 +466,9 @@ boolean rewardBeneficiary( .getBlockProcessor() .getCoinbaseReward(blockReward, header.getNumber(), ommers.size()); final WorldUpdater updater = worldState.updater(); - final EvmAccount beneficiary = updater.getOrCreate(miningBeneficiary); + final MutableAccount beneficiary = updater.getOrCreate(miningBeneficiary); - beneficiary.getMutable().incrementBalance(coinbaseReward); + beneficiary.incrementBalance(coinbaseReward); for (final BlockHeader ommerHeader : ommers) { if (ommerHeader.getNumber() - header.getNumber() > MAX_GENERATION) { LOG.trace( @@ -479,12 +479,12 @@ boolean rewardBeneficiary( return false; } - final EvmAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase()); + final MutableAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase()); final Wei ommerReward = protocolSpec .getBlockProcessor() .getOmmerReward(blockReward, header.getNumber(), ommerHeader.getNumber()); - ommerCoinbase.getMutable().incrementBalance(ommerReward); + ommerCoinbase.incrementBalance(ommerReward); } updater.commit(); diff --git a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/EntriesFromIntegrationTest.java b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/EntriesFromIntegrationTest.java index e139d69352d..fcfd71f206e 100644 --- a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/EntriesFromIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/EntriesFromIntegrationTest.java @@ -39,7 +39,7 @@ public class EntriesFromIntegrationTest { public void shouldCollectStateEntries() { final MutableWorldState worldState = createInMemoryWorldStateArchive().getMutable(); final WorldUpdater updater = worldState.updater(); - MutableAccount account = updater.getOrCreate(Address.fromHexString("0x56")).getMutable(); + MutableAccount account = updater.getOrCreate(Address.fromHexString("0x56")); final Map expectedValues = new TreeMap<>(); final int nodeCount = 100_000; final Random random = new Random(42989428249L); @@ -49,19 +49,19 @@ public void shouldCollectStateEntries() { addExpectedValue( account, expectedValues, - UInt256.valueOf(Math.abs(random.nextLong())), - UInt256.valueOf(i * 10 + 1)); + UInt256.valueOf(random.nextLong(Long.MAX_VALUE)), + UInt256.valueOf(i * 10 + 1L)); } updater.commit(); // Add some changes on top that AbstractWorldUpdater.UpdateTrackingAccount will have to merge. - account = worldState.updater().getOrCreate(Address.fromHexString("0x56")).getMutable(); + account = worldState.updater().getOrCreate(Address.fromHexString("0x56")); for (int i = 0; i <= nodeCount; i++) { addExpectedValue( account, expectedValues, - UInt256.valueOf(Math.abs(random.nextLong())), - UInt256.valueOf(i * 10 + 1)); + UInt256.valueOf(random.nextLong(Long.MAX_VALUE)), + UInt256.valueOf(i * 10 + 1L)); } final Map values = diff --git a/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/TransientStorageOperationBenchmark.java b/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/TransientStorageOperationBenchmark.java index 612bedc2c74..19d3c8b45ca 100644 --- a/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/TransientStorageOperationBenchmark.java +++ b/ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/TransientStorageOperationBenchmark.java @@ -59,7 +59,7 @@ private MessageFrame createMessageFrame(final Address address) { .blockHeader(blockHeader) .blockchain(blockchain) .build(); - worldStateUpdater.getOrCreate(address).getMutable().setBalance(Wei.of(1)); + worldStateUpdater.getOrCreate(address).setBalance(Wei.of(1)); worldStateUpdater.commit(); return benchmarkFrame; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java index 14be477a07d..a5488cb9a2e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java @@ -28,7 +28,6 @@ import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.evm.ModificationNotAllowedException; import org.hyperledger.besu.evm.account.AccountStorageEntry; -import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount; @@ -41,9 +40,9 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -public class BonsaiAccount implements MutableAccount, EvmAccount, AccountValue { +public class BonsaiAccount implements MutableAccount, AccountValue { private final BonsaiWorldView context; - private final boolean mutable; + private boolean mutable; private final Address address; private final Hash addressHash; @@ -163,7 +162,7 @@ public long getNonce() { @Override public void setNonce(final long value) { if (!mutable) { - throw new UnsupportedOperationException("Account is immutable"); + throw new ModificationNotAllowedException(); } nonce = value; } @@ -176,7 +175,7 @@ public Wei getBalance() { @Override public void setBalance(final Wei value) { if (!mutable) { - throw new UnsupportedOperationException("Account is immutable"); + throw new ModificationNotAllowedException(); } balance = value; } @@ -192,7 +191,7 @@ public Bytes getCode() { @Override public void setCode(final Bytes code) { if (!mutable) { - throw new UnsupportedOperationException("Account is immutable"); + throw new ModificationNotAllowedException(); } this.code = code; if (code == null || code.isEmpty()) { @@ -244,7 +243,7 @@ public void writeTo(final RLPOutput out) { @Override public void setStorageValue(final UInt256 key, final UInt256 value) { if (!mutable) { - throw new UnsupportedOperationException("Account is immutable"); + throw new ModificationNotAllowedException(); } updatedStorage.put(key, value); } @@ -259,15 +258,6 @@ public Map getUpdatedStorage() { return updatedStorage; } - @Override - public MutableAccount getMutable() throws ModificationNotAllowedException { - if (mutable) { - return this; - } else { - throw new ModificationNotAllowedException(); - } - } - @Override public Hash getStorageRoot() { return storageRoot; @@ -275,11 +265,16 @@ public Hash getStorageRoot() { public void setStorageRoot(final Hash storageRoot) { if (!mutable) { - throw new UnsupportedOperationException("Account is immutable"); + throw new ModificationNotAllowedException(); } this.storageRoot = storageRoot; } + @Override + public void becomeImmutable() { + mutable = false; + } + @Override public String toString() { return "AccountState{" diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java index 2a04f92fb19..b1cd64378b9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java @@ -27,10 +27,9 @@ import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater; import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount; -import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLogAccumulator; @@ -44,6 +43,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.function.Function; import com.google.common.collect.ForwardingMap; @@ -115,12 +115,12 @@ protected UpdateTrackingAccount track( } @Override - public EvmAccount getAccount(final Address address) { + public MutableAccount getAccount(final Address address) { return super.getAccount(address); } @Override - public EvmAccount createAccount(final Address address, final long nonce, final Wei balance) { + public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) { BonsaiValue bonsaiValue = accountsToUpdate.get(address); if (bonsaiValue == null) { @@ -141,7 +141,7 @@ public EvmAccount createAccount(final Address address, final long nonce, final W Hash.EMPTY, true); bonsaiValue.setUpdated(newAccount); - return new WrappedEvmAccount(track(new UpdateTrackingAccount<>(newAccount))); + return track(new UpdateTrackingAccount<>(newAccount)); } @Override @@ -176,17 +176,15 @@ protected BonsaiAccount loadAccount( final BonsaiValue bonsaiValue = accountsToUpdate.get(address); if (bonsaiValue == null) { final Account account; - if (wrappedWorldView() instanceof BonsaiWorldStateUpdateAccumulator) { - account = - ((BonsaiWorldStateUpdateAccumulator) wrappedWorldView()) - .loadAccount(address, bonsaiAccountFunction); + if (wrappedWorldView() + instanceof BonsaiWorldStateUpdateAccumulator bonsaiWorldStateUpdateAccumulator) { + account = bonsaiWorldStateUpdateAccumulator.loadAccount(address, bonsaiAccountFunction); } else { account = wrappedWorldView().get(address); } - BonsaiAccount mutableAccount = null; - if (account instanceof BonsaiAccount) { - mutableAccount = new BonsaiAccount((BonsaiAccount) account, this, true); - accountsToUpdate.put(address, new BonsaiValue<>((BonsaiAccount) account, mutableAccount)); + if (account instanceof BonsaiAccount bonsaiAccount) { + BonsaiAccount mutableAccount = new BonsaiAccount(bonsaiAccount, this, true); + accountsToUpdate.put(address, new BonsaiValue<>(bonsaiAccount, mutableAccount)); return mutableAccount; } else { // add the empty read in accountsToUpdate @@ -418,14 +416,13 @@ public Optional getStorageValueByStorageSlotKey( } try { final Optional valueUInt = - (wrappedWorldView() instanceof BonsaiWorldState) - ? ((BonsaiWorldState) wrappedWorldView()) - .getStorageValueByStorageSlotKey( - () -> - Optional.ofNullable(loadAccount(address, BonsaiValue::getPrior)) - .map(BonsaiAccount::getStorageRoot), - address, - storageSlotKey) + (wrappedWorldView() instanceof BonsaiWorldState bonsaiWorldState) + ? bonsaiWorldState.getStorageValueByStorageSlotKey( + () -> + Optional.ofNullable(loadAccount(address, BonsaiValue::getPrior)) + .map(BonsaiAccount::getStorageRoot), + address, + storageSlotKey) : wrappedWorldView().getStorageValueByStorageSlotKey(address, storageSlotKey); storageToUpdate .computeIfAbsent( @@ -495,53 +492,43 @@ public BonsaiWorldStateKeyValueStorage getWorldStateStorage() { } public void rollForward(final TrieLog layer) { - layer.getAccountChanges().entrySet().stream() + layer + .getAccountChanges() .forEach( - entry -> - rollAccountChange( - entry.getKey(), entry.getValue().getPrior(), entry.getValue().getUpdated())); - layer.getCodeChanges().entrySet().stream() + (address, change) -> + rollAccountChange(address, change.getPrior(), change.getUpdated())); + layer + .getCodeChanges() .forEach( - entry -> - rollCodeChange( - entry.getKey(), entry.getValue().getPrior(), entry.getValue().getUpdated())); - layer.getStorageChanges().entrySet().stream() + (address, change) -> rollCodeChange(address, change.getPrior(), change.getUpdated())); + layer + .getStorageChanges() .forEach( - entry -> - entry - .getValue() - .forEach( - (storageSlotKey, value) -> - rollStorageChange( - entry.getKey(), - storageSlotKey, - value.getPrior(), - value.getUpdated()))); + (address, storage) -> + storage.forEach( + (storageSlotKey, value) -> + rollStorageChange( + address, storageSlotKey, value.getPrior(), value.getUpdated()))); } public void rollBack(final TrieLog layer) { - layer.getAccountChanges().entrySet().stream() + layer + .getAccountChanges() .forEach( - entry -> - rollAccountChange( - entry.getKey(), entry.getValue().getUpdated(), entry.getValue().getPrior())); - layer.getCodeChanges().entrySet().stream() + (address, change) -> + rollAccountChange(address, change.getUpdated(), change.getPrior())); + layer + .getCodeChanges() .forEach( - entry -> - rollCodeChange( - entry.getKey(), entry.getValue().getUpdated(), entry.getValue().getPrior())); - layer.getStorageChanges().entrySet().stream() + (address, change) -> rollCodeChange(address, change.getUpdated(), change.getPrior())); + layer + .getStorageChanges() .forEach( - entry -> - entry - .getValue() - .forEach( - (storageSlotKey, value) -> - rollStorageChange( - entry.getKey(), - storageSlotKey, - value.getUpdated(), - value.getPrior()))); + (address, storage) -> + storage.forEach( + (storageSlotKey, value) -> + rollStorageChange( + address, storageSlotKey, value.getUpdated(), value.getPrior()))); } private void rollAccountChange( @@ -598,8 +585,7 @@ private BonsaiValue loadAccountFromParent( final Address address, final BonsaiValue defaultValue) { try { final Account parentAccount = wrappedWorldView().get(address); - if (parentAccount instanceof BonsaiAccount) { - final BonsaiAccount account = (BonsaiAccount) parentAccount; + if (parentAccount instanceof BonsaiAccount account) { final BonsaiValue loadedAccountValue = new BonsaiValue<>(new BonsaiAccount(account), account); accountsToUpdate.put(address, loadedAccountValue); @@ -634,7 +620,7 @@ private void rollCodeChange( } if (codeValue == null) { - if ((expectedCode == null || expectedCode.size() == 0) && replacementCode != null) { + if ((expectedCode == null || expectedCode.isEmpty()) && replacementCode != null) { codeToUpdate.put(address, new BonsaiValue<>(null, replacementCode)); } else { throw new IllegalStateException( @@ -772,11 +758,11 @@ public void reset() { public static class AccountConsumingMap extends ForwardingMap { - private final ConcurrentHashMap accounts; + private final ConcurrentMap accounts; private final Consumer consumer; public AccountConsumingMap( - final ConcurrentHashMap accounts, final Consumer consumer) { + final ConcurrentMap accounts, final Consumer consumer) { this.accounts = accounts; this.consumer = consumer; } @@ -801,11 +787,11 @@ public static class StorageConsumingMap extends ForwardingMap { private final Address address; - private final ConcurrentHashMap storages; + private final ConcurrentMap storages; private final Consumer consumer; public StorageConsumingMap( - final Address address, final ConcurrentHashMap storages, final Consumer consumer) { + final Address address, final ConcurrentMap storages, final Consumer consumer) { this.address = address; this.storages = storages; this.consumer = consumer; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java index b873161976a..f6c969d58b2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java @@ -48,7 +48,6 @@ import java.util.Optional; import java.util.OptionalLong; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; import com.google.common.base.MoreObjects; @@ -86,8 +85,7 @@ public static GenesisState fromJson(final String json, final ProtocolSchedule pr */ public static GenesisState fromConfig( final GenesisConfigFile config, final ProtocolSchedule protocolSchedule) { - final List genesisAccounts = - parseAllocations(config).collect(Collectors.toList()); + final List genesisAccounts = parseAllocations(config).toList(); final Block block = new Block( buildHeader(config, calculateGenesisStateHash(genesisAccounts), protocolSchedule), @@ -124,7 +122,7 @@ private static void writeAccountsTo( final WorldUpdater updater = target.updater(); genesisAccounts.forEach( genesisAccount -> { - final MutableAccount account = updater.getOrCreate(genesisAccount.address).getMutable(); + final MutableAccount account = updater.getOrCreate(genesisAccount.address); account.setNonce(genesisAccount.nonce); account.setBalance(genesisAccount.balance); account.setCode(genesisAccount.code); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicBlockProcessor.java index 5079c0763be..044017b8728 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicBlockProcessor.java @@ -64,7 +64,7 @@ boolean rewardCoinbase( } final Wei coinbaseReward = getCoinbaseReward(blockReward, header.getNumber(), ommers.size()); final WorldUpdater updater = worldState.updater(); - final MutableAccount coinbase = updater.getOrCreate(header.getCoinbase()).getMutable(); + final MutableAccount coinbase = updater.getOrCreate(header.getCoinbase()); coinbase.incrementBalance(coinbaseReward); for (final BlockHeader ommerHeader : ommers) { @@ -77,8 +77,7 @@ boolean rewardCoinbase( return false; } - final MutableAccount ommerCoinbase = - updater.getOrCreate(ommerHeader.getCoinbase()).getMutable(); + final MutableAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase()); final Wei ommerReward = getOmmerReward(blockReward, header.getNumber(), ommerHeader.getNumber()); ommerCoinbase.incrementBalance(ommerReward); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockProcessor.java index ae1187eb6bb..9f2096f63d2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockProcessor.java @@ -59,8 +59,7 @@ protected boolean rewardCoinbase( final Wei coinbaseReward = getCoinbaseReward(blockReward, header.getNumber(), ommers.size()); final WorldUpdater updater = worldState.updater(); final Address miningBeneficiary = getMiningBeneficiaryCalculator().calculateBeneficiary(header); - final MutableAccount miningBeneficiaryAccount = - updater.getOrCreate(miningBeneficiary).getMutable(); + final MutableAccount miningBeneficiaryAccount = updater.getOrCreate(miningBeneficiary); miningBeneficiaryAccount.incrementBalance(coinbaseReward); for (final BlockHeader ommerHeader : ommers) { @@ -73,8 +72,7 @@ protected boolean rewardCoinbase( return false; } - final MutableAccount ommerCoinbase = - updater.getOrCreate(ommerHeader.getCoinbase()).getMutable(); + final MutableAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase()); final Wei ommerReward = getOmmerReward(blockReward, header.getNumber(), ommerHeader.getNumber()); ommerCoinbase.incrementBalance(ommerReward); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index dd94e60b5bd..02f757483df 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -870,9 +870,9 @@ private void updateWorldStateForDao(final MutableWorldState worldState) { .toList(); final WorldUpdater worldUpdater = worldState.updater(); final MutableAccount daoRefundContract = - worldUpdater.getOrCreate(DAO_REFUND_CONTRACT_ADDRESS).getMutable(); + worldUpdater.getOrCreate(DAO_REFUND_CONTRACT_ADDRESS); for (final Address address : addresses) { - final MutableAccount account = worldUpdater.getOrCreate(address).getMutable(); + final MutableAccount account = worldUpdater.getOrCreate(address); final Wei balance = account.getBalance(); account.decrementBalance(balance); daoRefundContract.incrementBalance(balance); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 6dbd3b4c3db..7d235fb3a39 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -33,7 +33,6 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.code.CodeV0; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; @@ -285,7 +284,7 @@ public TransactionProcessingResult processTransaction( final Address senderAddress = transaction.getSender(); - final EvmAccount sender = worldState.getOrCreateSenderAccount(senderAddress); + final MutableAccount sender = worldState.getOrCreateSenderAccount(senderAddress); validationResult = transactionValidator.validateForSender(transaction, sender, transactionValidationParams); @@ -294,8 +293,7 @@ public TransactionProcessingResult processTransaction( return TransactionProcessingResult.invalid(validationResult); } - final MutableAccount senderMutableAccount = sender.getMutable(); - final long previousNonce = senderMutableAccount.incrementNonce(); + final long previousNonce = sender.incrementNonce(); LOG.trace( "Incremented sender {} nonce ({} -> {})", senderAddress, @@ -309,7 +307,7 @@ public TransactionProcessingResult processTransaction( final Wei upfrontGasCost = transaction.getUpfrontGasCost(transactionGasPrice, blobGasPrice, blobGas); - final Wei previousBalance = senderMutableAccount.decrementBalance(upfrontGasCost); + final Wei previousBalance = sender.decrementBalance(upfrontGasCost); LOG.trace( "Deducted sender {} upfront gas cost {} ({} -> {})", senderAddress, @@ -386,7 +384,7 @@ public TransactionProcessingResult processTransaction( final MessageFrame initialFrame; if (transaction.isContractCreation()) { final Address contractAddress = - Address.contractAddress(senderAddress, senderMutableAccount.getNonce() - 1L); + Address.contractAddress(senderAddress, sender.getNonce() - 1L); final Bytes initCodeBytes = transaction.getPayload(); initialFrame = @@ -443,7 +441,7 @@ public TransactionProcessingResult processTransaction( final long refundedGas = refunded(transaction, initialFrame.getRemainingGas(), baseRefundGas); final Wei refundedWei = transactionGasPrice.multiply(refundedGas); final Wei balancePriorToRefund = sender.getBalance(); - senderMutableAccount.incrementBalance(refundedWei); + sender.incrementBalance(refundedWei); LOG.atTrace() .setMessage("refunded sender {} {} wei ({} -> {})") .addArgument(senderAddress) @@ -454,7 +452,7 @@ public TransactionProcessingResult processTransaction( final long gasUsedByTransaction = transaction.getGasLimit() - initialFrame.getRemainingGas(); // update the coinbase - final var coinbase = worldState.getOrCreate(miningBeneficiary).getMutable(); + final var coinbase = worldState.getOrCreate(miningBeneficiary); final long usedGas = transaction.getGasLimit() - refundedGas; final CoinbaseFeePriceCalculator coinbaseCalculator; if (blockHeader.getBaseFee().isPresent()) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java index 7d110fb425b..669815f7d52 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ParentBeaconBlockRootHelper.java @@ -22,14 +22,14 @@ import org.apache.tuweni.units.bigints.UInt256; /** A helper class to store the parent beacon block root. */ -public class ParentBeaconBlockRootHelper { +public interface ParentBeaconBlockRootHelper { // Modulus use to for the timestamp to store the root public static final long HISTORICAL_ROOTS_MODULUS = 8191; public static final Address BEACON_ROOTS_ADDRESS = Address.fromHexString("0xBEaC020001c6C8B69E5257f4754e46e25f5dc9cB"); - public static void storeParentBeaconBlockRoot( + static void storeParentBeaconBlockRoot( final WorldUpdater worldUpdater, final long timestamp, final Bytes32 root) { /* see EIP-4788: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4788.md @@ -40,7 +40,7 @@ public static void storeParentBeaconBlockRoot( final UInt256 timestampIndex = UInt256.valueOf(timestampReduced); final UInt256 rootIndex = UInt256.valueOf(timestampExtended); - final MutableAccount account = worldUpdater.getOrCreate(BEACON_ROOTS_ADDRESS).getMutable(); + final MutableAccount account = worldUpdater.getOrCreate(BEACON_ROOTS_ADDRESS); account.setStorageValue(timestampIndex, UInt256.valueOf(timestamp)); account.setStorageValue(rootIndex, UInt256.fromBytes(root)); worldUpdater.commit(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsProcessor.java index b91f81208a6..d2b0f8edf78 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsProcessor.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.ethereum.mainnet; import org.hyperledger.besu.ethereum.core.Withdrawal; -import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.util.List; @@ -25,8 +25,8 @@ public class WithdrawalsProcessor { public void processWithdrawals( final List withdrawals, final WorldUpdater worldUpdater) { for (final Withdrawal withdrawal : withdrawals) { - final EvmAccount account = worldUpdater.getOrCreate(withdrawal.getAddress()); - account.getMutable().incrementBalance(withdrawal.getAmount().getAsWei()); + final MutableAccount account = worldUpdater.getOrCreate(withdrawal.getAddress()); + account.incrementBalance(withdrawal.getAmount().getAsWei()); } worldUpdater.clearAccountsThatAreEmpty(); worldUpdater.commit(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java index 713d73c48e5..462bd9c6619 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java @@ -231,7 +231,7 @@ private boolean rewardCoinbase( final Wei coinbaseReward = blockReward.add(blockReward.multiply(ommers.size()).divide(32)); final WorldUpdater updater = worldState.updater(); - final MutableAccount coinbase = updater.getOrCreate(header.getCoinbase()).getMutable(); + final MutableAccount coinbase = updater.getOrCreate(header.getCoinbase()); coinbase.incrementBalance(coinbaseReward); for (final BlockHeader ommerHeader : ommers) { @@ -245,8 +245,7 @@ private boolean rewardCoinbase( return false; } - final MutableAccount ommerCoinbase = - updater.getOrCreate(ommerHeader.getCoinbase()).getMutable(); + final MutableAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase()); final long distance = header.getNumber() - ommerHeader.getNumber(); final Wei ommerReward = blockReward.subtract(blockReward.multiply(distance).divide(8)); ommerCoinbase.incrementBalance(ommerReward); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateStateGenesisAllocator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateStateGenesisAllocator.java index 1f84f210b92..f1a022fa7c2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateStateGenesisAllocator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateStateGenesisAllocator.java @@ -56,7 +56,7 @@ public void applyGenesisToPrivateWorldState( final PrivacyGenesis genesis = privacyGroupGenesisProvider.getPrivacyGenesis(privacyGroupId, blockNumber); - if (genesis.getAccounts().size() > 0) { + if (!genesis.getAccounts().isEmpty()) { LOG.debug( "Applying {} privacy accounts onto {} private state genesis at {}", @@ -67,15 +67,14 @@ public void applyGenesisToPrivateWorldState( genesis .getAccounts() .forEach( - (genesisAccount) -> { + genesisAccount -> { final Address address = genesisAccount.getAddress(); if (address.toBigInteger().compareTo(BigInteger.valueOf(Byte.MAX_VALUE)) < 0) { LOG.warn( "Genesis address {} is in reserved range and may be overwritten", address); } - final MutableAccount account = - privateWorldStateUpdater.createAccount(address).getMutable(); + final MutableAccount account = privateWorldStateUpdater.createAccount(address); LOG.debug("{} applied to genesis", address.toHexString()); @@ -90,14 +89,14 @@ public void applyGenesisToPrivateWorldState( if (isFlexiblePrivacyEnabled) { // inject management final MutableAccount managementContract = - privateWorldStateUpdater.createAccount(DEFAULT_FLEXIBLE_PRIVACY_MANAGEMENT).getMutable(); + privateWorldStateUpdater.createAccount(DEFAULT_FLEXIBLE_PRIVACY_MANAGEMENT); // this is the code for the simple management contract managementContract.setCode(FlexibleGroupManagement.DEFAULT_GROUP_MANAGEMENT_RUNTIME_BYTECODE); // inject proxy final MutableAccount procyContract = - privateWorldStateUpdater.createAccount(FLEXIBLE_PRIVACY_PROXY).getMutable(); + privateWorldStateUpdater.createAccount(FLEXIBLE_PRIVACY_PROXY); // this is the code for the proxy contract procyContract.setCode(FlexibleGroupManagement.PROXY_RUNTIME_BYTECODE); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java index 2eeb29cf32b..c953ed93d1d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java @@ -26,7 +26,6 @@ import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.worldstate.DefaultMutablePrivateWorldStateUpdater; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.code.CodeV0; import org.hyperledger.besu.evm.frame.MessageFrame; @@ -90,11 +89,11 @@ public TransactionProcessingResult processTransaction( LOG.trace("Starting private execution of {}", transaction); final Address senderAddress = transaction.getSender(); - final EvmAccount maybePrivateSender = privateWorldState.getAccount(senderAddress); + final MutableAccount maybePrivateSender = privateWorldState.getAccount(senderAddress); final MutableAccount sender = maybePrivateSender != null - ? maybePrivateSender.getMutable() - : privateWorldState.createAccount(senderAddress, 0, Wei.ZERO).getMutable(); + ? maybePrivateSender + : privateWorldState.createAccount(senderAddress, 0, Wei.ZERO); final ValidationResult validationResult = privateTransactionValidator.validate(transaction, sender.getNonce(), false); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateMigrationBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateMigrationBlockProcessor.java index 73ebea34384..0310700e1f5 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateMigrationBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateMigrationBlockProcessor.java @@ -141,7 +141,7 @@ private boolean rewardCoinbase( final Wei coinbaseReward = blockReward.add(blockReward.multiply(ommers.size()).divide(32)); final WorldUpdater updater = worldState.updater(); - final MutableAccount coinbase = updater.getOrCreate(header.getCoinbase()).getMutable(); + final MutableAccount coinbase = updater.getOrCreate(header.getCoinbase()); coinbase.incrementBalance(coinbaseReward); for (final BlockHeader ommerHeader : ommers) { @@ -155,8 +155,7 @@ private boolean rewardCoinbase( return false; } - final MutableAccount ommerCoinbase = - updater.getOrCreate(ommerHeader.getCoinbase()).getMutable(); + final MutableAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase()); final long distance = header.getNumber() - ommerHeader.getNumber(); final Wei ommerReward = blockReward.subtract(blockReward.multiply(distance).divide(8)); ommerCoinbase.incrementBalance(ommerReward); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java index 07a10e218ab..b1ef1bc0b1c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java @@ -199,11 +199,8 @@ private Optional> captureStorage(final MessageFrame frame) try { final Map storageContents = new TreeMap<>( - frame - .getWorldUpdater() - .getAccount(frame.getRecipientAddress()) - .getMutable() - .getUpdatedStorage()); + frame.getWorldUpdater().getAccount(frame.getRecipientAddress()).getUpdatedStorage()); + return Optional.of(storageContents); } catch (final ModificationNotAllowedException e) { return Optional.of(new TreeMap<>()); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutablePrivateWorldStateUpdater.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutablePrivateWorldStateUpdater.java index fe1bf39ecbd..e52319463cc 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutablePrivateWorldStateUpdater.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutablePrivateWorldStateUpdater.java @@ -17,9 +17,8 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; import java.util.Collection; import java.util.Optional; @@ -39,24 +38,24 @@ public DefaultMutablePrivateWorldStateUpdater( } @Override - public EvmAccount createAccount(final Address address, final long nonce, final Wei balance) { + public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) { return privateWorldUpdater.createAccount(address, nonce, balance); } @Override - public EvmAccount createAccount(final Address address) { + public MutableAccount createAccount(final Address address) { return privateWorldUpdater.createAccount(address); } @Override - public EvmAccount getAccount(final Address address) { - final EvmAccount privateAccount = privateWorldUpdater.getAccount(address); + public MutableAccount getAccount(final Address address) { + final MutableAccount privateAccount = privateWorldUpdater.getAccount(address); if (privateAccount != null && !privateAccount.isEmpty()) { return privateAccount; } - final EvmAccount publicAccount = publicWorldUpdater.getAccount(address); + final MutableAccount publicAccount = publicWorldUpdater.getAccount(address); if (publicAccount != null && !publicAccount.isEmpty()) { - ((WrappedEvmAccount) publicAccount).setImmutable(true); // FIXME + publicAccount.becomeImmutable(); return publicAccount; } return privateAccount; diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java index e02406927fc..3b2b8e30958 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.ethereum.core; import static com.google.common.base.Preconditions.checkArgument; -import static java.util.stream.Collectors.toUnmodifiableList; import static java.util.stream.Collectors.toUnmodifiableSet; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive; @@ -58,7 +57,6 @@ import java.util.Random; import java.util.Set; import java.util.function.Supplier; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; @@ -141,7 +139,7 @@ private List blockSequence( // Mutate accounts accountsToSetup.forEach( hash -> { - final MutableAccount a = stateUpdater.getAccount(hash).getMutable(); + final MutableAccount a = stateUpdater.getAccount(hash); a.incrementNonce(); a.setBalance(Wei.of(positiveLong())); storageKeys.forEach(key -> a.setStorageValue(key, UInt256.ONE)); @@ -181,7 +179,7 @@ private List createRandomAccounts( final WorldUpdater updater = worldState.updater(); final List accounts = new ArrayList<>(count); for (int i = 0; i < count; i++) { - final MutableAccount account = updater.getOrCreate(address()).getMutable(); + final MutableAccount account = updater.getOrCreate(address()); if (random.nextFloat() < percentContractAccounts) { // Some percentage of accounts are contract accounts account.setCode(bytesValue(5, 50)); @@ -373,21 +371,13 @@ public Transaction transaction(final TransactionType transactionType, final Byte public Transaction transaction( final TransactionType transactionType, final Bytes payload, final Address to) { - switch (transactionType) { - case FRONTIER: - return frontierTransaction(payload, to); - case EIP1559: - return eip1559Transaction(payload, to); - case ACCESS_LIST: - return accessListTransaction(payload, to); - case BLOB: - return blobTransaction(payload, to); - default: - throw new RuntimeException( - String.format( - "Developer Error. No random transaction generator defined for %s", - transactionType)); - } + return switch (transactionType) { + case FRONTIER -> frontierTransaction(payload, to); + case EIP1559 -> eip1559Transaction(payload, to); + case ACCESS_LIST -> accessListTransaction(payload, to); + case BLOB -> blobTransaction(payload, to); + // no default, all types accounted for. + }; } private Transaction accessListTransaction(final Bytes payload, final Address to) { @@ -406,13 +396,12 @@ private Transaction accessListTransaction(final Bytes payload, final Address to) private List accessList() { final List
accessedAddresses = - Stream.generate(this::address).limit(1L + random.nextInt(3)).collect(toUnmodifiableList()); + Stream.generate(this::address).limit(1L + random.nextInt(3)).toList(); final List accessedStorage = new ArrayList<>(); for (int i = 0; i < accessedAddresses.size(); ++i) { accessedStorage.add( new AccessListEntry( - accessedAddresses.get(i), - Stream.generate(this::bytes32).limit(2L * i).collect(toUnmodifiableList()))); + accessedAddresses.get(i), Stream.generate(this::bytes32).limit(2L * i).toList())); } return accessedStorage; } @@ -469,10 +458,7 @@ public Set transactions(final int n, final TransactionType... trans public Set transactions(final int n) { return transactions( - n, - new TransactionType[] { - TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559 - }); + n, TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559); } public Set transactionsWithAllTypes() { @@ -483,10 +469,7 @@ public Set transactionsWithAllTypes(final int atLeast) { checkArgument(atLeast >= 0); final HashSet remainingTransactionTypes = new HashSet<>( - Set.of( - new TransactionType[] { - TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559 - })); + Set.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559)); final HashSet transactions = new HashSet<>(); while (transactions.size() < atLeast || !remainingTransactionTypes.isEmpty()) { final Transaction newTransaction = transaction(); @@ -540,7 +523,7 @@ public List receipts(final Block block) { } public List logs(final int logsCount, final int topicsPerLog) { - return Stream.generate(() -> log(topicsPerLog)).limit(logsCount).collect(Collectors.toList()); + return Stream.generate(() -> log(topicsPerLog)).limit(logsCount).toList(); } public Log log() { @@ -548,8 +531,7 @@ public Log log() { } public Log log(final int topicCount) { - final List topics = - Stream.generate(this::logTopic).limit(topicCount).collect(Collectors.toList()); + final List topics = Stream.generate(this::logTopic).limit(topicCount).toList(); return new Log(address(), bytesValue(5, 15), topics); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java index b26120e69fb..0e2fb0c0d1a 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java @@ -53,7 +53,7 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class LogRollingTests { +class LogRollingTests { private BonsaiWorldStateProvider archive; @@ -126,7 +126,7 @@ public class LogRollingTests { new MainnetBlockHeaderFunctions()); @BeforeEach - public void createStorage() { + void createStorage() { provider = new InMemoryKeyValueStorageProvider(); final CachedMerkleTrieLoader cachedMerkleTrieLoader = new CachedMerkleTrieLoader(new NoOpMetricsSystem()); @@ -167,15 +167,14 @@ public void createStorage() { } @Test - public void simpleRollForwardTest() { + void simpleRollForwardTest() { final BonsaiWorldState worldState = new BonsaiWorldState( archive, new BonsaiWorldStateKeyValueStorage(provider, new NoOpMetricsSystem())); final WorldUpdater updater = worldState.updater(); - final MutableAccount mutableAccount = - updater.createAccount(addressOne, 1, Wei.of(1L)).getMutable(); + final MutableAccount mutableAccount = updater.createAccount(addressOne, 1, Wei.of(1L)); mutableAccount.setCode(Bytes.of(0, 1, 2)); mutableAccount.setStorageValue(UInt256.ONE, UInt256.ONE); updater.commit(); @@ -210,14 +209,13 @@ public void simpleRollForwardTest() { } @Test - public void rollForwardTwice() { + void rollForwardTwice() { final BonsaiWorldState worldState = new BonsaiWorldState( archive, new BonsaiWorldStateKeyValueStorage(provider, new NoOpMetricsSystem())); final WorldUpdater updater = worldState.updater(); - final MutableAccount mutableAccount = - updater.createAccount(addressOne, 1, Wei.of(1L)).getMutable(); + final MutableAccount mutableAccount = updater.createAccount(addressOne, 1, Wei.of(1L)); mutableAccount.setCode(Bytes.of(0, 1, 2)); mutableAccount.setStorageValue(UInt256.ONE, UInt256.ONE); updater.commit(); @@ -225,7 +223,7 @@ public void rollForwardTwice() { worldState.persist(headerOne); final WorldUpdater updater2 = worldState.updater(); - final MutableAccount mutableAccount2 = updater2.getAccount(addressOne).getMutable(); + final MutableAccount mutableAccount2 = updater2.getAccount(addressOne); mutableAccount2.setStorageValue(UInt256.ONE, UInt256.valueOf(2)); updater2.commit(); @@ -261,14 +259,13 @@ public void rollForwardTwice() { } @Test - public void rollBackOnce() { + void rollBackOnce() { final BonsaiWorldState worldState = new BonsaiWorldState( archive, new BonsaiWorldStateKeyValueStorage(provider, new NoOpMetricsSystem())); final WorldUpdater updater = worldState.updater(); - final MutableAccount mutableAccount = - updater.createAccount(addressOne, 1, Wei.of(1L)).getMutable(); + final MutableAccount mutableAccount = updater.createAccount(addressOne, 1, Wei.of(1L)); mutableAccount.setCode(Bytes.of(0, 1, 2)); mutableAccount.setStorageValue(UInt256.ONE, UInt256.ONE); updater.commit(); @@ -276,7 +273,7 @@ public void rollBackOnce() { worldState.persist(headerOne); final WorldUpdater updater2 = worldState.updater(); - final MutableAccount mutableAccount2 = updater2.getAccount(addressOne).getMutable(); + final MutableAccount mutableAccount2 = updater2.getAccount(addressOne); mutableAccount2.setStorageValue(UInt256.ONE, UInt256.valueOf(2)); updater2.commit(); @@ -296,7 +293,7 @@ public void rollBackOnce() { final WorldUpdater secondUpdater = secondWorldState.updater(); final MutableAccount secondMutableAccount = - secondUpdater.createAccount(addressOne, 1, Wei.of(1L)).getMutable(); + secondUpdater.createAccount(addressOne, 1, Wei.of(1L)); secondMutableAccount.setCode(Bytes.of(0, 1, 2)); secondMutableAccount.setStorageValue(UInt256.ONE, UInt256.ONE); secondUpdater.commit(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java index 2fe864a5c90..4bc2c6944e2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java @@ -29,7 +29,6 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.vm.BlockHashLookup; -import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; @@ -49,7 +48,7 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class MainnetTransactionProcessorTest { +class MainnetTransactionProcessorTest { private static final int MAX_STACK_SIZE = 1024; @@ -67,8 +66,7 @@ public class MainnetTransactionProcessorTest { @Mock private Transaction transaction; @Mock private BlockHashLookup blockHashLookup; - @Mock private EvmAccount senderAccount; - @Mock private MutableAccount mutableSenderAccount; + @Mock private MutableAccount senderAccount; MainnetTransactionProcessor createTransactionProcessor(final boolean warmCoinbase) { return new MainnetTransactionProcessor( @@ -84,14 +82,13 @@ MainnetTransactionProcessor createTransactionProcessor(final boolean warmCoinbas } @Test - public void shouldWarmCoinbaseIfRequested() { + void shouldWarmCoinbaseIfRequested() { Optional
toAddresss = Optional.of(Address.fromHexString("0x2222222222222222222222222222222222222222")); when(transaction.getTo()).thenReturn(toAddresss); Address senderAddress = Address.fromHexString("0x5555555555555555555555555555555555555555"); Address coinbaseAddress = Address.fromHexString("0x4242424242424242424242424242424242424242"); - when(senderAccount.getMutable()).thenReturn(mutableSenderAccount); when(transaction.getHash()).thenReturn(Hash.EMPTY); when(transaction.getPayload()).thenReturn(Bytes.EMPTY); when(transaction.getSender()).thenReturn(senderAddress); @@ -145,7 +142,7 @@ public void shouldWarmCoinbaseIfRequested() { } @Test - public void shouldCallTransactionValidatorWithExpectedTransactionValidationParams() { + void shouldCallTransactionValidatorWithExpectedTransactionValidationParams() { final ArgumentCaptor txValidationParamCaptor = transactionValidationParamCaptor(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java index 8835854ee05..4711e456cf0 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java @@ -45,7 +45,6 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.util.Collections; @@ -59,7 +58,7 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class PrivacyBlockProcessorTest { +class PrivacyBlockProcessorTest { private PrivacyBlockProcessor privacyBlockProcessor; private PrivateStateStorage privateStateStorage; @@ -91,7 +90,7 @@ public void setUp() { } @Test - public void mustCopyPreviousPrivacyGroupBlockHeadMap() { + void mustCopyPreviousPrivacyGroupBlockHeadMap() { final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); final Blockchain blockchain = mock(Blockchain.class); final MutableWorldState mutableWorldState = mock(MutableWorldState.class); @@ -132,7 +131,7 @@ public void mustCopyPreviousPrivacyGroupBlockHeadMap() { } @Test - public void mustPerformRehydration() { + void mustPerformRehydration() { final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); final Blockchain blockchain = mock(Blockchain.class); final MutableWorldState mutableWorldState = mock(MutableWorldState.class); @@ -191,9 +190,7 @@ public void mustPerformRehydration() { private MutableWorldState mockPrivateStateArchive() { final MutableWorldState mockPrivateState = mock(MutableWorldState.class); final WorldUpdater mockWorldUpdater = mock(WorldUpdater.class); - final WrappedEvmAccount mockWrappedEvmAccount = mock(WrappedEvmAccount.class); - final MutableAccount mockMutableAccount = mock(MutableAccount.class); - when(mockWrappedEvmAccount.getMutable()).thenReturn(mockMutableAccount); + final MutableAccount mockWrappedEvmAccount = mock(MutableAccount.class); when(mockWorldUpdater.createAccount(any())).thenReturn(mockWrappedEvmAccount); when(mockPrivateState.updater()).thenReturn(mockWorldUpdater); when(mockPrivateState.rootHash()).thenReturn(Hash.ZERO); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java index 48fe26af187..146213722b5 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java @@ -33,7 +33,6 @@ import org.hyperledger.besu.evm.operation.Operation; import org.hyperledger.besu.evm.operation.Operation.OperationResult; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; import java.util.Map; import java.util.TreeMap; @@ -47,7 +46,7 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class DebugOperationTracerTest { +class DebugOperationTracerTest { private static final int DEPTH = 4; private static final long INITIAL_GAS = 1000L; @@ -65,7 +64,7 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { }; @Test - public void shouldRecordProgramCounter() { + void shouldRecordProgramCounter() { final MessageFrame frame = validMessageFrame(); frame.setPC(10); final TraceFrame traceFrame = traceFrame(frame); @@ -74,14 +73,14 @@ public void shouldRecordProgramCounter() { } @Test - public void shouldRecordOpcode() { + void shouldRecordOpcode() { final MessageFrame frame = validMessageFrame(); final TraceFrame traceFrame = traceFrame(frame); assertThat(traceFrame.getOpcode()).isEqualTo("MUL"); } @Test - public void shouldRecordDepth() { + void shouldRecordDepth() { final MessageFrame frame = validMessageFrame(); // simulate 4 calls frame.getMessageFrameStack().add(frame); @@ -93,7 +92,7 @@ public void shouldRecordDepth() { } @Test - public void shouldRecordRemainingGas() { + void shouldRecordRemainingGas() { final MessageFrame frame = validMessageFrame(); // final Gas currentGasCost = Gas.of(50); final TraceFrame traceFrame = traceFrame(frame); @@ -101,7 +100,7 @@ public void shouldRecordRemainingGas() { } @Test - public void shouldRecordStackWhenEnabled() { + void shouldRecordStackWhenEnabled() { final MessageFrame frame = validMessageFrame(); final UInt256 stackItem1 = UInt256.fromHexString("0x01"); final UInt256 stackItem2 = UInt256.fromHexString("0x02"); @@ -115,14 +114,14 @@ public void shouldRecordStackWhenEnabled() { } @Test - public void shouldNotRecordStackWhenDisabled() { + void shouldNotRecordStackWhenDisabled() { final TraceFrame traceFrame = traceFrame(validMessageFrame(), new TraceOptions(false, false, false)); assertThat(traceFrame.getStack()).isEmpty(); } @Test - public void shouldRecordMemoryWhenEnabled() { + void shouldRecordMemoryWhenEnabled() { final MessageFrame frame = validMessageFrame(); final Bytes32 word1 = Bytes32.fromHexString("0x01"); final Bytes32 word2 = Bytes32.fromHexString("0x02"); @@ -136,14 +135,14 @@ public void shouldRecordMemoryWhenEnabled() { } @Test - public void shouldNotRecordMemoryWhenDisabled() { + void shouldNotRecordMemoryWhenDisabled() { final TraceFrame traceFrame = traceFrame(validMessageFrame(), new TraceOptions(false, false, false)); assertThat(traceFrame.getMemory()).isEmpty(); } @Test - public void shouldRecordStorageWhenEnabled() { + void shouldRecordStorageWhenEnabled() { final MessageFrame frame = validMessageFrame(); final Map updatedStorage = setupStorageForCapture(frame); final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(true, false, false)); @@ -152,14 +151,14 @@ public void shouldRecordStorageWhenEnabled() { } @Test - public void shouldNotRecordStorageWhenDisabled() { + void shouldNotRecordStorageWhenDisabled() { final TraceFrame traceFrame = traceFrame(validMessageFrame(), new TraceOptions(false, false, false)); assertThat(traceFrame.getStorage()).isEmpty(); } @Test - public void shouldCaptureFrameWhenExceptionalHaltOccurs() { + void shouldCaptureFrameWhenExceptionalHaltOccurs() { final MessageFrame frame = validMessageFrame(); final Map updatedStorage = setupStorageForCapture(frame); @@ -210,15 +209,13 @@ private MessageFrameTestFixture validMessageFrameBuilder() { } private Map setupStorageForCapture(final MessageFrame frame) { - final WrappedEvmAccount account = mock(WrappedEvmAccount.class); - final MutableAccount mutableAccount = mock(MutableAccount.class); - when(account.getMutable()).thenReturn(mutableAccount); + final MutableAccount account = mock(MutableAccount.class); when(worldUpdater.getAccount(frame.getRecipientAddress())).thenReturn(account); final Map updatedStorage = new TreeMap<>(); updatedStorage.put(UInt256.ZERO, UInt256.valueOf(233)); updatedStorage.put(UInt256.ONE, UInt256.valueOf(2424)); - when(mutableAccount.getUpdatedStorage()).thenReturn(updatedStorage); + when(account.getUpdatedStorage()).thenReturn(updatedStorage); final Bytes32 word1 = Bytes32.fromHexString("0x01"); final Bytes32 word2 = Bytes32.fromHexString("0x02"); final Bytes32 word3 = Bytes32.fromHexString("0x03"); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldStateTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldStateTest.java index 7f910364511..bc632e0f62a 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldStateTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldStateTest.java @@ -46,7 +46,7 @@ // TODO: make that an abstract mutable world state test, and create sub-class for all world state // implementations. -public class DefaultMutableWorldStateTest { +class DefaultMutableWorldStateTest { // The following test cases are loosely derived from the testTransactionToItself // GeneralStateReferenceTest. @@ -64,7 +64,7 @@ private static MutableWorldState createEmpty() { } @Test - public void rootHash_Empty() { + void rootHash_Empty() { final MutableWorldState worldState = createEmpty(); assertThat(worldState.rootHash()).isEqualTo(MerkleTrie.EMPTY_TRIE_NODE_HASH); @@ -73,16 +73,16 @@ public void rootHash_Empty() { } @Test - public void containsAccount_AccountDoesNotExist() { + void containsAccount_AccountDoesNotExist() { final WorldState worldState = createEmpty(); assertThat(worldState.get(ADDRESS)).isNull(); } @Test - public void containsAccount_AccountExists() { + void containsAccount_AccountExists() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - updater.createAccount(ADDRESS).getMutable().setBalance(Wei.of(100000)); + updater.createAccount(ADDRESS).setBalance(Wei.of(100000)); updater.commit(); assertThat(worldState.get(ADDRESS)).isNotNull(); assertThat(worldState.rootHash()) @@ -92,7 +92,7 @@ public void containsAccount_AccountExists() { } @Test - public void removeAccount_AccountDoesNotExist() { + void removeAccount_AccountDoesNotExist() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); updater.deleteAccount(ADDRESS); @@ -104,10 +104,10 @@ public void removeAccount_AccountDoesNotExist() { } @Test - public void removeAccount_UpdatedAccount() { + void removeAccount_UpdatedAccount() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - updater.createAccount(ADDRESS).getMutable().setBalance(Wei.of(100000)); + updater.createAccount(ADDRESS).setBalance(Wei.of(100000)); updater.deleteAccount(ADDRESS); updater.commit(); assertThat(worldState.rootHash()).isEqualTo(MerkleTrie.EMPTY_TRIE_NODE_HASH); @@ -117,11 +117,11 @@ public void removeAccount_UpdatedAccount() { } @Test - public void removeAccount_AccountExists() { + void removeAccount_AccountExists() { // Create a world state with one account final MutableWorldState worldState = createEmpty(); WorldUpdater updater = worldState.updater(); - updater.createAccount(ADDRESS).getMutable().setBalance(Wei.of(100000)); + updater.createAccount(ADDRESS).setBalance(Wei.of(100000)); updater.commit(); assertThat(worldState.get(ADDRESS)).isNotNull(); assertThat(worldState.rootHash()).isNotEqualTo(MerkleTrie.EMPTY_TRIE_NODE_HASH); @@ -138,11 +138,11 @@ public void removeAccount_AccountExists() { } @Test - public void removeAccount_AccountExistsAndIsPersisted() { + void removeAccount_AccountExistsAndIsPersisted() { // Create a world state with one account final MutableWorldState worldState = createEmpty(); WorldUpdater updater = worldState.updater(); - updater.createAccount(ADDRESS).getMutable().setBalance(Wei.of(100000)); + updater.createAccount(ADDRESS).setBalance(Wei.of(100000)); updater.commit(); worldState.persist(null); assertThat(worldState.get(ADDRESS)).isNotNull(); @@ -164,35 +164,35 @@ public void removeAccount_AccountExistsAndIsPersisted() { } @Test - public void streamAccounts_empty() { + void streamAccounts_empty() { final MutableWorldState worldState = createEmpty(); final Stream accounts = worldState.streamAccounts(Bytes32.ZERO, 10); - assertThat(accounts.count()).isEqualTo(0L); + assertThat(accounts.count()).isZero(); } @Test - public void streamAccounts_singleAccount() { + void streamAccounts_singleAccount() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - updater.createAccount(ADDRESS).getMutable().setBalance(Wei.of(100000)); + updater.createAccount(ADDRESS).setBalance(Wei.of(100000)); updater.commit(); List accounts = worldState.streamAccounts(Bytes32.ZERO, 10).collect(Collectors.toList()); - assertThat(accounts.size()).isEqualTo(1L); + assertThat(accounts).hasSize(1); assertThat(accounts.get(0).getAddress()).hasValue(ADDRESS); assertThat(accounts.get(0).getBalance()).isEqualTo(Wei.of(100000)); // Check again after persisting worldState.persist(null); accounts = worldState.streamAccounts(Bytes32.ZERO, 10).collect(Collectors.toList()); - assertThat(accounts.size()).isEqualTo(1L); + assertThat(accounts).hasSize(1); assertThat(accounts.get(0).getAddress()).hasValue(ADDRESS); assertThat(accounts.get(0).getBalance()).isEqualTo(Wei.of(100000)); } @Test - public void streamAccounts_multipleAccounts() { + void streamAccounts_multipleAccounts() { final Address addr1 = Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); final Address addr2 = Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c"); @@ -200,10 +200,10 @@ public void streamAccounts_multipleAccounts() { final WorldUpdater updater = worldState.updater(); // Create an account - final MutableAccount accountA = updater.createAccount(addr1).getMutable(); + final MutableAccount accountA = updater.createAccount(addr1); accountA.setBalance(Wei.of(100000)); // Create another - final MutableAccount accountB = updater.createAccount(addr2).getMutable(); + final MutableAccount accountB = updater.createAccount(addr2); accountB.setNonce(1); // Commit changes updater.commit(); @@ -217,16 +217,14 @@ public void streamAccounts_multipleAccounts() { final Hash startHash = accountAIsFirst ? accountA.getAddressHash() : accountB.getAddressHash(); // Get first account - final List firstAccount = - worldState.streamAccounts(startHash, 1).collect(Collectors.toList()); - assertThat(firstAccount.size()).isEqualTo(1L); + final List firstAccount = worldState.streamAccounts(startHash, 1).toList(); + assertThat(firstAccount).hasSize(1); assertThat(firstAccount.get(0).getAddress()) .hasValue(accountAIsFirst ? accountA.getAddress() : accountB.getAddress()); // Get both accounts - final List allAccounts = - worldState.streamAccounts(Bytes32.ZERO, 2).collect(Collectors.toList()); - assertThat(allAccounts.size()).isEqualTo(2L); + final List allAccounts = worldState.streamAccounts(Bytes32.ZERO, 2).toList(); + assertThat(allAccounts).hasSize(2); assertThat(allAccounts.get(0).getAddress()) .hasValue(accountAIsFirst ? accountA.getAddress() : accountB.getAddress()); assertThat(allAccounts.get(1).getAddress()) @@ -235,14 +233,14 @@ public void streamAccounts_multipleAccounts() { // Get second account final Bytes32 startHashForSecondAccount = UInt256.fromBytes(startHash).add(1L); final List secondAccount = - worldState.streamAccounts(startHashForSecondAccount, 100).collect(Collectors.toList()); - assertThat(secondAccount.size()).isEqualTo(1L); + worldState.streamAccounts(startHashForSecondAccount, 100).toList(); + assertThat(secondAccount).hasSize(1); assertThat(secondAccount.get(0).getAddress()) .hasValue(accountAIsFirst ? accountB.getAddress() : accountA.getAddress()); } @Test - public void commitAndPersist() { + void commitAndPersist() { final KeyValueStorage storage = new InMemoryKeyValueStorage(); final WorldStateKeyValueStorage kvWorldStateStorage = new WorldStateKeyValueStorage(storage); final MutableWorldState worldState = createEmpty(kvWorldStateStorage); @@ -252,7 +250,7 @@ public void commitAndPersist() { Hash.fromHexString("0xa3e1c133a5a51b03399ed9ad0380f3182e9e18322f232b816dd4b9094f871e1b"); // Update account and assert we get the expected response from updater - updater.createAccount(ADDRESS).getMutable().setBalance(newBalance); + updater.createAccount(ADDRESS).setBalance(newBalance); assertThat(updater.get(ADDRESS)).isNotNull(); assertThat(updater.get(ADDRESS).getBalance()).isEqualTo(newBalance); @@ -285,10 +283,10 @@ public void commitAndPersist() { } @Test - public void getAccountNonce_AccountExists() { + void getAccountNonce_AccountExists() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - updater.createAccount(ADDRESS).getMutable().setNonce(1L); + updater.createAccount(ADDRESS).setNonce(1L); updater.commit(); assertThat(worldState.get(ADDRESS).getNonce()).isEqualTo(1L); assertThat(worldState.rootHash()) @@ -298,10 +296,10 @@ public void getAccountNonce_AccountExists() { } @Test - public void replaceAccountNonce() { + void replaceAccountNonce() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - final MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + final MutableAccount account = updater.createAccount(ADDRESS); account.setNonce(1L); account.setNonce(2L); updater.commit(); @@ -313,19 +311,19 @@ public void replaceAccountNonce() { } @Test - public void getAccountBalance_AccountExists() { + void getAccountBalance_AccountExists() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - updater.createAccount(ADDRESS).getMutable().setBalance(Wei.of(100000)); + updater.createAccount(ADDRESS).setBalance(Wei.of(100000)); updater.commit(); assertThat(worldState.get(ADDRESS).getBalance()).isEqualTo(Wei.of(100000)); } @Test - public void replaceAccountBalance() { + void replaceAccountBalance() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - final MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + final MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setBalance(Wei.of(200000)); updater.commit(); @@ -337,10 +335,10 @@ public void replaceAccountBalance() { } @Test - public void setStorageValue_ZeroValue() { + void setStorageValue_ZeroValue() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - final MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + final MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setStorageValue(UInt256.ZERO, UInt256.ZERO); updater.commit(); @@ -352,10 +350,10 @@ public void setStorageValue_ZeroValue() { } @Test - public void setStorageValue_NonzeroValue() { + void setStorageValue_NonzeroValue() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - final MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + final MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setStorageValue(UInt256.ONE, UInt256.valueOf(2)); updater.commit(); @@ -367,10 +365,10 @@ public void setStorageValue_NonzeroValue() { } @Test - public void replaceStorageValue_NonzeroValue() { + void replaceStorageValue_NonzeroValue() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - final MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + final MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setStorageValue(UInt256.ONE, UInt256.valueOf(2)); account.setStorageValue(UInt256.ONE, UInt256.valueOf(3)); @@ -383,10 +381,10 @@ public void replaceStorageValue_NonzeroValue() { } @Test - public void replaceStorageValue_ZeroValue() { + void replaceStorageValue_ZeroValue() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - final MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + final MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setStorageValue(UInt256.ONE, UInt256.valueOf(2)); account.setStorageValue(UInt256.ONE, UInt256.ZERO); @@ -398,15 +396,15 @@ public void replaceStorageValue_ZeroValue() { } @Test - public void getOriginalStorageValue() { + void getOriginalStorageValue() { final MutableWorldState worldState = createEmpty(); final WorldUpdater setupUpdater = worldState.updater(); - final MutableAccount setupAccount = setupUpdater.createAccount(ADDRESS).getMutable(); + final MutableAccount setupAccount = setupUpdater.createAccount(ADDRESS); setupAccount.setStorageValue(UInt256.ONE, UInt256.valueOf(2)); setupUpdater.commit(); final WorldUpdater updater = worldState.updater(); - final MutableAccount account = updater.getOrCreate(ADDRESS).getMutable(); + final MutableAccount account = updater.getOrCreate(ADDRESS); assertThat(account.getOriginalStorageValue(UInt256.ONE)).isEqualTo(UInt256.valueOf(2)); account.setStorageValue(UInt256.ONE, UInt256.valueOf(3)); @@ -414,35 +412,35 @@ public void getOriginalStorageValue() { } @Test - public void originalStorageValueIsAlwaysZeroIfStorageWasCleared() { + void originalStorageValueIsAlwaysZeroIfStorageWasCleared() { final MutableWorldState worldState = createEmpty(); final WorldUpdater setupUpdater = worldState.updater(); - final MutableAccount setupAccount = setupUpdater.createAccount(ADDRESS).getMutable(); + final MutableAccount setupAccount = setupUpdater.createAccount(ADDRESS); setupAccount.setStorageValue(UInt256.ONE, UInt256.valueOf(2)); setupUpdater.commit(); final WorldUpdater updater = worldState.updater(); - final MutableAccount account = updater.getOrCreate(ADDRESS).getMutable(); + final MutableAccount account = updater.getOrCreate(ADDRESS); account.clearStorage(); assertThat(account.getOriginalStorageValue(UInt256.ONE)).isEqualTo(UInt256.ZERO); } @Test - public void clearStorage() { + void clearStorage() { final UInt256 storageKey = UInt256.ONE; final UInt256 storageValue = UInt256.valueOf(2L); // Create a world state with one account final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setStorageValue(storageKey, storageValue); assertThat(account.getStorageValue(storageKey)).isEqualTo(storageValue); // Clear storage - account = updater.getAccount(ADDRESS).getMutable(); + account = updater.getAccount(ADDRESS); assertThat(account).isNotNull(); assertThat(account.getStorageValue(storageKey)).isEqualTo(storageValue); account.clearStorage(); @@ -462,14 +460,14 @@ public void clearStorage() { } @Test - public void clearStorage_AfterPersisting() { + void clearStorage_AfterPersisting() { final UInt256 storageKey = UInt256.ONE; final UInt256 storageValue = UInt256.valueOf(2L); // Create a world state with one account final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setStorageValue(storageKey, storageValue); updater.commit(); @@ -478,7 +476,7 @@ public void clearStorage_AfterPersisting() { assertThat(worldState.rootHash()).isNotEqualTo(MerkleTrie.EMPTY_TRIE_NODE_HASH); // Clear storage - account = updater.getAccount(ADDRESS).getMutable(); + account = updater.getAccount(ADDRESS); assertThat(account).isNotNull(); assertThat(account.getStorageValue(storageKey)).isEqualTo(storageValue); account.clearStorage(); @@ -499,7 +497,7 @@ public void clearStorage_AfterPersisting() { } @Test - public void clearStorageThenEdit() { + void clearStorageThenEdit() { final UInt256 storageKey = UInt256.ONE; final UInt256 originalStorageValue = UInt256.valueOf(2L); final UInt256 newStorageValue = UInt256.valueOf(3L); @@ -507,13 +505,13 @@ public void clearStorageThenEdit() { // Create a world state with one account final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setStorageValue(storageKey, originalStorageValue); assertThat(account.getStorageValue(storageKey)).isEqualTo(originalStorageValue); // Clear storage then edit - account = updater.getAccount(ADDRESS).getMutable(); + account = updater.getAccount(ADDRESS); assertThat(account).isNotNull(); assertThat(account.getStorageValue(storageKey)).isEqualTo(originalStorageValue); assertThat(updater.get(ADDRESS).getStorageValue(storageKey)).isEqualTo(originalStorageValue); @@ -534,7 +532,7 @@ public void clearStorageThenEdit() { } @Test - public void clearStorageThenEditAfterPersisting() { + void clearStorageThenEditAfterPersisting() { final UInt256 storageKey = UInt256.ONE; final UInt256 originalStorageValue = UInt256.valueOf(2L); final UInt256 newStorageValue = UInt256.valueOf(3L); @@ -542,7 +540,7 @@ public void clearStorageThenEditAfterPersisting() { // Create a world state with one account final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setStorageValue(storageKey, originalStorageValue); assertThat(account.getStorageValue(storageKey)).isEqualTo(originalStorageValue); @@ -550,7 +548,7 @@ public void clearStorageThenEditAfterPersisting() { worldState.persist(null); // Clear storage then edit - account = updater.getAccount(ADDRESS).getMutable(); + account = updater.getAccount(ADDRESS); assertThat(account).isNotNull(); assertThat(account.getStorageValue(storageKey)).isEqualTo(originalStorageValue); assertThat(updater.get(ADDRESS).getStorageValue(storageKey)).isEqualTo(originalStorageValue); @@ -572,10 +570,10 @@ public void clearStorageThenEditAfterPersisting() { } @Test - public void replaceAccountCode() { + void replaceAccountCode() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater = worldState.updater(); - final MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + final MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setCode(Bytes.of(1, 2, 3)); account.setCode(Bytes.of(3, 2, 1)); @@ -588,15 +586,15 @@ public void replaceAccountCode() { } @Test - public void revert() { + void revert() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater1 = worldState.updater(); - final MutableAccount account1 = updater1.createAccount(ADDRESS).getMutable(); + final MutableAccount account1 = updater1.createAccount(ADDRESS); account1.setBalance(Wei.of(200000)); updater1.commit(); final WorldUpdater updater2 = worldState.updater(); - final MutableAccount account2 = updater2.getAccount(ADDRESS).getMutable(); + final MutableAccount account2 = updater2.getAccount(ADDRESS); account2.setBalance(Wei.of(300000)); assertThat(updater2.get(ADDRESS).getBalance()).isEqualTo(Wei.of(300000)); @@ -613,27 +611,27 @@ public void revert() { } @Test - public void shouldReturnNullForGetMutableWhenAccountDeletedInAncestor() { + void shouldReturnNullForGetMutableWhenAccountDeletedInAncestor() { final MutableWorldState worldState = createEmpty(); final WorldUpdater updater1 = worldState.updater(); - final MutableAccount account1 = updater1.createAccount(ADDRESS).getMutable(); + final MutableAccount account1 = updater1.createAccount(ADDRESS); updater1.commit(); assertThat(updater1.get(ADDRESS)) .isEqualToComparingOnlyGivenFields(account1, "address", "nonce", "balance", "codeHash"); updater1.deleteAccount(ADDRESS); final WorldUpdater updater2 = updater1.updater(); - assertThat(updater2.get(ADDRESS)).isEqualTo(null); + assertThat(updater2.get(ADDRESS)).isNull(); final WorldUpdater updater3 = updater2.updater(); - assertThat(updater3.getAccount(ADDRESS)).isEqualTo(null); + assertThat(updater3.getAccount(ADDRESS)).isNull(); } @Test - public void shouldCombineUnchangedAndChangedValuesWhenRetrievingStorageEntries() { + void shouldCombineUnchangedAndChangedValuesWhenRetrievingStorageEntries() { final MutableWorldState worldState = createEmpty(); WorldUpdater updater = worldState.updater(); - MutableAccount account = updater.createAccount(ADDRESS).getMutable(); + MutableAccount account = updater.createAccount(ADDRESS); account.setBalance(Wei.of(100000)); account.setStorageValue(UInt256.ONE, UInt256.valueOf(2)); account.setStorageValue(UInt256.valueOf(2), UInt256.valueOf(5)); @@ -647,7 +645,7 @@ public void shouldCombineUnchangedAndChangedValuesWhenRetrievingStorageEntries() initialSetOfEntries.forEach(entry -> initialEntries.put(entry.getKeyHash(), entry)); updater = worldState.updater(); - account = updater.getAccount(ADDRESS).getMutable(); + account = updater.getAccount(ADDRESS); account.setStorageValue(UInt256.ONE, UInt256.valueOf(3)); account.setStorageValue(UInt256.valueOf(3), UInt256.valueOf(6)); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java index 63005b81140..9d2faeb7dc8 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java @@ -354,7 +354,6 @@ static T8nResult runTest( : Wei.of(Long.decode(rewardString)); worldStateUpdater .getOrCreateSenderAccount(blockHeader.getCoinbase()) - .getMutable() .incrementBalance(reward); } diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java index 9518d2c99d4..659847c1211 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java @@ -81,7 +81,7 @@ public Map getStorage() { static void insertAccount( final WorldUpdater updater, final Address address, final AccountMock toCopy) { - final MutableAccount account = updater.getOrCreate(address).getMutable(); + final MutableAccount account = updater.getOrCreate(address); account.setNonce(toCopy.getNonce()); account.setBalance(toCopy.getBalance()); account.setCode(toCopy.getCode()); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/account/EvmAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/account/EvmAccount.java deleted file mode 100644 index ecd3cf3ceaf..00000000000 --- a/evm/src/main/java/org/hyperledger/besu/evm/account/EvmAccount.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.evm.account; - -import org.hyperledger.besu.evm.ModificationNotAllowedException; - -/** The interface Evm account. */ -public interface EvmAccount extends Account { - /** - * Gets mutable account. - * - * @return the mutable account - * @throws ModificationNotAllowedException the modification not allowed exception - */ - public MutableAccount getMutable() throws ModificationNotAllowedException; -} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/account/MutableAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/account/MutableAccount.java index a4caf35c288..455df4a8b3f 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/account/MutableAccount.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/account/MutableAccount.java @@ -105,4 +105,9 @@ default Wei decrementBalance(final Wei value) { * @return a map of storage that has been modified. */ Map getUpdatedStorage(); + + /** + * Make this instance immutable. Used for private world state interactions with public contracts. + */ + void becomeImmutable(); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java index 75c86070950..b8a4db21eab 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java @@ -21,7 +21,6 @@ import org.hyperledger.besu.evm.ModificationNotAllowedException; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.AccountStorageEntry; -import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import java.util.HashMap; @@ -35,10 +34,12 @@ import org.apache.tuweni.units.bigints.UInt256; /** The Simple account. */ -public class SimpleAccount implements EvmAccount, MutableAccount { +public class SimpleAccount implements MutableAccount { private final Account parent; + private boolean mutable = true; + private Address address; private final Supplier addressHash = Suppliers.memoize(() -> address == null ? Hash.ZERO : address.addressHash()); @@ -137,34 +138,44 @@ public NavigableMap storageEntriesFrom( "Storage iteration not supported in simple account facade"); } - @Override - public MutableAccount getMutable() throws ModificationNotAllowedException { - return this; - } - @Override public void setNonce(final long value) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } nonce = value; } @Override public void setBalance(final Wei value) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } balance = value; } @Override public void setCode(final Bytes code) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } this.code = code; codeHash = Suppliers.memoize(() -> this.code == null ? Hash.EMPTY : Hash.hash(this.code)); } @Override public void setStorageValue(final UInt256 key, final UInt256 value) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } storage.put(key, value); } @Override public void clearStorage() { + if (!mutable) { + throw new ModificationNotAllowedException(); + } storage.clear(); } @@ -172,4 +183,9 @@ public void clearStorage() { public Map getUpdatedStorage() { return storage; } + + @Override + public void becomeImmutable() { + mutable = false; + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java index a7288602083..6bc19ca0dae 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java @@ -18,14 +18,13 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; /** The Simple world. */ public class SimpleWorld implements WorldUpdater { @@ -66,14 +65,14 @@ public Account get(final Address address) { } @Override - public EvmAccount createAccount(final Address address, final long nonce, final Wei balance) { + public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) { SimpleAccount account = new SimpleAccount(address, nonce, balance); accounts.put(address, account); return account; } @Override - public EvmAccount getAccount(final Address address) { + public MutableAccount getAccount(final Address address) { if (accounts.containsKey(address)) { return accounts.get(address); } else if (parent != null) { @@ -98,7 +97,7 @@ public Collection
getDeletedAccountAddresses() { return accounts.entrySet().stream() .filter(e -> e.getValue() == null) .map(Map.Entry::getKey) - .collect(Collectors.toList()); + .toList(); } @Override diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java index 50ced6fd8b7..d695edf1c8c 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java @@ -79,7 +79,7 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { final Wei value = Wei.wrap(frame.getStackItem(0)); final Address address = frame.getRecipientAddress(); - final MutableAccount account = frame.getWorldUpdater().getAccount(address).getMutable(); + final MutableAccount account = frame.getWorldUpdater().getAccount(address); frame.clearReturnData(); final long inputOffset = clampedToLong(frame.getStackItem(1)); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/SStoreOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/SStoreOperation.java index b4fa49751e4..d5055e0bd81 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/SStoreOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/SStoreOperation.java @@ -66,8 +66,7 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { final UInt256 key = UInt256.fromBytes(frame.popStackItem()); final UInt256 newValue = UInt256.fromBytes(frame.popStackItem()); - final MutableAccount account = - frame.getWorldUpdater().getAccount(frame.getRecipientAddress()).getMutable(); + final MutableAccount account = frame.getWorldUpdater().getAccount(frame.getRecipientAddress()); if (account == null) { return ILLEGAL_STATE_CHANGE; } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java index 98807652034..3f29fcea57e 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java @@ -75,10 +75,9 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { } // We passed preliminary checks, get mutable accounts. - final MutableAccount originatorAccount = - frame.getWorldUpdater().getAccount(originatorAddress).getMutable(); + final MutableAccount originatorAccount = frame.getWorldUpdater().getAccount(originatorAddress); final MutableAccount beneficiaryAccount = - frame.getWorldUpdater().getOrCreate(beneficiaryAddress).getMutable(); + frame.getWorldUpdater().getOrCreate(beneficiaryAddress); // Do the "sweep," all modes send all originator balance to the beneficiary account. originatorAccount.decrementBalance(originatorBalance); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java index 17fa4da60b8..7acea893724 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java @@ -108,12 +108,11 @@ public void start(final MessageFrame frame, final OperationTracer operationTrace } try { - final MutableAccount sender = frame.getWorldUpdater().getSenderAccount(frame).getMutable(); + final MutableAccount sender = frame.getWorldUpdater().getSenderAccount(frame); sender.decrementBalance(frame.getValue()); Address contractAddress = frame.getContractAddress(); - final MutableAccount contract = - frame.getWorldUpdater().getOrCreate(contractAddress).getMutable(); + final MutableAccount contract = frame.getWorldUpdater().getOrCreate(contractAddress); if (accountExists(contract)) { LOG.trace( "Contract creation error: account has already been created for address {}", @@ -169,7 +168,7 @@ public void codeSuccess(final MessageFrame frame, final OperationTracer operatio // Finalize contract creation, setting the contract code. final MutableAccount contract = - frame.getWorldUpdater().getOrCreate(frame.getContractAddress()).getMutable(); + frame.getWorldUpdater().getOrCreate(frame.getContractAddress()); contract.setCode(contractCode); LOG.trace( "Successful creation of contract {} with code of size {} (Gas remaining: {})", diff --git a/evm/src/main/java/org/hyperledger/besu/evm/processor/MessageCallProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/MessageCallProcessor.java index b1d41da97a1..0c100e33407 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/processor/MessageCallProcessor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/processor/MessageCallProcessor.java @@ -18,7 +18,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.ModificationNotAllowedException; -import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.precompile.PrecompileContractRegistry; @@ -28,8 +28,8 @@ import java.util.Collection; import java.util.Objects; import java.util.Optional; +import java.util.Set; -import com.google.common.collect.ImmutableSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,7 +61,7 @@ public MessageCallProcessor( * @param precompiles the precompiles */ public MessageCallProcessor(final EVM evm, final PrecompileContractRegistry precompiles) { - super(evm, ImmutableSet.of()); + super(evm, Set.of()); this.precompiles = precompiles; } @@ -102,11 +102,11 @@ protected void codeSuccess(final MessageFrame frame, final OperationTracer opera * of the world state of this executor. */ private void transferValue(final MessageFrame frame) { - final EvmAccount senderAccount = frame.getWorldUpdater().getSenderAccount(frame); + final MutableAccount senderAccount = frame.getWorldUpdater().getSenderAccount(frame); // The yellow paper explicitly states that if the recipient account doesn't exist at this // point, it is created. Even if the value is zero we are still creating an account with 0x! - final EvmAccount recipientAccount = + final MutableAccount recipientAccount = frame.getWorldUpdater().getOrCreate(frame.getRecipientAddress()); if (Objects.equals(frame.getValue(), Wei.ZERO)) { @@ -125,9 +125,8 @@ private void transferValue(final MessageFrame frame) { if (frame.getRecipientAddress().equals(frame.getSenderAddress())) { LOG.trace("Message call of {} to itself: no fund transferred", frame.getSenderAddress()); } else { - final Wei prevSenderBalance = senderAccount.getMutable().decrementBalance(frame.getValue()); - final Wei prevRecipientBalance = - recipientAccount.getMutable().incrementBalance(frame.getValue()); + final Wei prevSenderBalance = senderAccount.decrementBalance(frame.getValue()); + final Wei prevRecipientBalance = recipientAccount.incrementBalance(frame.getValue()); LOG.trace( "Transferred value {} for message call from {} ({} -> {}) to {} ({} -> {})", diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/AbstractWorldUpdater.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/AbstractWorldUpdater.java index fde3aa8c244..41cacdbea06 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/AbstractWorldUpdater.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/AbstractWorldUpdater.java @@ -17,7 +17,6 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import java.util.Collection; @@ -78,11 +77,11 @@ protected UpdateTrackingAccount track(final UpdateTrackingAccount account) } @Override - public EvmAccount createAccount(final Address address, final long nonce, final Wei balance) { + public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) { final UpdateTrackingAccount account = new UpdateTrackingAccount<>(address); account.setNonce(nonce); account.setBalance(balance); - return new WrappedEvmAccount(track(account)); + return track(account); } @Override @@ -99,11 +98,11 @@ public Account get(final Address address) { } @Override - public EvmAccount getAccount(final Address address) { + public MutableAccount getAccount(final Address address) { // We may have updated it already, so check that first. final MutableAccount existing = updatedAccounts.get(address); if (existing != null) { - return new WrappedEvmAccount(existing); + return existing; } if (deletedAccounts.contains(address)) { return null; @@ -114,7 +113,7 @@ public EvmAccount getAccount(final Address address) { if (origin == null) { return null; } else { - return new WrappedEvmAccount(track(new UpdateTrackingAccount<>(origin))); + return track(new UpdateTrackingAccount<>(origin)); } } @@ -150,8 +149,8 @@ protected W wrappedWorldView() { @Override public Optional parentUpdater() { - if (world instanceof WorldUpdater) { - return Optional.of((WorldUpdater) world); + if (world instanceof WorldUpdater worldUpdater) { + return Optional.of(worldUpdater); } else { return Optional.empty(); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/UpdateTrackingAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/UpdateTrackingAccount.java index 9b9f5e2a127..bc8a0fdfcd5 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/UpdateTrackingAccount.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/UpdateTrackingAccount.java @@ -24,7 +24,6 @@ import org.hyperledger.besu.evm.ModificationNotAllowedException; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.AccountStorageEntry; -import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import java.util.Map; @@ -47,12 +46,14 @@ * * @param the type parameter */ -public class UpdateTrackingAccount implements MutableAccount, EvmAccount { +public class UpdateTrackingAccount implements MutableAccount { private final Address address; private final Hash addressHash; @Nullable private A account; // null if this is a new account. + private boolean mutable = true; + private long nonce; private Wei balance; @@ -172,6 +173,9 @@ public long getNonce() { @Override public void setNonce(final long value) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } this.nonce = value; } @@ -182,6 +186,9 @@ public Wei getBalance() { @Override public void setBalance(final Wei value) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } this.balance = value; } @@ -214,6 +221,9 @@ public boolean hasCode() { @Override public void setCode(final Bytes code) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } this.updatedCode = code; this.updatedCodeHash = null; } @@ -271,15 +281,26 @@ public NavigableMap storageEntriesFrom( @Override public void setStorageValue(final UInt256 key, final UInt256 value) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } updatedStorage.put(key, value); } @Override public void clearStorage() { + if (!mutable) { + throw new ModificationNotAllowedException(); + } storageWasCleared = true; updatedStorage.clear(); } + @Override + public void becomeImmutable() { + mutable = false; + } + /** * Gets storage was cleared. * @@ -308,9 +329,4 @@ public String toString() { "%s -> {nonce: %s, balance:%s, code:%s, storage:%s }", address, nonce, balance, updatedCode == null ? "[not updated]" : updatedCode, storage); } - - @Override - public MutableAccount getMutable() throws ModificationNotAllowedException { - return this; - } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WorldUpdater.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WorldUpdater.java index a9b012facbf..fe88c86a7df 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WorldUpdater.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WorldUpdater.java @@ -17,7 +17,6 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.MessageFrame; @@ -48,7 +47,7 @@ public interface WorldUpdater extends MutableWorldView { * @return the account {@code address}, which will have nonce {@code nonce}, balance {@code * balance} and empty code and storage. */ - EvmAccount createAccount(Address address, long nonce, Wei balance); + MutableAccount createAccount(Address address, long nonce, Wei balance); /** * Creates a new account, or reset it (that is, act as if it was deleted and created anew) if it @@ -61,7 +60,7 @@ public interface WorldUpdater extends MutableWorldView { * @return the account {@code address}, which will have 0 for the nonce and balance and empty code * and storage. */ - default EvmAccount createAccount(final Address address) { + default MutableAccount createAccount(final Address address) { return createAccount(address, Account.DEFAULT_NONCE, Account.DEFAULT_BALANCE); } @@ -73,8 +72,8 @@ default EvmAccount createAccount(final Address address) { * #getAccount(Address)}, otherwise, it is created and returned as if by {@link * #createAccount(Address)} (and thus all his fields will be zero/empty). */ - default EvmAccount getOrCreate(final Address address) { - final EvmAccount account = getAccount(address); + default MutableAccount getOrCreate(final Address address) { + final MutableAccount account = getAccount(address); return account == null ? createAccount(address) : account; } @@ -85,7 +84,7 @@ default EvmAccount getOrCreate(final Address address) { * @param address the address of the account. * @return the account of the sender for {@code address} */ - default EvmAccount getOrCreateSenderAccount(final Address address) { + default MutableAccount getOrCreateSenderAccount(final Address address) { return getOrCreate(address); } @@ -96,7 +95,7 @@ default EvmAccount getOrCreateSenderAccount(final Address address) { * @param address the address of the account. * @return the account {@code address}, or {@code null} if the account does not exist. */ - EvmAccount getAccount(Address address); + MutableAccount getAccount(Address address); /** * Retrieves the senders account, returning a modifiable object (whose updates are accumulated by @@ -105,7 +104,7 @@ default EvmAccount getOrCreateSenderAccount(final Address address) { * @param frame the current message frame. * @return the account {@code address}, or {@code null} if the account does not exist. */ - default EvmAccount getSenderAccount(final MessageFrame frame) { + default MutableAccount getSenderAccount(final MessageFrame frame) { return getAccount(frame.getSenderAddress()); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WrappedEvmAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WrappedEvmAccount.java deleted file mode 100644 index 8d644d9650d..00000000000 --- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WrappedEvmAccount.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.evm.worldstate; - -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.evm.ModificationNotAllowedException; -import org.hyperledger.besu.evm.account.AccountStorageEntry; -import org.hyperledger.besu.evm.account.EvmAccount; -import org.hyperledger.besu.evm.account.MutableAccount; - -import java.util.NavigableMap; - -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt256; - -/** The Wrapped evm account. */ -public class WrappedEvmAccount implements EvmAccount { - private final MutableAccount mutableAccount; - - /** - * Is immutable. - * - * @return the boolean - */ - public boolean isImmutable() { - return isImmutable; - } - - /** - * Sets immutable. - * - * @param immutable the immutable - */ - public void setImmutable(final boolean immutable) { - isImmutable = immutable; - } - - private boolean isImmutable; - - /** - * Instantiates a new Wrapped evm account. - * - * @param mutableAccount the mutable account - */ - public WrappedEvmAccount(final MutableAccount mutableAccount) { - - this.mutableAccount = mutableAccount; - this.isImmutable = false; - } - - @Override - public MutableAccount getMutable() throws ModificationNotAllowedException { - if (isImmutable) { - throw new ModificationNotAllowedException(); - } - return mutableAccount; - } - - @Override - public Address getAddress() { - return mutableAccount.getAddress(); - } - - @Override - public Hash getAddressHash() { - return mutableAccount.getAddressHash(); - } - - @Override - public long getNonce() { - return mutableAccount.getNonce(); - } - - @Override - public Wei getBalance() { - return mutableAccount.getBalance(); - } - - @Override - public Bytes getCode() { - return mutableAccount.getCode(); - } - - @Override - public Hash getCodeHash() { - return mutableAccount.getCodeHash(); - } - - @Override - public UInt256 getStorageValue(final UInt256 key) { - return mutableAccount.getStorageValue(key); - } - - @Override - public UInt256 getOriginalStorageValue(final UInt256 key) { - return mutableAccount.getOriginalStorageValue(key); - } - - @Override - public NavigableMap storageEntriesFrom( - final Bytes32 startKeyHash, final int limit) { - return mutableAccount.storageEntriesFrom(startKeyHash, limit); - } -} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java index aa3dfd40217..1a703f489d7 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java @@ -39,7 +39,6 @@ import org.hyperledger.besu.evm.processor.ContractCreationProcessor; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; import java.util.Deque; import java.util.List; @@ -52,10 +51,8 @@ class AbstractCreateOperationTest { private final WorldUpdater worldUpdater = mock(WorldUpdater.class); - private final WrappedEvmAccount account = mock(WrappedEvmAccount.class); - private final WrappedEvmAccount newAccount = mock(WrappedEvmAccount.class); - private final MutableAccount mutableAccount = mock(MutableAccount.class); - private final MutableAccount newMutableAccount = mock(MutableAccount.class); + private final MutableAccount account = mock(MutableAccount.class); + private final MutableAccount newAccount = mock(MutableAccount.class); private final FakeCreateOperation operation = new FakeCreateOperation(new ConstantinopleGasCalculator(), Integer.MAX_VALUE); @@ -169,15 +166,13 @@ private void executeOperation(final Bytes contract, final EVM evm) { messageFrame.expandMemory(0, 500); messageFrame.writeMemory(memoryOffset.trimLeadingZeros().toInt(), contract.size(), contract); - when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.get(any())).thenReturn(account); when(worldUpdater.getSenderAccount(any())).thenReturn(account); when(worldUpdater.getOrCreate(any())).thenReturn(newAccount); - when(newAccount.getMutable()).thenReturn(newMutableAccount); - when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY); + when(newAccount.getCode()).thenReturn(Bytes.EMPTY); when(worldUpdater.updater()).thenReturn(worldUpdater); operation.execute(messageFrame, evm); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java index 5590cd09b4f..d9b41d4681e 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java @@ -40,7 +40,6 @@ import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; import java.util.Deque; import java.util.List; @@ -56,11 +55,9 @@ public class Create2OperationTest { private MessageFrame messageFrame; private final WorldUpdater worldUpdater = mock(WorldUpdater.class); - private final WrappedEvmAccount account = mock(WrappedEvmAccount.class); - private final MutableAccount mutableAccount = mock(MutableAccount.class); + private final MutableAccount account = mock(MutableAccount.class); private final EVM evm = mock(EVM.class); - private final WrappedEvmAccount newAccount = mock(WrappedEvmAccount.class); - private final MutableAccount newMutableAccount = mock(MutableAccount.class); + private final MutableAccount newAccount = mock(MutableAccount.class); private final Create2Operation operation = new Create2Operation(new ConstantinopleGasCalculator(), Integer.MAX_VALUE); @@ -147,7 +144,6 @@ public void setUp(final String sender, final String salt, final String code) { final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final Bytes codeBytes = Bytes.fromHexString(code); final UInt256 memoryLength = UInt256.valueOf(codeBytes.size()); - when(account.getMutable()).thenReturn(mutableAccount); messageFrame = MessageFrame.builder() .type(MessageFrame.Type.CONTRACT_CREATION) @@ -174,7 +170,7 @@ public void setUp(final String sender, final String salt, final String code) { messageFrame.expandMemory(0, 500); messageFrame.writeMemory(memoryOffset.trimLeadingZeros().toInt(), code.length(), codeBytes); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.updater()).thenReturn(worldUpdater); when(evm.getCode(any(), any())) @@ -214,15 +210,13 @@ void shanghaiMaxInitCodeSizeCreate() { final UInt256 memoryLength = UInt256.fromHexString("0xc000"); final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); - when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.get(any())).thenReturn(account); when(worldUpdater.getSenderAccount(any())).thenReturn(account); when(worldUpdater.getOrCreate(any())).thenReturn(newAccount); - when(newAccount.getMutable()).thenReturn(newMutableAccount); - when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY); + when(newAccount.getCode()).thenReturn(Bytes.EMPTY); when(worldUpdater.updater()).thenReturn(worldUpdater); final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT); @@ -244,15 +238,13 @@ void shanghaiMaxInitCodeSizePlus1Create() { final UInt256 memoryLength = UInt256.fromHexString("0xc001"); final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); - when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.get(any())).thenReturn(account); when(worldUpdater.getSenderAccount(any())).thenReturn(account); when(worldUpdater.getOrCreate(any())).thenReturn(newAccount); - when(newAccount.getMutable()).thenReturn(newMutableAccount); - when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY); + when(newAccount.getCode()).thenReturn(Bytes.EMPTY); when(worldUpdater.updater()).thenReturn(worldUpdater); final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT); @@ -314,8 +306,7 @@ void eofV1CannotCreateLegacy() { .build(); messageFrame.writeMemory(memoryOffset.toLong(), memoryLength.toLong(), SIMPLE_CREATE); - when(account.getMutable()).thenReturn(mutableAccount); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); final EVM evm = MainnetEVMs.cancun(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT); @@ -339,9 +330,8 @@ void legacyCanCreateEOFv1() { .build(); messageFrame.writeMemory(memoryOffset.toLong(), memoryLength.toLong(), SIMPLE_EOF); - when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.get(any())).thenReturn(account); when(worldUpdater.getSenderAccount(any())).thenReturn(account); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java index b685b8702ff..822f515741e 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java @@ -40,7 +40,6 @@ import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; import java.util.Deque; import java.util.List; @@ -53,10 +52,8 @@ class CreateOperationTest { private final WorldUpdater worldUpdater = mock(WorldUpdater.class); - private final WrappedEvmAccount account = mock(WrappedEvmAccount.class); - private final WrappedEvmAccount newAccount = mock(WrappedEvmAccount.class); - private final MutableAccount mutableAccount = mock(MutableAccount.class); - private final MutableAccount newMutableAccount = mock(MutableAccount.class); + private final MutableAccount account = mock(MutableAccount.class); + private final MutableAccount newAccount = mock(MutableAccount.class); private final CreateOperation operation = new CreateOperation(new ConstantinopleGasCalculator(), Integer.MAX_VALUE); private final CreateOperation maxInitCodeOperation = @@ -91,15 +88,13 @@ void createFromMemoryMutationSafe() { final UInt256 memoryLength = UInt256.valueOf(SIMPLE_CREATE.size()); final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); - when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.get(any())).thenReturn(account); when(worldUpdater.getSenderAccount(any())).thenReturn(account); when(worldUpdater.getOrCreate(any())).thenReturn(newAccount); - when(newAccount.getMutable()).thenReturn(newMutableAccount); - when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY); + when(newAccount.getCode()).thenReturn(Bytes.EMPTY); when(worldUpdater.updater()).thenReturn(worldUpdater); final EVM evm = MainnetEVMs.london(EvmConfiguration.DEFAULT); @@ -131,9 +126,8 @@ void nonceTooLarge() { final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); when(worldUpdater.getAccount(any())).thenReturn(account); - when(account.getMutable()).thenReturn(mutableAccount); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); - when(mutableAccount.getNonce()).thenReturn(-1L); + when(account.getBalance()).thenReturn(Wei.ZERO); + when(account.getNonce()).thenReturn(-1L); final EVM evm = MainnetEVMs.london(EvmConfiguration.DEFAULT); operation.execute(messageFrame, evm); @@ -149,9 +143,8 @@ void messageFrameStackTooDeep() { testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1025); when(worldUpdater.getAccount(any())).thenReturn(account); - when(account.getMutable()).thenReturn(mutableAccount); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); - when(mutableAccount.getNonce()).thenReturn(55L); + when(account.getBalance()).thenReturn(Wei.ZERO); + when(account.getNonce()).thenReturn(55L); final EVM evm = MainnetEVMs.london(EvmConfiguration.DEFAULT); operation.execute(messageFrame, evm); @@ -171,9 +164,8 @@ void notEnoughValue() { } when(worldUpdater.getAccount(any())).thenReturn(account); - when(account.getMutable()).thenReturn(mutableAccount); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); - when(mutableAccount.getNonce()).thenReturn(55L); + when(account.getBalance()).thenReturn(Wei.ZERO); + when(account.getNonce()).thenReturn(55L); final EVM evm = MainnetEVMs.london(EvmConfiguration.DEFAULT); operation.execute(messageFrame, evm); @@ -187,15 +179,13 @@ void shanghaiMaxInitCodeSizeCreate() { final UInt256 memoryLength = UInt256.fromHexString("0xc000"); final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); - when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.get(any())).thenReturn(account); when(worldUpdater.getSenderAccount(any())).thenReturn(account); when(worldUpdater.getOrCreate(any())).thenReturn(newAccount); - when(newAccount.getMutable()).thenReturn(newMutableAccount); - when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY); + when(newAccount.getCode()).thenReturn(Bytes.EMPTY); when(worldUpdater.updater()).thenReturn(worldUpdater); final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT); @@ -217,15 +207,13 @@ void shanghaiMaxInitCodeSizePlus1Create() { final UInt256 memoryLength = UInt256.fromHexString("0xc001"); final MessageFrame messageFrame = testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1); - when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.get(any())).thenReturn(account); when(worldUpdater.getSenderAccount(any())).thenReturn(account); when(worldUpdater.getOrCreate(any())).thenReturn(newAccount); - when(newAccount.getMutable()).thenReturn(newMutableAccount); - when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY); + when(newAccount.getCode()).thenReturn(Bytes.EMPTY); when(worldUpdater.updater()).thenReturn(worldUpdater); final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT); @@ -247,8 +235,7 @@ void eofV1CannotCreateLegacy() { .build(); messageFrame.writeMemory(memoryOffset.toLong(), memoryLength.toLong(), SIMPLE_CREATE); - when(account.getMutable()).thenReturn(mutableAccount); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); final EVM evm = MainnetEVMs.cancun(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT); @@ -271,9 +258,8 @@ void legacyCanCreateEOFv1() { .build(); messageFrame.writeMemory(memoryOffset.toLong(), memoryLength.toLong(), SIMPLE_EOF); - when(account.getMutable()).thenReturn(mutableAccount); when(account.getNonce()).thenReturn(55L); - when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); + when(account.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.get(any())).thenReturn(account); when(worldUpdater.getSenderAccount(any())).thenReturn(account); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCodeHashOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCodeHashOperationTest.java index 3127970c3b9..a7ca5eefe67 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCodeHashOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCodeHashOperationTest.java @@ -69,7 +69,7 @@ void shouldReturnZeroWhenAccountDoesNotExist() { @Test void shouldReturnHashOfEmptyDataWhenAccountExistsButDoesNotHaveCode() { - worldStateUpdater.getOrCreate(REQUESTED_ADDRESS).getMutable().setBalance(Wei.of(1)); + worldStateUpdater.getOrCreate(REQUESTED_ADDRESS).setBalance(Wei.of(1)); assertThat(executeOperation(REQUESTED_ADDRESS)).isEqualTo(Hash.EMPTY); } @@ -87,14 +87,14 @@ void shouldReturnZeroWhenPrecompiledContractHasNoBalance() { @Test void shouldReturnEmptyCodeHashWhenPrecompileHasBalance() { // Sending money to a precompile causes it to exist in the world state archive. - worldStateUpdater.getOrCreate(Address.ECREC).getMutable().setBalance(Wei.of(10)); + worldStateUpdater.getOrCreate(Address.ECREC).setBalance(Wei.of(10)); assertThat(executeOperation(Address.ECREC)).isEqualTo(Hash.EMPTY); } @Test void shouldGetHashOfAccountCodeWhenCodeIsPresent() { final Bytes code = Bytes.fromHexString("0xabcdef"); - final MutableAccount account = worldStateUpdater.getOrCreate(REQUESTED_ADDRESS).getMutable(); + final MutableAccount account = worldStateUpdater.getOrCreate(REQUESTED_ADDRESS); account.setCode(code); assertThat(executeOperation(REQUESTED_ADDRESS)).isEqualTo(Hash.hash(code)); } @@ -103,7 +103,7 @@ void shouldGetHashOfAccountCodeWhenCodeIsPresent() { void shouldZeroOutLeftMostBitsToGetAddress() { // If EXTCODEHASH of A is X, then EXTCODEHASH of A + 2**160 is X. final Bytes code = Bytes.fromHexString("0xabcdef"); - final MutableAccount account = worldStateUpdater.getOrCreate(REQUESTED_ADDRESS).getMutable(); + final MutableAccount account = worldStateUpdater.getOrCreate(REQUESTED_ADDRESS); account.setCode(code); final UInt256 value = UInt256.fromBytes(Words.fromAddress(REQUESTED_ADDRESS)) diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/SStoreOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/SStoreOperationTest.java index fbf21ab5102..e2f14dbdb2a 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/SStoreOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/SStoreOperationTest.java @@ -64,7 +64,7 @@ private MessageFrame createMessageFrame( .blockValues(blockHeader) .initialGas(initialGas) .build(); - worldStateUpdater.getOrCreate(address).getMutable().setBalance(Wei.of(1)); + worldStateUpdater.getOrCreate(address).setBalance(Wei.of(1)); worldStateUpdater.commit(); frame.setGasRemaining(remainingGas); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java index f596bed8aad..6c178dda2a9 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java @@ -33,7 +33,6 @@ import org.hyperledger.besu.evm.operation.Operation; import org.hyperledger.besu.evm.operation.SelfDestructOperation; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.extension.ExtendWith; @@ -54,10 +53,8 @@ public class SelfDestructOperationTest { private MessageFrame messageFrame; @Mock private WorldUpdater worldUpdater; - @Mock private WrappedEvmAccount accountOriginator; - @Mock private WrappedEvmAccount accountBeneficiary; - @Mock private MutableAccount mutableAccountOriginator; - @Mock private MutableAccount mutableAccountBeneficiary; + @Mock private MutableAccount accountOriginator; + @Mock private MutableAccount accountBeneficiary; @Mock private EVM evm; private final SelfDestructOperation frontierOperation = @@ -104,9 +101,7 @@ void checkContractDeletionCommon( when(worldUpdater.get(beneficiaryAddress)).thenReturn(accountBeneficiary); } when(worldUpdater.getOrCreate(beneficiaryAddress)).thenReturn(accountBeneficiary); - when(accountOriginator.getMutable()).thenReturn(mutableAccountOriginator); when(accountOriginator.getBalance()).thenReturn(Wei.fromHexString(balanceHex)); - when(accountBeneficiary.getMutable()).thenReturn(mutableAccountBeneficiary); final Operation.OperationResult operationResult = operation.execute(messageFrame, evm); assertThat(operationResult).isNotNull(); @@ -115,10 +110,10 @@ void checkContractDeletionCommon( // some subset of these calls. verify(accountOriginator, atLeast(0)).getBalance(); verify(accountBeneficiary, atLeast(0)).getBalance(); - verify(mutableAccountOriginator, atLeast(0)).getBalance(); - verify(mutableAccountOriginator).decrementBalance(Wei.fromHexString(balanceHex)); - verify(mutableAccountOriginator, atLeast(0)).setBalance(Wei.ZERO); - verify(mutableAccountBeneficiary).incrementBalance(Wei.fromHexString(balanceHex)); + verify(accountOriginator, atLeast(0)).getBalance(); + verify(accountOriginator).decrementBalance(Wei.fromHexString(balanceHex)); + verify(accountOriginator, atLeast(0)).setBalance(Wei.ZERO); + verify(accountBeneficiary).incrementBalance(Wei.fromHexString(balanceHex)); } public static Object[][] params() { diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/TStoreOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/TStoreOperationTest.java index 403bd68a7a6..fed95ec0820 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/TStoreOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/TStoreOperationTest.java @@ -60,7 +60,7 @@ private MessageFrame createMessageFrame( .blockValues(blockHeader) .initialGas(initialGas) .build(); - worldStateUpdater.getOrCreate(address).getMutable().setBalance(Wei.of(1)); + worldStateUpdater.getOrCreate(address).setBalance(Wei.of(1)); worldStateUpdater.commit(); frame.setGasRemaining(remainingGas); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestCodeExecutor.java b/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestCodeExecutor.java index 02f6ffba191..7cc12b5867f 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestCodeExecutor.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestCodeExecutor.java @@ -83,7 +83,7 @@ public MessageFrame executeCode( public static void deployContract( final WorldUpdater worldUpdater, final Address contractAddress, final String codeHexString) { var updater = worldUpdater.updater(); - final MutableAccount contract = updater.getOrCreate(contractAddress).getMutable(); + final MutableAccount contract = updater.getOrCreate(contractAddress); contract.setNonce(0); contract.clearStorage(); @@ -95,8 +95,7 @@ public static WorldUpdater createInitialWorldState(final Consumer addressHash = Suppliers.memoize(() -> address == null ? Hash.ZERO : address.addressHash()); @@ -117,34 +118,44 @@ public NavigableMap storageEntriesFrom( throw new UnsupportedOperationException("Storage iteration not supported in toy evm"); } - @Override - public MutableAccount getMutable() throws ModificationNotAllowedException { - return this; - } - @Override public void setNonce(final long value) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } nonce = value; } @Override public void setBalance(final Wei value) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } balance = value; } @Override public void setCode(final Bytes code) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } this.code = code; codeHash = Suppliers.memoize(() -> this.code == null ? Hash.EMPTY : Hash.hash(this.code)); } @Override public void setStorageValue(final UInt256 key, final UInt256 value) { + if (!mutable) { + throw new ModificationNotAllowedException(); + } storage.put(key, value); } @Override public void clearStorage() { + if (!mutable) { + throw new ModificationNotAllowedException(); + } storage.clear(); } @@ -152,4 +163,9 @@ public void clearStorage() { public Map getUpdatedStorage() { return storage; } + + @Override + public void becomeImmutable() { + mutable = false; + } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyWorld.java b/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyWorld.java index b49d4930e5f..06aa833bcd2 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyWorld.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyWorld.java @@ -18,7 +18,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.util.Collection; @@ -59,11 +59,11 @@ public Account get(final Address address) { } @Override - public EvmAccount createAccount(final Address address, final long nonce, final Wei balance) { + public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) { return createAccount(null, address, nonce, balance, Bytes.EMPTY); } - public EvmAccount createAccount( + public MutableAccount createAccount( final Account parentAccount, final Address address, final long nonce, @@ -75,7 +75,7 @@ public EvmAccount createAccount( } @Override - public EvmAccount getAccount(final Address address) { + public MutableAccount getAccount(final Address address) { if (accounts.containsKey(address)) { return accounts.get(address); } else if (parent != null) { diff --git a/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java b/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java index e74d43d8ec4..9b57bd938f4 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.evm.EVM; -import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; @@ -45,7 +44,6 @@ class ExtendedOperationTracerTest { @Mock EVM evm; @Mock MessageFrame frame; @Mock WorldUpdater worldUpdater; - @Mock EvmAccount evmAccount; @Mock MutableAccount mutableAccount; @BeforeEach @@ -55,8 +53,7 @@ void setUp() { when(frame.getRemainingGas()).thenReturn(1L); when(frame.getWorldUpdater()).thenReturn(worldUpdater); - when(worldUpdater.getOrCreate(any())).thenReturn(evmAccount); - when(evmAccount.getMutable()).thenReturn(mutableAccount); + when(worldUpdater.getOrCreate(any())).thenReturn(mutableAccount); } @Test @@ -69,7 +66,6 @@ void shouldCallTraceAccountCreationResultIfIsExtendedTracing() { // traceAccountCreationResult has been called and values have been set assertThat(tracer.frame).isNotNull(); - assertThat(tracer.haltReason).isNotNull(); assertThat(tracer.haltReason).isEmpty(); } From 4ea60b239cdf5686b2bd11115944f292c630ea3d Mon Sep 17 00:00:00 2001 From: delehef Date: Thu, 14 Sep 2023 04:57:25 +0200 Subject: [PATCH 21/34] Add world context to transaction tracing API (#5836) * Add world context to transaction tracing API Signed-off-by: Franklin Delehelle * Update changelog with PR ID Signed-off-by: Franklin Delehelle * Add the Transaction to traceEndTransaction Signed-off-by: Franklin Delehelle * Rebase on main Signed-off-by: Franklin Delehelle * Add receipt-linked information to the transaction tracer Signed-off-by: Franklin Delehelle * added test Signed-off-by: Daniel Lehrner --------- Signed-off-by: Franklin Delehelle Signed-off-by: Daniel Lehrner Co-authored-by: Daniel Lehrner Co-authored-by: Sally MacFarlane Signed-off-by: garyschulte --- CHANGELOG.md | 1 + .../besu/services/TraceServiceImpl.java | 15 ++- .../besu/services/TraceServiceImplTest.java | 106 ++++++++++++++++++ .../hyperledger/besu/evmtool/T8nExecutor.java | 11 +- .../besu/evm/tracing/OperationTracer.java | 19 +++- .../besu/evm/tracing/StandardJsonTracer.java | 12 +- 6 files changed, 155 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5eab7194849..ad2cc26475f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 23.7.3 ### Additions and Improvements +- Add access to an immutable world view to start/end transaction hooks in the tracing API[#5836](https://github.com/hyperledger/besu/pull/5836) ### Breaking Changes - Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816) diff --git a/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java index 8b27108191f..485880ac50d 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java @@ -173,12 +173,12 @@ private List trace( .map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) .orElse(BlobGas.ZERO)); - tracer.traceStartTransaction(transaction); - + final WorldUpdater worldUpdater = chainUpdater.getNextUpdater(); + tracer.traceStartTransaction(worldUpdater, transaction); final TransactionProcessingResult result = transactionProcessor.processTransaction( blockchain, - chainUpdater.getNextUpdater(), + worldUpdater, header, transaction, header.getCoinbase(), @@ -188,7 +188,14 @@ private List trace( blobGasPrice); long transactionGasUsed = transaction.getGasLimit() - result.getGasRemaining(); - tracer.traceEndTransaction(result.getOutput(), transactionGasUsed, 0); + tracer.traceEndTransaction( + worldUpdater, + transaction, + result.isSuccessful(), + result.getOutput(), + result.getLogs(), + transactionGasUsed, + 0); results.add(result); }); diff --git a/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java index 0c8acd6a190..cb88a9b9730 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java @@ -17,14 +17,21 @@ import static org.assertj.core.api.Assertions.assertThat; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.evm.log.Log; +import org.hyperledger.besu.evm.worldstate.WorldView; import org.hyperledger.besu.plugin.services.TraceService; import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; +import java.util.List; + +import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; @@ -102,4 +109,103 @@ void shouldRetrieveStateUpdatePostTracingForAllBlocks() { assertThat(worldStateArchive.getMutable().get(addressToVerify).getNonce()) .isEqualTo(persistedNonceForAccount); } + + @Test + void shouldReturnTheCorrectWorldViewForTxStartEnd() { + final TxStartEndTracer txStartEndTracer = new TxStartEndTracer(); + + // block contains 1 transaction + traceService.traceBlock(31, txStartEndTracer); + + assertThat(txStartEndTracer.txStartWorldView).isNotNull(); + assertThat(txStartEndTracer.txEndWorldView).isNotNull(); + + assertThat(txStartEndTracer.txStartTransaction.getNonce()) + .isEqualTo(txStartEndTracer.txEndTransaction.getNonce()) + .isEqualTo(30); + assertThat(txStartEndTracer.txStartTransaction.getGasLimit()) + .isEqualTo(txStartEndTracer.txEndTransaction.getGasLimit()) + .isEqualTo(314159); + assertThat(txStartEndTracer.txStartTransaction.getTo().get()) + .isEqualTo(txStartEndTracer.txEndTransaction.getTo().get()) + .isEqualTo(Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f")); + assertThat(txStartEndTracer.txStartTransaction.getValue()) + .isEqualTo(txStartEndTracer.txEndTransaction.getValue()) + .isEqualTo( + Wei.fromHexString( + "0x000000000000000000000000000000000000000000000000000000000000000a")); + assertThat(txStartEndTracer.txStartTransaction.getPayload()) + .isEqualTo(txStartEndTracer.txEndTransaction.getPayload()) + .isEqualTo(Bytes.fromHexString("0xfd408767")); + + assertThat(txStartEndTracer.txEndStatus).isTrue(); + assertThat(txStartEndTracer.txEndOutput).isEqualTo(Bytes.fromHexString("0x")); + assertThat(txStartEndTracer.txEndGasUsed).isEqualTo(24303); + assertThat(txStartEndTracer.txEndTimeNs).isNotNull(); + + assertThat(txStartEndTracer.txEndLogs).isNotEmpty(); + + final Log actualLog = txStartEndTracer.txEndLogs.get(0); + assertThat(actualLog.getLogger()) + .isEqualTo(Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f")); + assertThat(actualLog.getData()) + .isEqualTo( + Bytes.fromHexString( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9000000000000000000000000000000000000000000000000000000000000002a")); + assertThat(actualLog.getTopics()).hasSize(4); + assertThat(actualLog.getTopics().get(0)) + .isEqualTo( + Bytes.fromHexString( + "0xd5f0a30e4be0c6be577a71eceb7464245a796a7e6a55c0d971837b250de05f4e")); + assertThat(actualLog.getTopics().get(1)) + .isEqualTo( + Bytes.fromHexString( + "0x0000000000000000000000000000000000000000000000000000000000000001")); + assertThat(actualLog.getTopics().get(2)) + .isEqualTo( + Bytes.fromHexString( + "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")); + assertThat(actualLog.getTopics().get(3)) + .isEqualTo( + Bytes.fromHexString( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + } + + private static class TxStartEndTracer implements BlockAwareOperationTracer { + public WorldView txStartWorldView; + public WorldView txEndWorldView; + + public Transaction txStartTransaction; + public Transaction txEndTransaction; + + public boolean txEndStatus; + public Bytes txEndOutput; + public List txEndLogs; + public long txEndGasUsed; + public Long txEndTimeNs; + + @Override + public void traceStartTransaction(final WorldView worldView, final Transaction transaction) { + txStartWorldView = worldView; + txStartTransaction = transaction; + } + + @Override + public void traceEndTransaction( + final WorldView worldView, + final Transaction transaction, + final boolean status, + final Bytes output, + final List logs, + final long gasUsed, + final long timeNs) { + txEndWorldView = worldView; + txEndTransaction = transaction; + txEndStatus = status; + txEndOutput = output; + txEndLogs = logs; + txEndGasUsed = gasUsed; + txEndTimeNs = timeNs; + } + } } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java index 9d2faeb7dc8..816954353dd 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java @@ -270,6 +270,7 @@ static T8nResult runTest( final TransactionProcessingResult result; try { tracer = tracerManager.getManagedTracer(i, transaction.getHash()); + tracer.traceStartTransaction(worldStateUpdater, transaction); result = processor.processTransaction( blockchain, @@ -312,12 +313,18 @@ static T8nResult runTest( .getGasCalculator() .transactionIntrinsicGasCost( transaction.getPayload(), transaction.getTo().isEmpty()); - tracer.traceEndTransaction( - result.getOutput(), gasUsed - intrinsicGas, timer.elapsed(TimeUnit.NANOSECONDS)); TransactionReceipt receipt = protocolSpec .getTransactionReceiptFactory() .create(transaction.getType(), result, worldState, gasUsed); + tracer.traceEndTransaction( + worldStateUpdater, + transaction, + result.isSuccessful(), + result.getOutput(), + result.getLogs(), + gasUsed - intrinsicGas, + timer.elapsed(TimeUnit.NANOSECONDS)); Bytes gasUsedInTransaction = Bytes.ofUnsignedLong(transactionGasUsed); receipts.add(receipt); ObjectNode receiptObject = receiptsArray.addObject(); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java index 4552fec4543..455911c6ca1 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java @@ -17,8 +17,11 @@ import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.operation.Operation.OperationResult; +import org.hyperledger.besu.evm.worldstate.WorldView; +import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; @@ -67,18 +70,30 @@ default void traceAccountCreationResult( /** * Trace the start of a transaction. * + * @param worldView an immutable view of the execution context * @param transaction the transaction which will be processed */ - default void traceStartTransaction(final Transaction transaction) {} + default void traceStartTransaction(final WorldView worldView, final Transaction transaction) {} /** * Trace the end of a transaction. * + * @param worldView an immutable view of the execution context + * @param tx the transaction that just concluded + * @param status true if the transaction is successful, false otherwise * @param output the bytes output from the transaction + * @param logs the logs emitted by this transaction * @param gasUsed the gas used by the entire transaction * @param timeNs the time in nanoseconds it took to execute the transaction */ - default void traceEndTransaction(final Bytes output, final long gasUsed, final long timeNs) {} + default void traceEndTransaction( + final WorldView worldView, + final Transaction tx, + final boolean status, + final Bytes output, + final List logs, + final long gasUsed, + final long timeNs) {} /** * Trace the entering of a new context diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java index 5dbc99dd0cf..1734e7f6730 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java @@ -18,10 +18,13 @@ import static com.google.common.base.Strings.padStart; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.internal.Words; +import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.operation.Operation; +import org.hyperledger.besu.evm.worldstate.WorldView; import java.io.PrintStream; import java.io.PrintWriter; @@ -216,7 +219,14 @@ public void traceAccountCreationResult( } @Override - public void traceEndTransaction(final Bytes output, final long gasUsed, final long timeNs) { + public void traceEndTransaction( + final WorldView _worldView, + final Transaction _tx, + final boolean _status, + final Bytes output, + final List _logs, + final long gasUsed, + final long timeNs) { final StringBuilder sb = new StringBuilder(1024); sb.append("{"); if (output.size() > 0) { From e4dd06e4fe4fed9207022d7f7d9e8d78fce96e53 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 13 Sep 2023 21:30:18 -0700 Subject: [PATCH 22/34] Bonsai based reference test worldstate (#5686) * create a bonsai based reference test worldstate -> getOrCreate in BonsaiWorldStateUpdateAccumulator - do not throw if we discover an empty account in a non-null BonsaiValue -> add curentStateRoot to t8n -> storageEntriesFrom and streamAccounts implemented in BonsaiWorldStateKeyValueStorage -> add endKey version of streamFromKey * bonsai fix for self-destruct and create2 at the same address and same block Signed-off-by: garyschulte Signed-off-by: Karim TAAM Co-authored-by: Karim TAAM Signed-off-by: garyschulte --- .../besu/ethereum/bonsai/BonsaiAccount.java | 2 +- .../bonsai/BonsaiWorldStateProvider.java | 2 +- .../bonsai/storage/BonsaiPreImageProxy.java | 68 +++++++ .../BonsaiWorldStateKeyValueStorage.java | 8 +- .../storage/flat/FlatDbReaderStrategy.java | 13 +- .../bonsai/worldview/BonsaiWorldState.java | 80 ++++---- .../BonsaiWorldStateUpdateAccumulator.java | 60 ++++-- .../mainnet/MainnetBlockProcessorTest.java | 3 + .../backwardsync/BackwardSyncContextTest.java | 7 +- .../backwardsync/ForwardSyncStepTest.java | 5 +- .../besu/evmtool/StateTestSubCommand.java | 7 +- .../hyperledger/besu/evmtool/T8nExecutor.java | 6 +- .../besu/evmtool/T8nSubCommand.java | 3 +- .../besu/evmtool/state-test/blockhash.json | 4 +- .../t8n/berlin-calculate-difficulty.json | 3 +- .../besu/evmtool/t8n/berlin-example-yul.json | 3 +- .../t8n/berlin-negative-cli-reward.json | 3 +- .../evmtool/t8n/berlin-no-cli-reward.json | 3 +- .../besu/evmtool/t8n/berlin-no-tx.json | 3 +- .../besu/evmtool/t8n/berlin-simple.json | 3 +- .../t8n/cancun-6780-selfdestruct-sweep.json | 3 +- .../t8n/cancun-6780-selfdestruct-to-self.json | 3 +- .../cancun-6780-selfdestruct-transient.json | 3 +- .../besu/evmtool/t8n/cancun-blobs-per-tx.json | 3 +- .../evmtool/t8n/istanbul-cumulative-gas.json | 1 + .../evmtool/t8n/london-env-no-basefee.json | 3 +- .../besu/evmtool/t8n/london-hex.json | 3 +- .../besu/evmtool/t8n/shanghai-blockhash.json | 3 +- .../besu/evmtool/t8n/shanghai-init-code.json | 3 +- .../besu/evmtool/t8n/shanghai-invalidTx.json | 3 +- .../t8n/shanghai-withdrawals-no-nonce.json | 3 +- .../t8n/shanghai-withdrawals-overflow.json | 3 +- .../evmtool/t8n/shanghai-withdrawals.json | 3 +- ethereum/referencetests/build.gradle | 3 + .../BonsaiReferenceTestUpdateAccumulator.java | 44 +++++ .../BonsaiReferenceTestWorldState.java | 182 ++++++++++++++++++ .../BonsaiReferenceTestWorldStateStorage.java | 85 ++++++++ .../DefaultReferenceTestWorldState.java | 60 ++++++ .../GeneralStateTestCaseEipSpec.java | 7 +- .../GeneralStateTestCaseSpec.java | 11 +- .../referencetests/ReferenceTestEnv.java | 3 +- .../ReferenceTestWorldState.java | 30 +-- .../vm/GeneralStateReferenceTestTools.java | 8 +- plugin-api/build.gradle | 2 +- .../services/storage/KeyValueStorage.java | 11 ++ .../storage/SegmentedKeyValueStorage.java | 13 ++ .../RocksDBColumnarKeyValueSnapshot.java | 9 +- .../RocksDBColumnarKeyValueStorage.java | 11 ++ .../segmented/RocksDBSnapshotTransaction.java | 43 +++++ .../kvstore/LayeredKeyValueStorage.java | 12 +- .../LimitedInMemoryKeyValueStorage.java | 7 + .../SegmentedInMemoryKeyValueStorage.java | 13 +- .../SegmentedKeyValueStorageAdapter.java | 10 +- 53 files changed, 746 insertions(+), 141 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiPreImageProxy.java create mode 100644 ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestUpdateAccumulator.java create mode 100644 ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java create mode 100644 ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldStateStorage.java create mode 100644 ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/DefaultReferenceTestWorldState.java diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java index a5488cb9a2e..7362d345ce4 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java @@ -219,7 +219,7 @@ public UInt256 getOriginalStorageValue(final UInt256 key) { @Override public NavigableMap storageEntriesFrom( final Bytes32 startKeyHash, final int limit) { - throw new RuntimeException("Bonsai Tries does not currently support enumerating storage"); + return context.getWorldStateStorage().storageEntriesFrom(this.addressHash, startKeyHash, limit); } public Bytes serializeAccount() { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java index 986e736745a..6388d62a584 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java @@ -102,8 +102,8 @@ public BonsaiWorldStateProvider( pluginContext); this.blockchain = blockchain; this.worldStateStorage = worldStateStorage; - this.persistedState = new BonsaiWorldState(this, worldStateStorage); this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; + this.persistedState = new BonsaiWorldState(this, worldStateStorage); blockchain .getBlockHeader(persistedState.getWorldStateBlockHash()) .ifPresent( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiPreImageProxy.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiPreImageProxy.java new file mode 100644 index 00000000000..248e5d895fd --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiPreImageProxy.java @@ -0,0 +1,68 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.bonsai.storage; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; + +import java.util.Optional; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt256; + +/** Acts as both a Hasher and PreImageStorage for Bonsai storage format. */ +public interface BonsaiPreImageProxy extends WorldStatePreimageStorage { + /** + * If this value is not already present, save in preImage store and return the hash value. + * + * @param value value to hash + * @return Hash of value + */ + Hash hashAndSavePreImage(Bytes value); + + /** + * A caching PreImageProxy suitable for ReferenceTestWorldState which saves hashes in an unbounded + * BiMap. + */ + class BonsaiReferenceTestPreImageProxy implements BonsaiPreImageProxy { + BiMap preImageCache = HashBiMap.create(); + + @Override + public synchronized Hash hashAndSavePreImage(final Bytes value) { + return preImageCache.inverse().computeIfAbsent(value, Hash::hash); + } + + @Override + public Optional getStorageTrieKeyPreimage(final Bytes32 trieKey) { + return Optional.ofNullable(preImageCache.get(trieKey)).map(UInt256::fromBytes); + } + + @Override + public Optional
getAccountTrieKeyPreimage(final Bytes32 trieKey) { + return Optional.ofNullable(preImageCache.get(trieKey)).map(Address::wrap); + } + + @Override + public Updater updater() { + throw new UnsupportedOperationException( + "BonsaiReferenceTestPreImageProxy does not implement an updater"); + } + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java index 4ceb63ef219..1201fffb3b8 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; @@ -41,6 +42,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; +import java.util.NavigableMap; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; @@ -53,7 +55,6 @@ @SuppressWarnings("unused") public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoCloseable { - private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateKeyValueStorage.class); // 0x776f726c64526f6f74 @@ -250,6 +251,11 @@ public Map streamFlatStorages( composedWorldStateStorage, accountHash, startKeyHash, endKeyHash, max); } + public NavigableMap storageEntriesFrom( + final Hash addressHash, final Bytes32 startKeyHash, final int limit) { + throw new RuntimeException("Bonsai Tries does not currently support enumerating storage"); + } + @Override public Optional getNodeData(final Bytes location, final Bytes32 hash) { return Optional.empty(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FlatDbReaderStrategy.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FlatDbReaderStrategy.java index 1a35dbb93fe..74c7b101c25 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FlatDbReaderStrategy.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FlatDbReaderStrategy.java @@ -135,10 +135,10 @@ public Map streamAccountFlatDatabase( final long max) { final Stream> pairStream = storage - .streamFromKey(ACCOUNT_INFO_STATE, startKeyHash.toArrayUnsafe()) + .streamFromKey( + ACCOUNT_INFO_STATE, startKeyHash.toArrayUnsafe(), endKeyHash.toArrayUnsafe()) .limit(max) - .map(pair -> new Pair<>(Bytes32.wrap(pair.getKey()), Bytes.wrap(pair.getValue()))) - .takeWhile(pair -> pair.getFirst().compareTo(endKeyHash) <= 0); + .map(pair -> new Pair<>(Bytes32.wrap(pair.getKey()), Bytes.wrap(pair.getValue()))); final TreeMap collected = pairStream.collect( @@ -157,15 +157,14 @@ public Map streamStorageFlatDatabase( storage .streamFromKey( ACCOUNT_STORAGE_STORAGE, - Bytes.concatenate(accountHash, startKeyHash).toArrayUnsafe()) - .takeWhile(pair -> Bytes.wrap(pair.getKey()).slice(0, Hash.SIZE).equals(accountHash)) + Bytes.concatenate(accountHash, startKeyHash).toArrayUnsafe(), + Bytes.concatenate(accountHash, endKeyHash).toArrayUnsafe()) .limit(max) .map( pair -> new Pair<>( Bytes32.wrap(Bytes.wrap(pair.getKey()).slice(Hash.SIZE)), - RLP.encodeValue(Bytes.wrap(pair.getValue()).trimLeadingZeros()))) - .takeWhile(pair -> pair.getFirst().compareTo(endKeyHash) <= 0); + RLP.encodeValue(Bytes.wrap(pair.getValue()).trimLeadingZeros()))); final TreeMap collected = pairStream.collect( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java index 865471eca99..f28e24b0970 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.bonsai.BonsaiAccount; import org.hyperledger.besu.ethereum.bonsai.BonsaiValue; import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateProvider; +import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiSnapshotWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber; @@ -65,51 +66,52 @@ public class BonsaiWorldState private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldState.class); - private BonsaiWorldStateKeyValueStorage worldStateStorage; + protected BonsaiWorldStateKeyValueStorage worldStateStorage; - private final BonsaiWorldStateProvider archive; - private final BonsaiWorldStateUpdateAccumulator accumulator; + protected final CachedMerkleTrieLoader cachedMerkleTrieLoader; + protected final TrieLogManager trieLogManager; + private BonsaiWorldStateUpdateAccumulator accumulator; - private Hash worldStateRootHash; + protected Hash worldStateRootHash; Hash worldStateBlockHash; - private boolean isFrozen; public BonsaiWorldState( final BonsaiWorldStateProvider archive, final BonsaiWorldStateKeyValueStorage worldStateStorage) { - this.archive = archive; + this(worldStateStorage, archive.getCachedMerkleTrieLoader(), archive.getTrieLogManager()); + } + + protected BonsaiWorldState( + final BonsaiWorldStateKeyValueStorage worldStateStorage, + final CachedMerkleTrieLoader cachedMerkleTrieLoader, + final TrieLogManager trieLogManager) { this.worldStateStorage = worldStateStorage; - worldStateRootHash = + this.worldStateRootHash = Hash.wrap( Bytes32.wrap(worldStateStorage.getWorldStateRootHash().orElse(Hash.EMPTY_TRIE_HASH))); - worldStateBlockHash = + this.worldStateBlockHash = Hash.wrap(Bytes32.wrap(worldStateStorage.getWorldStateBlockHash().orElse(Hash.ZERO))); - accumulator = + this.accumulator = new BonsaiWorldStateUpdateAccumulator( this, (addr, value) -> - archive - .getCachedMerkleTrieLoader() - .preLoadAccount(getWorldStateStorage(), worldStateRootHash, addr), + cachedMerkleTrieLoader.preLoadAccount( + getWorldStateStorage(), worldStateRootHash, addr), (addr, value) -> - archive - .getCachedMerkleTrieLoader() - .preLoadStorageSlot(getWorldStateStorage(), addr, value)); + cachedMerkleTrieLoader.preLoadStorageSlot(getWorldStateStorage(), addr, value)); + this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; + this.trieLogManager = trieLogManager; } - public BonsaiWorldState( - final BonsaiWorldStateProvider archive, - final BonsaiWorldStateKeyValueStorage worldStateStorage, - final BonsaiWorldStateUpdateAccumulator updater) { - this.archive = archive; - this.worldStateStorage = worldStateStorage; - this.worldStateRootHash = - Hash.wrap( - Bytes32.wrap(worldStateStorage.getWorldStateRootHash().orElse(Hash.EMPTY_TRIE_HASH))); - this.worldStateBlockHash = - Hash.wrap(Bytes32.wrap(worldStateStorage.getWorldStateBlockHash().orElse(Hash.ZERO))); - this.accumulator = updater; + /** + * Having a protected method to override the accumulator solves the chicken-egg problem of needing + * a worldstate reference (this) when construction the Accumulator. + * + * @param accumulator accumulator to use. + */ + protected void setAccumulator(final BonsaiWorldStateUpdateAccumulator accumulator) { + this.accumulator = accumulator; } /** @@ -130,10 +132,6 @@ public Hash getWorldStateRootHash() { return worldStateRootHash; } - public BonsaiWorldStateProvider getArchive() { - return archive; - } - @Override public boolean isPersisted() { return isPersisted(worldStateStorage); @@ -189,9 +187,7 @@ private Hash calculateRootHash( final StoredMerklePatriciaTrie accountTrie = createTrie( (location, hash) -> - archive - .getCachedMerkleTrieLoader() - .getAccountStateTrieNode(worldStateStorage, location, hash), + cachedMerkleTrieLoader.getAccountStateTrieNode(worldStateStorage, location, hash), worldStateRootHash); // for manicured tries and composting, collect branches here (not implemented) @@ -223,7 +219,7 @@ private void updateTheAccounts( final BonsaiAccount updatedAccount = bonsaiValue.getUpdated(); try { if (updatedAccount == null) { - final Hash addressHash = Hash.hash(accountKey); + final Hash addressHash = hashAndSavePreImage(accountKey); accountTrie.remove(addressHash); maybeStateUpdater.ifPresent( bonsaiUpdater -> bonsaiUpdater.removeAccountInfoState(addressHash)); @@ -232,7 +228,7 @@ private void updateTheAccounts( final Bytes accountValue = updatedAccount.serializeAccount(); maybeStateUpdater.ifPresent( bonsaiUpdater -> - bonsaiUpdater.putAccountInfoState(Hash.hash(accountKey), accountValue)); + bonsaiUpdater.putAccountInfoState(hashAndSavePreImage(accountKey), accountValue)); accountTrie.put(addressHash, accountValue); } } catch (MerkleTrieException e) { @@ -277,10 +273,8 @@ private void updateAccountStorageState( final StoredMerklePatriciaTrie storageTrie = createTrie( (location, key) -> - archive - .getCachedMerkleTrieLoader() - .getAccountStorageTrieNode( - worldStateStorage, updatedAddressHash, location, key), + cachedMerkleTrieLoader.getAccountStorageTrieNode( + worldStateStorage, updatedAddressHash, location, key), storageRoot); // for manicured tries and composting, collect branches here (not implemented) @@ -405,7 +399,6 @@ public void persist(final BlockHeader blockHeader) { } saveTrieLog = () -> { - final TrieLogManager trieLogManager = archive.getTrieLogManager(); trieLogManager.saveTrieLog(localCopy, newWorldStateRootHash, blockHeader, this); // not save a frozen state in the cache if (!isFrozen) { @@ -626,4 +619,9 @@ private void closeFrozenStorage() { // no op } } + + protected Hash hashAndSavePreImage(final Bytes value) { + // by default do not save has preImages + return Hash.hash(value); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java index b1cd64378b9..23fd7625fa3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java @@ -127,14 +127,18 @@ public MutableAccount createAccount(final Address address, final long nonce, fin bonsaiValue = new BonsaiValue<>(null, null); accountsToUpdate.put(address, bonsaiValue); } else if (bonsaiValue.getUpdated() != null) { - throw new IllegalStateException("Cannot create an account when one already exists"); + if (bonsaiValue.getUpdated().isEmpty()) { + return track(new UpdateTrackingAccount<>(bonsaiValue.getUpdated())); + } else { + throw new IllegalStateException("Cannot create an account when one already exists"); + } } final BonsaiAccount newAccount = new BonsaiAccount( this, address, - address.addressHash(), + hashAndSavePreImage(address), nonce, balance, Hash.EMPTY_TRIE_HASH, @@ -288,6 +292,19 @@ public void commit() { final BonsaiAccount updatedAccount; final BonsaiValue updatedAccountValue = accountsToUpdate.get(updatedAddress); + + final Map> pendingStorageUpdates = + storageToUpdate.computeIfAbsent( + updatedAddress, + k -> + new StorageConsumingMap<>( + updatedAddress, new ConcurrentHashMap<>(), storagePreloader)); + + if (tracked.getStorageWasCleared()) { + storageToClear.add(updatedAddress); + pendingStorageUpdates.clear(); + } + if (tracked.getWrappedAccount() == null) { updatedAccount = new BonsaiAccount(this, tracked); tracked.setWrappedAccount(updatedAccount); @@ -307,6 +324,17 @@ public void commit() { } if (tracked.getStorageWasCleared()) { updatedAccount.clearStorage(); + wrappedWorldView() + .getAllAccountStorage(updatedAddress, updatedAccount.getStorageRoot()) + .forEach( + (keyHash, entryValue) -> { + final StorageSlotKey storageSlotKey = + new StorageSlotKey(Hash.wrap(keyHash), Optional.empty()); + final UInt256 value = UInt256.fromBytes(RLP.decodeOne(entryValue)); + pendingStorageUpdates.put( + storageSlotKey, new BonsaiValue<>(value, null, true)); + }); + updatedAccount.setStorageRoot(Hash.EMPTY_TRIE_HASH); } tracked.getUpdatedStorage().forEach(updatedAccount::setStorageValue); } @@ -329,24 +357,12 @@ public void commit() { pendingCode.setUpdated(updatedAccount.getCode()); } - // This is especially to avoid unnecessary computation for withdrawals + // This is especially to avoid unnecessary computation for withdrawals and + // self-destruct beneficiaries if (updatedAccount.getUpdatedStorage().isEmpty()) { return; } - final StorageConsumingMap> - pendingStorageUpdates = - storageToUpdate.computeIfAbsent( - updatedAddress, - __ -> - new StorageConsumingMap<>( - updatedAddress, new ConcurrentHashMap<>(), storagePreloader)); - - if (tracked.getStorageWasCleared()) { - storageToClear.add(updatedAddress); - pendingStorageUpdates.clear(); - } - final TreeSet> entries = new TreeSet<>(Map.Entry.comparingByKey()); entries.addAll(updatedAccount.getUpdatedStorage().entrySet()); @@ -355,7 +371,7 @@ public void commit() { entries.forEach( storageUpdate -> { final UInt256 keyUInt = storageUpdate.getKey(); - final Hash slotHash = Hash.hash(keyUInt); + final Hash slotHash = hashAndSavePreImage(keyUInt); final StorageSlotKey slotKey = new StorageSlotKey(slotHash, Optional.of(keyUInt)); final UInt256 value = storageUpdate.getValue(); @@ -399,7 +415,8 @@ public Optional getCode(final Address address, final Hash codeHash) { @Override public UInt256 getStorageValue(final Address address, final UInt256 slotKey) { - StorageSlotKey storageSlotKey = new StorageSlotKey(Hash.hash(slotKey), Optional.of(slotKey)); + StorageSlotKey storageSlotKey = + new StorageSlotKey(hashAndSavePreImage(slotKey), Optional.of(slotKey)); return getStorageValueByStorageSlotKey(address, storageSlotKey).orElse(UInt256.ZERO); } @@ -443,7 +460,7 @@ public Optional getStorageValueByStorageSlotKey( public UInt256 getPriorStorageValue(final Address address, final UInt256 storageKey) { // TODO maybe log the read into the trie layer? StorageSlotKey storageSlotKey = - new StorageSlotKey(Hash.hash(storageKey), Optional.of(storageKey)); + new StorageSlotKey(hashAndSavePreImage(storageKey), Optional.of(storageKey)); final Map> localAccountStorage = storageToUpdate.get(address); if (localAccountStorage != null) { @@ -816,4 +833,9 @@ protected Map delegate() { public interface Consumer { void process(final Address address, T value); } + + protected Hash hashAndSavePreImage(final Bytes bytes) { + // by default do not save hash preImages + return Hash.hash(bytes); + } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockProcessorTest.java index 6bd6978acb1..1b106686bfc 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockProcessorTest.java @@ -94,6 +94,9 @@ public void accountCreatedWhenBlockRewardIsZeroAndNotSkipped() { final BlockHeader emptyBlockHeader = new BlockHeaderTestFixture() .transactionsRoot(Hash.EMPTY_LIST_HASH) + .stateRoot( + Hash.fromHexString( + "0xa6b5d50f7b3c39b969c2fe8fed091939c674fef49b4826309cb6994361e39b71")) .ommersHash(Hash.EMPTY_LIST_HASH) .buildHeader(); blockProcessor.processBlock(blockchain, worldState, emptyBlockHeader, emptyList(), emptyList()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java index 3ed28e66f4d..b5909c4d429 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java @@ -47,7 +47,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; -import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState; +import org.hyperledger.besu.ethereum.referencetests.DefaultReferenceTestWorldState; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -149,7 +149,10 @@ public void setup() { return new BlockProcessingResult( Optional.of( new BlockProcessingOutputs( - new ReferenceTestWorldState(), blockDataGenerator.receipts(block)))); + // use forest-based worldstate since it does not require + // blockheader stateroot to match actual worldstate root + DefaultReferenceTestWorldState.create(Collections.emptyMap()), + blockDataGenerator.receipts(block)))); }); backwardChain = inMemoryBackwardChain(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java index 77308ebcc3b..e38a9647b79 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java @@ -38,7 +38,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState; +import org.hyperledger.besu.ethereum.referencetests.DefaultReferenceTestWorldState; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.nio.charset.StandardCharsets; @@ -138,7 +138,8 @@ public void setup() { return new BlockProcessingResult( Optional.of( new BlockProcessingOutputs( - new ReferenceTestWorldState(), blockDataGenerator.receipts(block)))); + DefaultReferenceTestWorldState.create(Collections.emptyMap()), + blockDataGenerator.receipts(block)))); }); } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java index 95af770c589..2bc5f815309 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java @@ -37,12 +37,10 @@ import org.hyperledger.besu.ethereum.referencetests.ReferenceTestBlockchain; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules; import org.hyperledger.besu.ethereum.rlp.RLP; -import org.hyperledger.besu.ethereum.worldstate.DefaultMutableWorldState; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.StandardJsonTracer; -import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evmtool.exception.UnsupportedForkException; import org.hyperledger.besu.util.LogConfigurator; @@ -200,9 +198,7 @@ private void traceTestSpecs(final String test, final List transactions, final List rejections, final TracerManager tracerManager) { @@ -238,7 +238,7 @@ static T8nResult runTest( ReferenceTestProtocolSchedules.create( new StubGenesisConfigOptions().chainId(BigInteger.valueOf(chainId))); - final MutableWorldState worldState = new DefaultMutableWorldState(initialWorldState); + final MutableWorldState worldState = initialWorldState.copy(); final ProtocolSchedule protocolSchedule = referenceTestProtocolSchedules.getByName(fork); if (protocolSchedule == null) { diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java index 1571dc3551e..ea2984c5c90 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java @@ -21,7 +21,6 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState; @@ -175,7 +174,7 @@ public void run() { final ObjectMapper objectMapper = JsonUtils.createObjectMapper(); final ObjectReader t8nReader = objectMapper.reader(); - MutableWorldState initialWorldState; + ReferenceTestWorldState initialWorldState; ReferenceTestEnv referenceTestEnv; List transactions = new ArrayList<>(); List rejections = new ArrayList<>(); diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/blockhash.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/blockhash.json index b5bac5462ef..de44541641d 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/blockhash.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/blockhash.json @@ -61,7 +61,7 @@ "post": { "Shanghai": [ { - "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "hash": "0xd14c10ed22a1cfb642e374be985ac581c39f3969bd59249e0405aca3beb47a47", "logs": "0x0000000000000000000000000000000000000000000000000000000000000000", "indexes": { "data": 0, @@ -101,4 +101,4 @@ {"pc":83,"op":62,"gas":"0x79bc18","gasCost":"0x0","memSize":0,"stack":["0x0","0x1","0x1","0x2","0x2","0xffff","0x1f4","0x78859e5b97166c486532b1595a673e9f9073643f1b519c6f18511b9913","0x2","0x389","0x0","0x0","0x1","0x0","0x3e3d6d5ff042148d326c1898713a76759ca273","0xb94f5374fce5edbc8e2a8697c15331677e6ebf1b"],"depth":1,"refund":0,"opName":"RETURNDATACOPY","error":"Out of bounds"}, {"output":"","gasUsed":"0x7a1200","test":"00000936-mixed-1","fork":"Shanghai","d":0,"g":0,"v":0,"postHash":"0xd14c10ed22a1cfb642e374be985ac581c39f3969bd59249e0405aca3beb47a47","postLogsHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","pass":false} ] -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json index 1a3c7a178c6..005cb1498ad 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json @@ -48,6 +48,7 @@ "currentGasLimit": "100000000000000000", "currentNumber": "1", "currentTimestamp": "1000", + "currentStateRoot": "0xd921e74bfe864514fa508003336b8f66eb98d748c5163749827029a1ed7db265", "parentDifficulty": "131072", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", @@ -101,4 +102,4 @@ "gasUsed": "0xa8ad" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json index 1a3c7a178c6..005cb1498ad 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json @@ -48,6 +48,7 @@ "currentGasLimit": "100000000000000000", "currentNumber": "1", "currentTimestamp": "1000", + "currentStateRoot": "0xd921e74bfe864514fa508003336b8f66eb98d748c5163749827029a1ed7db265", "parentDifficulty": "131072", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", @@ -101,4 +102,4 @@ "gasUsed": "0xa8ad" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-negative-cli-reward.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-negative-cli-reward.json index 4ef273955c4..f41eb4989c4 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-negative-cli-reward.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-negative-cli-reward.json @@ -46,6 +46,7 @@ "env": { "currentCoinbase": "0x0000000000000000000000000000000000000000", "currentDifficulty": "0x0", + "currentStateRoot": "0xde762e485411037c02119ff1115b422945b37efe91f4135dd442c3346629d0ef", "currentGasLimit": "0x0", "currentNumber": "0", "currentTimestamp": "0" @@ -93,4 +94,4 @@ "gasUsed": "0xa8ad" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-no-cli-reward.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-no-cli-reward.json index d06c75ccfd2..4aba3a31a1d 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-no-cli-reward.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-no-cli-reward.json @@ -45,6 +45,7 @@ "env": { "currentCoinbase": "0x0000000000000000000000000000000000000000", "currentDifficulty": "0x0", + "currentStateRoot": "0x9580f6eec8ad54773eff8e370d12dfea7b3216e929657c48a509af64c4190be6", "currentGasLimit": "0x0", "currentNumber": "0", "currentTimestamp": "0" @@ -92,4 +93,4 @@ "gasUsed": "0xa8ad" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-no-tx.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-no-tx.json index 5abcf7bb347..8c655b71ec9 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-no-tx.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-no-tx.json @@ -30,6 +30,7 @@ "env": { "currentCoinbase": "0x0000000000000000000000000000000000000000", "currentDifficulty": "0x0", + "currentStateRoot": "0x369ba8b2e5b32d675d07933d6fb851d97d3ca66c60a829f7356163d92ae0439a", "currentGasLimit": "0x0", "currentNumber": "0", "currentTimestamp": "0" @@ -57,4 +58,4 @@ "gasUsed": "0x0" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-simple.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-simple.json index e4555f220b3..3fef5b5a296 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-simple.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-simple.json @@ -46,6 +46,7 @@ "env": { "currentCoinbase": "0x0000000000000000000000000000000000000000", "currentDifficulty": "0x0", + "currentStateRoot": "0xde762e485411037c02119ff1115b422945b37efe91f4135dd442c3346629d0ef", "currentGasLimit": "0x0", "currentNumber": "0", "currentTimestamp": "0" @@ -93,4 +94,4 @@ "gasUsed": "0xa8ad" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-sweep.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-sweep.json index bc7d113ec79..7e1ffaf68d1 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-sweep.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-sweep.json @@ -49,6 +49,7 @@ "currentTimestamp": "1000", "currentRandom": "0", "currentDifficulty": "0", + "currentStateRoot": "0x3a0e532de836d767cae901aba671040fedc07557d277f7203066f640ed95f78d", "parentDifficulty": "0", "parentBaseFee": "7", "parentGasUsed": "0", @@ -113,4 +114,4 @@ "currentExcessBlobGas": "0x0" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-to-self.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-to-self.json index 7d8907d9bfb..d922c54baa7 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-to-self.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-to-self.json @@ -51,6 +51,7 @@ "currentTimestamp": "1000", "currentRandom": "0", "currentDifficulty": "0", + "currentStateRoot" : "0xddd3a541e86e2dd0293959736de63e1fad74ae95149f34740b1173378e82527a", "parentDifficulty": "0", "parentBaseFee": "7", "parentGasUsed": "0", @@ -112,4 +113,4 @@ "currentExcessBlobGas": "0x0" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-transient.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-transient.json index 1860990b0f7..997b29f76bd 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-transient.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-transient.json @@ -43,6 +43,7 @@ "currentTimestamp": "1000", "currentRandom": "0", "currentDifficulty": "0", + "currentStateRoot": "0xe8a9461dcfdbaa48bbddca4f4baa439e45f1489827e5deeb2797363323e34769", "parentDifficulty": "0", "parentBaseFee": "7", "parentGasUsed": "0", @@ -97,4 +98,4 @@ "currentExcessBlobGas": "0x0" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json index b2ed324b3d6..0912b52b81a 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json @@ -53,6 +53,7 @@ "currentTimestamp": "24", "currentRandom": "0", "currentDifficulty": "0", + "currentStateRoot": "0xd29f5a8dd1a63e0a299009f546bdf447fb61f1604d95e737bd8eb3c089d78060", "parentDifficulty": "0", "parentBaseFee": "7", "parentGasUsed": "21000", @@ -114,4 +115,4 @@ "currentExcessBlobGas": "0x0" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json index d3dd7021df7..087eae7745b 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json @@ -363,6 +363,7 @@ "currentGasLimit": "100000000000000000", "currentNumber": "1", "currentTimestamp": "1000", + "currentStateRoot": "0xf4f4aed0d1813d2880d8bb1cb5697303c20002ac6bfc206635645f43805ccbcb", "parentDifficulty": "131072", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json index 052ebb5260b..bb2d2da5dbc 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json @@ -48,6 +48,7 @@ "currentGasLimit": "100000000000000000", "currentNumber": "1", "currentTimestamp": "1000", + "currentStateRoot": "0x5c0f211cd1bea44ac01bd3fd7e0ab742d316adabd139bcf60a7aac6c458d596d", "parentDifficulty": "131072", "parentBaseFee": "7", "parentGasUsed": "50000000000000000", @@ -103,4 +104,4 @@ "currentBaseFee": "0x7" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-hex.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-hex.json index 502ac628de6..1ccce1739d6 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-hex.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-hex.json @@ -48,6 +48,7 @@ "currentNumber": "0x1", "currentTimestamp": "0x0", "currentGasLimit": "0xff112233445566", + "currentStateRoot": "0x5775e461ac316f8c02466d23e4492d24bbe546336f6fc632dd1311d6a5b67b22", "previousHash": "0xb271e9e5796d0ff5a2fd519ba666393e42d4f38680854761121d84a7a96ff017", "parentTimestamp": "0x00", "parentDifficulty": "0x00", @@ -102,4 +103,4 @@ "currentBaseFee": "0xa" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json index e1c331206d2..9b2908976fc 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json @@ -48,6 +48,7 @@ "currentTimestamp": "24", "currentRandom": "0", "currentDifficulty": "0", + "currentStateRoot": "0x89412c0f1bb31b983d0317e6e2801a4e604e1ef9987a132ab63c52f2d5a3994b", "parentDifficulty": "0", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", @@ -106,4 +107,4 @@ "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json index d536a6a7260..6c502e80cc8 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json @@ -42,6 +42,7 @@ "currentTimestamp": "12", "currentRandom": "0", "currentDifficulty": "0", + "currentStateRoot": "0x70c42824108fafccadbfce71e6e22660c4fad89be18be324cd15ef351969a8c8", "parentDifficulty": "0", "parentBaseFee": "7", "parentGasUsed": "0", @@ -81,4 +82,4 @@ "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-invalidTx.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-invalidTx.json index 7ec8a1d7763..79087bf545a 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-invalidTx.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-invalidTx.json @@ -42,6 +42,7 @@ "currentNumber": "1", "currentTimestamp": "1000", "currentDifficulty": "0x20000", + "currentStateRoot": "0xec92f4c572101075d17eb5aaf15c33df92b6d5519cbed635fc53353b99e8e6da", "currentBaseFee": "0xa", "blockHashes": { "0": "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" @@ -84,4 +85,4 @@ "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json index 86cefab468f..4e9f1febebe 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json @@ -40,6 +40,7 @@ "currentTimestamp": "24", "currentRandom": "0", "currentDifficulty": "0", + "currentStateRoot": "0x41855ebd4b425591ae60f57de6ec700c8a1128c7761b63371b09671b5f1abb3f", "parentDifficulty": "0", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", @@ -98,4 +99,4 @@ "withdrawalsRoot": "0xa485a3bd07e29cb8234b5f093d5216eb8b965fb2693c66fea254f6cacef97a6f" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json index 8f8b29b7525..e334d94cbff 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json @@ -34,6 +34,7 @@ "currentTimestamp": "12", "currentRandom": "0", "currentDifficulty": "0", + "currentStateRoot": "0x2a23ea102cd739aa3ad83a9be1555d621e50b3a3f780a7369ec2a6c03f22e18d", "parentDifficulty": "0", "parentBaseFee": "7", "parentGasUsed": "0", @@ -78,4 +79,4 @@ "withdrawalsRoot": "0x7bae13217931ff0d7a6c5823c996492f28cd92da5a7788a9a68856bb2206741a" } } -} \ No newline at end of file +} diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json index 5a4efc2eea0..946a97ceac6 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json @@ -35,6 +35,7 @@ "currentTimestamp": "12", "currentRandom": "0", "currentDifficulty": "0", + "currentStateRoot": "0x7075d070d6ec70a91216fc2dba6ceae6b8d30815166f6b7b7249776767fb9855", "parentDifficulty": "0", "parentBaseFee": "7", "parentGasUsed": "0", @@ -81,4 +82,4 @@ "withdrawalsRoot": "0xa485a3bd07e29cb8234b5f093d5216eb8b965fb2693c66fea254f6cacef97a6f" } } -} \ No newline at end of file +} diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index a0b7db03d48..cf1a6e1f8a8 100644 --- a/ethereum/referencetests/build.gradle +++ b/ethereum/referencetests/build.gradle @@ -147,11 +147,14 @@ dependencies { implementation project(':crypto:algorithms') implementation project(':datatypes') implementation project(':ethereum:core') + implementation project(':metrics:core') + implementation project(':util') implementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') implementation project(':ethereum:rlp') implementation project(':evm') implementation project(':services:kvstore') + implementation 'io.tmio:tuweni-rlp' implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.google.guava:guava' diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestUpdateAccumulator.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestUpdateAccumulator.java new file mode 100644 index 00000000000..c8349b7f790 --- /dev/null +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestUpdateAccumulator.java @@ -0,0 +1,44 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.referencetests; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.StorageSlotKey; +import org.hyperledger.besu.ethereum.bonsai.BonsaiAccount; +import org.hyperledger.besu.ethereum.bonsai.BonsaiValue; +import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiPreImageProxy; +import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; +import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldView; + +import org.apache.tuweni.bytes.Bytes; + +public class BonsaiReferenceTestUpdateAccumulator extends BonsaiWorldStateUpdateAccumulator { + private final BonsaiPreImageProxy preImageProxy; + + public BonsaiReferenceTestUpdateAccumulator( + final BonsaiWorldView world, + final Consumer> accountPreloader, + final Consumer storagePreloader, + final BonsaiPreImageProxy preImageProxy) { + super(world, accountPreloader, storagePreloader); + this.preImageProxy = preImageProxy; + } + + @Override + protected Hash hashAndSavePreImage(final Bytes bytes) { + // by default do not save hash preImages + return preImageProxy.hashAndSavePreImage(bytes); + } +} diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java new file mode 100644 index 00000000000..e40b3774a97 --- /dev/null +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java @@ -0,0 +1,182 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.referencetests; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoader; +import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiPreImageProxy; +import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogAddedEvent; +import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogFactoryImpl; +import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogManager; +import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldState; +import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.plugin.services.trielogs.TrieLog; +import org.hyperledger.besu.plugin.services.trielogs.TrieLogEvent; +import org.hyperledger.besu.plugin.services.trielogs.TrieLogFactory; +import org.hyperledger.besu.util.Subscribers; + +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; + +import com.fasterxml.jackson.annotation.JsonCreator; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; + +public class BonsaiReferenceTestWorldState extends BonsaiWorldState + implements ReferenceTestWorldState { + + private final BonsaiReferenceTestWorldStateStorage refTestStorage; + private final BonsaiPreImageProxy preImageProxy; + + protected BonsaiReferenceTestWorldState( + final BonsaiReferenceTestWorldStateStorage worldStateStorage, + final CachedMerkleTrieLoader cachedMerkleTrieLoader, + final TrieLogManager trieLogManager, + final BonsaiPreImageProxy preImageProxy) { + super(worldStateStorage, cachedMerkleTrieLoader, trieLogManager); + this.refTestStorage = worldStateStorage; + this.preImageProxy = preImageProxy; + setAccumulator( + new BonsaiReferenceTestUpdateAccumulator( + this, + (addr, value) -> + cachedMerkleTrieLoader.preLoadAccount( + getWorldStateStorage(), worldStateRootHash, addr), + (addr, value) -> + cachedMerkleTrieLoader.preLoadStorageSlot(getWorldStateStorage(), addr, value), + preImageProxy)); + } + + @Override + public ReferenceTestWorldState copy() { + var layerCopy = new BonsaiReferenceTestWorldStateStorage(worldStateStorage, preImageProxy); + return new BonsaiReferenceTestWorldState( + layerCopy, cachedMerkleTrieLoader, trieLogManager, preImageProxy); + } + + @JsonCreator + public static BonsaiReferenceTestWorldState create( + final Map accounts) { + final ObservableMetricsSystem metricsSystem = new NoOpMetricsSystem(); + final CachedMerkleTrieLoader cachedMerkleTrieLoader = new CachedMerkleTrieLoader(metricsSystem); + final TrieLogManager trieLogManager = new NoOpTrieLogManager(); + final BonsaiPreImageProxy preImageProxy = + new BonsaiPreImageProxy.BonsaiReferenceTestPreImageProxy(); + + final BonsaiReferenceTestWorldStateStorage worldStateStorage = + new BonsaiReferenceTestWorldStateStorage( + new BonsaiWorldStateKeyValueStorage( + new InMemoryKeyValueStorageProvider(), metricsSystem), + preImageProxy); + + final BonsaiReferenceTestWorldState worldState = + new BonsaiReferenceTestWorldState( + worldStateStorage, cachedMerkleTrieLoader, trieLogManager, preImageProxy); + + final WorldUpdater updater = worldState.updater(); + for (final Map.Entry entry : accounts.entrySet()) { + ReferenceTestWorldState.insertAccount( + updater, Address.fromHexString(entry.getKey()), entry.getValue()); + } + updater.commit(); + return worldState; + } + + @Override + public Stream streamAccounts(final Bytes32 startKeyHash, final int limit) { + return this.refTestStorage.streamAccounts(this, startKeyHash, limit); + } + + static class NoOpTrieLogManager implements TrieLogManager { + private final Subscribers trieLogObservers = Subscribers.create(); + private final TrieLogFactory trieLogFactory = new TrieLogFactoryImpl(); + + @Override + public void saveTrieLog( + final BonsaiWorldStateUpdateAccumulator localUpdater, + final Hash forWorldStateRootHash, + final BlockHeader forBlockHeader, + final BonsaiWorldState forWorldState) { + // notify trie log added observers, synchronously + TrieLog trieLog = trieLogFactory.create(localUpdater, forBlockHeader); + trieLogObservers.forEach(o -> o.onTrieLogAdded(new TrieLogAddedEvent(trieLog))); + } + + @Override + public void addCachedLayer( + final BlockHeader blockHeader, + final Hash worldStateRootHash, + final BonsaiWorldState forWorldState) {} + + @Override + public boolean containWorldStateStorage(final Hash blockHash) { + return false; + } + + @Override + public Optional getWorldState(final Hash blockHash) { + return Optional.empty(); + } + + @Override + public Optional getNearestWorldState(final BlockHeader blockHeader) { + return Optional.empty(); + } + + @Override + public Optional getHeadWorldState( + final Function> hashBlockHeaderFunction) { + return Optional.empty(); + } + + @Override + public long getMaxLayersToLoad() { + return 0; + } + + @Override + public void reset() {} + + @Override + public Optional getTrieLogLayer(final Hash blockHash) { + return Optional.empty(); + } + + @Override + public synchronized long subscribe(final TrieLogEvent.TrieLogObserver sub) { + return trieLogObservers.subscribe(sub); + } + + @Override + public synchronized void unsubscribe(final long id) { + trieLogObservers.unsubscribe(id); + } + } + + @Override + protected Hash hashAndSavePreImage(final Bytes value) { + // by default do not save has preImages + return preImageProxy.hashAndSavePreImage(value); + } +} diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldStateStorage.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldStateStorage.java new file mode 100644 index 00000000000..b998bf7d25b --- /dev/null +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldStateStorage.java @@ -0,0 +1,85 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.referencetests; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.bonsai.BonsaiAccount; +import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiPreImageProxy; +import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateLayerStorage; +import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldView; +import org.hyperledger.besu.evm.account.AccountStorageEntry; +import org.hyperledger.besu.evm.worldstate.WorldState; + +import java.util.Comparator; +import java.util.NavigableMap; +import java.util.Optional; +import java.util.TreeMap; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.rlp.RLP; +import org.apache.tuweni.units.bigints.UInt256; + +public class BonsaiReferenceTestWorldStateStorage extends BonsaiWorldStateLayerStorage { + private final BonsaiPreImageProxy preImageProxy; + + public BonsaiReferenceTestWorldStateStorage( + final BonsaiWorldStateKeyValueStorage parent, final BonsaiPreImageProxy preImageProxy) { + super(parent); + this.preImageProxy = preImageProxy; + } + + @Override + public NavigableMap storageEntriesFrom( + final Hash addressHash, final Bytes32 startKeyHash, final int limit) { + return streamFlatStorages(addressHash, startKeyHash, UInt256.MAX_VALUE, limit) + .entrySet() + // map back to slot keys using preImage provider: + .stream() + .collect( + Collectors.toMap( + e -> e.getKey(), + e -> + AccountStorageEntry.create( + UInt256.fromBytes(RLP.decodeValue(e.getValue())), + Hash.wrap(e.getKey()), + preImageProxy.getStorageTrieKeyPreimage(e.getKey())), + (a, b) -> a, + TreeMap::new)); + } + + public Stream streamAccounts( + final BonsaiWorldView context, final Bytes32 startKeyHash, final int limit) { + return streamFlatAccounts(startKeyHash, UInt256.MAX_VALUE, limit) + .entrySet() + // map back to addresses using preImage provider: + .stream() + .map( + entry -> + preImageProxy + .getAccountTrieKeyPreimage(entry.getKey()) + .map( + address -> + new WorldState.StreamableAccount( + Optional.of(address), + BonsaiAccount.fromRLP(context, address, entry.getValue(), false)))) + .filter(Optional::isPresent) + .map(Optional::get) + .sorted(Comparator.comparing(account -> account.getAddress().orElse(Address.ZERO))); + } +} diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/DefaultReferenceTestWorldState.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/DefaultReferenceTestWorldState.java new file mode 100644 index 00000000000..ec0b058ba99 --- /dev/null +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/DefaultReferenceTestWorldState.java @@ -0,0 +1,60 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.referencetests; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.DefaultMutableWorldState; +import org.hyperledger.besu.evm.worldstate.WorldState; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonCreator; + +public class DefaultReferenceTestWorldState extends DefaultMutableWorldState + implements ReferenceTestWorldState { + + DefaultReferenceTestWorldState() { + super( + new WorldStateKeyValueStorage(new InMemoryKeyValueStorage()), + new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage())); + } + + public DefaultReferenceTestWorldState(final WorldState worldState) { + super(worldState); + } + + @Override + public ReferenceTestWorldState copy() { + return new DefaultReferenceTestWorldState(this); + } + + @JsonCreator + public static ReferenceTestWorldState create(final Map accounts) { + final ReferenceTestWorldState worldState = new DefaultReferenceTestWorldState(); + final WorldUpdater updater = worldState.updater(); + + for (final Map.Entry entry : accounts.entrySet()) { + ReferenceTestWorldState.insertAccount( + updater, Address.fromHexString(entry.getKey()), entry.getValue()); + } + + updater.commit(); + return worldState; + } +} diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/GeneralStateTestCaseEipSpec.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/GeneralStateTestCaseEipSpec.java index b396eff98f8..def8c14f17e 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/GeneralStateTestCaseEipSpec.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/GeneralStateTestCaseEipSpec.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.evm.worldstate.WorldState; import java.util.function.Supplier; @@ -37,7 +36,7 @@ public class GeneralStateTestCaseEipSpec { // is why this is a supplier: calling get() actually does the signing. private final Supplier transactionSupplier; - private final WorldState initialWorldState; + private final ReferenceTestWorldState initialWorldState; private final Hash expectedRootHash; @@ -54,7 +53,7 @@ public class GeneralStateTestCaseEipSpec { GeneralStateTestCaseEipSpec( final String fork, final Supplier transactionSupplier, - final WorldState initialWorldState, + final ReferenceTestWorldState initialWorldState, final Hash expectedRootHash, final Hash expectedLogsHash, final BlockHeader blockHeader, @@ -78,7 +77,7 @@ public String getFork() { return fork; } - public WorldState getInitialWorldState() { + public ReferenceTestWorldState getInitialWorldState() { return initialWorldState; } diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/GeneralStateTestCaseSpec.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/GeneralStateTestCaseSpec.java index 328922e1876..59f0a86fe09 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/GeneralStateTestCaseSpec.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/GeneralStateTestCaseSpec.java @@ -17,7 +17,10 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; +import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -37,6 +40,7 @@ public class GeneralStateTestCaseSpec { private final Map> finalStateSpecs; + private static final BlockHeaderFunctions MAINNET_FUNCTIONS = new MainnetBlockHeaderFunctions(); @JsonCreator public GeneralStateTestCaseSpec( @@ -49,7 +53,7 @@ public GeneralStateTestCaseSpec( } private Map> generate( - final BlockHeader blockHeader, + final BlockHeader rawBlockHeader, final ReferenceTestWorldState initialWorldState, final Map> postSections, final StateTestVersionedTransaction versionedTransaction) { @@ -62,6 +66,11 @@ private Map> generate( final List post = entry.getValue(); final List specs = new ArrayList<>(post.size()); for (final PostSection p : post) { + final BlockHeader blockHeader = + BlockHeaderBuilder.fromHeader(rawBlockHeader) + .stateRoot(p.rootHash) + .blockHeaderFunctions(MAINNET_FUNCTIONS) + .buildBlockHeader(); final Supplier txSupplier = () -> versionedTransaction.get(p.indexes); specs.add( new GeneralStateTestCaseEipSpec( diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java index 79356331fb6..5f7af60719a 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java @@ -104,6 +104,7 @@ public ReferenceTestEnv( @JsonProperty("currentBaseFee") final String baseFee, @JsonProperty("currentTimestamp") final String timestamp, @JsonProperty("currentRandom") final String random, + @JsonProperty("currentStateRoot") final String stateRoot, @JsonProperty("previousHash") final String previousHash, @JsonProperty("parentDifficulty") final String parentDifficulty, @JsonProperty("parentBaseFee") final String parentBaseFee, @@ -127,7 +128,7 @@ public ReferenceTestEnv( generateTestBlockHash(previousHash, number), Hash.EMPTY_LIST_HASH, // ommersHash Address.fromHexString(coinbase), - Hash.EMPTY, // stateRoot + Optional.ofNullable(stateRoot).map(Hash::fromHexString).orElse(Hash.EMPTY), // stateRoot Hash.EMPTY, // transactionsRoot Hash.EMPTY, // receiptsRoot new LogsBloomFilter(), diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java index 659847c1211..825d7a2cd4b 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java @@ -17,12 +17,9 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DefaultMutableWorldState; +import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.util.HashMap; import java.util.Map; @@ -35,9 +32,9 @@ /** Represent a worldState for testing. */ @JsonIgnoreProperties(ignoreUnknown = true) -public class ReferenceTestWorldState extends DefaultMutableWorldState { +public interface ReferenceTestWorldState extends MutableWorldState { - public static class AccountMock { + class AccountMock { private final long nonce; private final Wei balance; private final Bytes code; @@ -90,22 +87,11 @@ static void insertAccount( } } - @JsonCreator - public static ReferenceTestWorldState create(final Map accounts) { - final ReferenceTestWorldState worldState = new ReferenceTestWorldState(); - final WorldUpdater updater = worldState.updater(); - - for (final Map.Entry entry : accounts.entrySet()) { - insertAccount(updater, Address.fromHexString(entry.getKey()), entry.getValue()); - } + ReferenceTestWorldState copy(); - updater.commit(); - return worldState; - } - - public ReferenceTestWorldState() { - super( - new WorldStateKeyValueStorage(new InMemoryKeyValueStorage()), - new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage())); + @JsonCreator + static ReferenceTestWorldState create(final Map accounts) { + // delegate to a Bonsai reference test world state: + return BonsaiReferenceTestWorldState.create(accounts); } } diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java index e01e08c0414..83388fe2526 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java @@ -21,8 +21,10 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; +import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; @@ -31,6 +33,7 @@ import org.hyperledger.besu.ethereum.referencetests.GeneralStateTestCaseSpec; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestBlockchain; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules; +import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.worldstate.DefaultMutableWorldState; import org.hyperledger.besu.evm.account.Account; @@ -123,7 +126,7 @@ public static Collection generateTestParametersForConfig(final String[ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { final BlockHeader blockHeader = spec.getBlockHeader(); - final WorldState initialWorldState = spec.getInitialWorldState(); + final ReferenceTestWorldState initialWorldState = spec.getInitialWorldState(); final Transaction transaction = spec.getTransaction(); // Sometimes the tests ask us assemble an invalid transaction. If we have @@ -136,7 +139,7 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { return; } - final MutableWorldState worldState = new DefaultMutableWorldState(initialWorldState); + final MutableWorldState worldState = initialWorldState.copy(); // Several of the GeneralStateTests check if the transaction could potentially // consume more gas than is left for the block it's attempted to be included in. // This check is performed within the `BlockImporter` rather than inside the @@ -178,6 +181,7 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { worldStateUpdater.deleteAccount(coinbase.getAddress()); } worldStateUpdater.commit(); + worldState.persist(blockHeader); // Check the world state root hash. final Hash expectedRootHash = spec.getExpectedRootHash(); diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index aedc706bab1..e544419b8ab 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -69,7 +69,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'fPOd/MnNB1PwfTV7HDTXc3oYRcoeUzMJrlzDUdg/HNk=' + knownHash = 'tpSnjt4HgqSiOTJhBbYdB0r1nFX4QZbicjfloI71Wf0=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorage.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorage.java index 6ccdb3b0a24..3d0e9e5efea 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorage.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorage.java @@ -82,6 +82,17 @@ public interface KeyValueStorage extends Closeable { */ Stream> streamFromKey(final byte[] startKey); + /** + * Returns a stream of key-value pairs starting from the specified key, ending at the specified + * key. This method is used to retrieve a stream of data from the storage, starting from the given + * key. If no data is available from the specified key onwards, an empty stream is returned. + * + * @param startKey The key from which the stream should start. + * @param endKey The key at which the stream should stop. + * @return A stream of key-value pairs starting from the specified key. + */ + Stream> streamFromKey(final byte[] startKey, final byte[] endKey); + /** * Returns a stream of all keys. * diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java index 21e6ecca6f6..55d04d470c4 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java @@ -78,6 +78,19 @@ default boolean containsKey(final SegmentIdentifier segment, final byte[] key) Stream> streamFromKey( final SegmentIdentifier segmentIdentifier, final byte[] startKey); + /** + * Returns a stream of key-value pairs starting from the specified key, ending at the specified + * key. This method is used to retrieve a stream of data from the storage, starting from the given + * key. If no data is available from the specified key onwards, an empty stream is returned. + * + * @param segmentIdentifier The segment identifier whose keys we want to stream. + * @param startKey The key from which the stream should start. + * @param endKey The key at which the stream should stop. + * @return A stream of key-value pairs starting from the specified key. + */ + Stream> streamFromKey( + final SegmentIdentifier segmentIdentifier, final byte[] startKey, final byte[] endKey); + /** * Stream keys. * diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java index d51bdb310b8..6a123069001 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java @@ -33,7 +33,6 @@ import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; -import org.apache.tuweni.bytes.Bytes; import org.rocksdb.ColumnFamilyHandle; import org.rocksdb.OptimisticTransactionDB; import org.slf4j.Logger; @@ -83,7 +82,13 @@ public Stream> stream(final SegmentIdentifier segment) { @Override public Stream> streamFromKey( final SegmentIdentifier segment, final byte[] startKey) { - return stream(segment).filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); + return snapTx.streamFromKey(segment, startKey); + } + + @Override + public Stream> streamFromKey( + final SegmentIdentifier segment, final byte[] startKey, final byte[] endKey) { + return snapTx.streamFromKey(segment, startKey, endKey); } @Override diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index 3d98be37523..9462f9bcb14 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -333,6 +333,17 @@ public Stream> streamFromKey( return RocksDbIterator.create(rocksIterator).toStream(); } + @Override + public Stream> streamFromKey( + final SegmentIdentifier segmentIdentifier, final byte[] startKey, final byte[] endKey) { + final Bytes endKeyBytes = Bytes.wrap(endKey); + final RocksIterator rocksIterator = getDB().newIterator(safeColumnHandle(segmentIdentifier)); + rocksIterator.seek(startKey); + return RocksDbIterator.create(rocksIterator) + .toStream() + .takeWhile(e -> endKeyBytes.compareTo(Bytes.wrap(e.getKey())) >= 0); + } + @Override public Stream streamKeys(final SegmentIdentifier segmentIdentifier) { final RocksIterator rocksIterator = getDB().newIterator(safeColumnHandle(segmentIdentifier)); diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBSnapshotTransaction.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBSnapshotTransaction.java index c1c404628d9..0897493eb19 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBSnapshotTransaction.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBSnapshotTransaction.java @@ -28,6 +28,7 @@ import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; +import org.apache.tuweni.bytes.Bytes; import org.rocksdb.ColumnFamilyHandle; import org.rocksdb.OptimisticTransactionDB; import org.rocksdb.ReadOptions; @@ -165,6 +166,48 @@ public Stream streamKeys(final SegmentIdentifier segmentId) { rocksIterator.seekToFirst(); return RocksDbIterator.create(rocksIterator).toStreamKeys(); } + /** + * Returns a stream of key-value pairs starting from the specified key. This method is used to + * retrieve a stream of data reading through the transaction, starting from the given key. If no + * data is available from the specified key onwards, an empty stream is returned. + * + * @param segment The segment identifier whose keys we want to stream. + * @param startKey The key from which the stream should start. + * @return A stream of key-value pairs starting from the specified key. + */ + public Stream> streamFromKey( + final SegmentIdentifier segment, final byte[] startKey) { + throwIfClosed(); + + final RocksIterator rocksIterator = + db.newIterator(columnFamilyMapper.apply(segment), readOptions); + rocksIterator.seek(startKey); + return RocksDbIterator.create(rocksIterator).toStream(); + } + + /** + * Returns a stream of key-value pairs starting from the specified key, ending at the specified + * key. This method is used to retrieve a stream of data reading through the transaction, starting + * from the given key. If no data is available from the specified key onwards, an empty stream is + * returned. + * + * @param segment The segment identifier whose keys we want to stream. + * @param startKey The key from which the stream should start. + * @param endKey The key at which the stream should stop. + * @return A stream of key-value pairs starting from the specified key. + */ + public Stream> streamFromKey( + final SegmentIdentifier segment, final byte[] startKey, final byte[] endKey) { + throwIfClosed(); + final Bytes endKeyBytes = Bytes.wrap(endKey); + + final RocksIterator rocksIterator = + db.newIterator(columnFamilyMapper.apply(segment), readOptions); + rocksIterator.seek(startKey); + return RocksDbIterator.create(rocksIterator) + .toStream() + .takeWhile(e -> endKeyBytes.compareTo(Bytes.wrap(e.getKey())) >= 0); + } @Override public void commit() throws StorageException { diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LayeredKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LayeredKeyValueStorage.java index 9a028becdf8..ffc57530682 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LayeredKeyValueStorage.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LayeredKeyValueStorage.java @@ -122,8 +122,18 @@ public Stream> stream(final SegmentIdentifier segmentId) { @Override public Stream> streamFromKey( final SegmentIdentifier segmentId, final byte[] startKey) { + final Bytes startKeyBytes = Bytes.wrap(startKey); + return stream(segmentId).filter(e -> startKeyBytes.compareTo(Bytes.wrap(e.getKey())) <= 0); + } + + @Override + public Stream> streamFromKey( + final SegmentIdentifier segmentId, final byte[] startKey, final byte[] endKey) { + final Bytes startKeyBytes = Bytes.wrap(startKey); + final Bytes endKeyBytes = Bytes.wrap(endKey); return stream(segmentId) - .filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); + .filter(e -> startKeyBytes.compareTo(Bytes.wrap(e.getKey())) <= 0) + .filter(e -> endKeyBytes.compareTo(Bytes.wrap(e.getKey())) >= 0); } @Override diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java index 7ab04ec26e8..aa52e49284f 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java @@ -118,6 +118,13 @@ public Stream> streamFromKey(final byte[] startKey) { return stream().filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); } + @Override + public Stream> streamFromKey(final byte[] startKey, final byte[] endKey) { + return stream() + .filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0) + .takeWhile(e -> Bytes.wrap(endKey).compareTo(Bytes.wrap(e.getKey())) >= 0); + } + @Override public Stream streamKeys() { final Lock lock = rwLock.readLock(); diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java index adc9a4c71dc..66d70bac4dc 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java @@ -149,8 +149,19 @@ public Stream> stream(final SegmentIdentifier segmentIdenti @Override public Stream> streamFromKey( final SegmentIdentifier segmentIdentifier, final byte[] startKey) { + final Bytes startKeyBytes = Bytes.wrap(startKey); return stream(segmentIdentifier) - .filter(e -> Bytes.wrap(startKey).compareTo(Bytes.wrap(e.getKey())) <= 0); + .filter(e -> startKeyBytes.compareTo(Bytes.wrap(e.getKey())) <= 0); + } + + @Override + public Stream> streamFromKey( + final SegmentIdentifier segmentIdentifier, final byte[] startKey, final byte[] endKey) { + final Bytes startKeyHash = Bytes.wrap(startKey); + final Bytes endKeyHash = Bytes.wrap(endKey); + return stream(segmentIdentifier) + .filter(e -> startKeyHash.compareTo(Bytes.wrap(e.getKey())) <= 0) + .filter(e -> endKeyHash.compareTo(Bytes.wrap(e.getKey())) >= 0); } @Override diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java index 81a492624f2..a02e9284fa6 100644 --- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java +++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java @@ -88,8 +88,14 @@ public Stream> stream() { } @Override - public Stream> streamFromKey(final byte[] startKey) throws StorageException { - return storage.streamFromKey(segmentIdentifier, startKey); + public Stream> streamFromKey(final byte[] startKeyHash) + throws StorageException { + return storage.streamFromKey(segmentIdentifier, startKeyHash); + } + + @Override + public Stream> streamFromKey(final byte[] startKey, final byte[] endKey) { + return storage.streamFromKey(segmentIdentifier, startKey, endKey); } @Override From 32c8e2be448ab430c1369e80b61b2f7a8eca25f4 Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Fri, 15 Sep 2023 05:47:15 +0100 Subject: [PATCH 23/34] Don't start BFT mining coordinators until initial sync has completed (#5861) * Don't start BFT mining coordinators until initial sync has completed Signed-off-by: Matthew Whitehead * Fix unit tests Signed-off-by: Matthew Whitehead * Fix 'enable' logic Signed-off-by: Matthew Whitehead --------- Signed-off-by: Matthew Whitehead Signed-off-by: garyschulte --- .../controller/IbftBesuControllerBuilder.java | 26 ++++++++++++++++++- .../controller/QbftBesuControllerBuilder.java | 26 ++++++++++++++++++- .../common/MigratingMiningCoordinator.java | 1 + .../blockcreation/BftMiningCoordinator.java | 14 +++++++--- .../BftMiningCoordinatorTest.java | 1 + 5 files changed, 63 insertions(+), 5 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index 53d4771b5cc..40765769e6e 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -72,6 +72,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.plugin.services.BesuEvents; import org.hyperledger.besu.util.Subscribers; import java.util.HashMap; @@ -231,7 +232,30 @@ protected MiningCoordinator createMiningCoordinator( blockCreatorFactory, blockchain, bftEventQueue); - ibftMiningCoordinator.enable(); + + if (syncState.isInitialSyncPhaseDone()) { + LOG.info("Starting IBFT mining coordinator"); + ibftMiningCoordinator.enable(); + ibftMiningCoordinator.start(); + } else { + LOG.info("IBFT mining coordinator not starting while initial sync in progress"); + } + + syncState.subscribeCompletionReached( + new BesuEvents.InitialSyncCompletionListener() { + @Override + public void onInitialSyncCompleted() { + LOG.info("Starting IBFT mining coordinator following initial sync"); + ibftMiningCoordinator.enable(); + ibftMiningCoordinator.start(); + } + + @Override + public void onInitialSyncRestart() { + // Nothing to do. The mining coordinator won't be started until + // sync has completed. + } + }); return ibftMiningCoordinator; } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 45fc52f3695..11049e7f3f4 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -82,6 +82,7 @@ import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.plugin.services.BesuEvents; import org.hyperledger.besu.util.Subscribers; import java.util.HashMap; @@ -271,7 +272,30 @@ protected MiningCoordinator createMiningCoordinator( blockCreatorFactory, blockchain, bftEventQueue); - miningCoordinator.enable(); + + if (syncState.isInitialSyncPhaseDone()) { + LOG.info("Starting QBFT mining coordinator"); + miningCoordinator.enable(); + miningCoordinator.start(); + } else { + LOG.info("QBFT mining coordinator not starting while initial sync in progress"); + } + + syncState.subscribeCompletionReached( + new BesuEvents.InitialSyncCompletionListener() { + @Override + public void onInitialSyncCompleted() { + LOG.info("Starting QBFT mining coordinator following initial sync"); + miningCoordinator.enable(); + miningCoordinator.start(); + } + + @Override + public void onInitialSyncRestart() { + // Nothing to do. The mining coordinator won't be started until + // sync has completed. + } + }); return miningCoordinator; } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java index 84fbac198a5..de3fc3a3a0f 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java @@ -65,6 +65,7 @@ public void start() { } private void startActiveMiningCoordinator() { + activeMiningCoordinator.enable(); activeMiningCoordinator.start(); if (activeMiningCoordinator instanceof BlockAddedObserver) { ((BlockAddedObserver) activeMiningCoordinator).removeObserver(); diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java index 6158bda8ba3..5107a00fe15 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java @@ -46,7 +46,9 @@ private enum State { /** Running state. */ RUNNING, /** Stopped state. */ - STOPPED + STOPPED, + /** Paused state. */ + PAUSED, } private static final Logger LOG = LoggerFactory.getLogger(BftMiningCoordinator.class); @@ -61,7 +63,7 @@ private enum State { private final BftExecutors bftExecutors; private long blockAddedObserverId; - private final AtomicReference state = new AtomicReference<>(State.IDLE); + private final AtomicReference state = new AtomicReference<>(State.PAUSED); /** * Instantiates a new Bft mining coordinator. @@ -122,7 +124,13 @@ public void awaitStop() throws InterruptedException { @Override public boolean enable() { - return true; + // Return true if we're already running or idle, or successfully switch to idle + if (state.get() == State.RUNNING + || state.get() == State.IDLE + || state.compareAndSet(State.PAUSED, State.IDLE)) { + return true; + } + return false; } @Override diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinatorTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinatorTest.java index 5af20546941..5b1d7a3cf64 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinatorTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinatorTest.java @@ -75,6 +75,7 @@ public void stopsMining() { bftMiningCoordinator.stop(); verify(bftProcessor, never()).stop(); + bftMiningCoordinator.enable(); bftMiningCoordinator.start(); bftMiningCoordinator.stop(); verify(bftProcessor).stop(); From 5770fd9d6da521d2ac7aa322bd84644833e09226 Mon Sep 17 00:00:00 2001 From: matkt Date: Fri, 15 Sep 2023 08:26:44 +0200 Subject: [PATCH 24/34] display only peers ready for requets on ethstats (#5880) * display only ready for requets peers in ethstats Signed-off-by: Karim TAAM * cast to int Signed-off-by: Sally MacFarlane --------- Signed-off-by: Karim TAAM Signed-off-by: Sally MacFarlane Co-authored-by: Sally MacFarlane Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Signed-off-by: garyschulte --- .../java/org/hyperledger/besu/ethstats/EthStatsService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java index 5adbf8978fb..0fa93e1b68c 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/EthStatsService.java @@ -424,7 +424,9 @@ private void sendNodeStatsReport() { final boolean isSyncing = syncState.isInSync(); final long gasPrice = suggestGasPrice(blockchainQueries.getBlockchain().getChainHeadBlock()); final long hashrate = miningCoordinator.hashesPerSecond().orElse(0L); - final int peersNumber = protocolManager.ethContext().getEthPeers().peerCount(); + // safe to cast to int since it isn't realistic to have more than max int peers + final int peersNumber = + (int) protocolManager.ethContext().getEthPeers().streamAvailablePeers().count(); final NodeStatsReport nodeStatsReport = ImmutableNodeStatsReport.builder() From ec846e29593fd42ae59313a87e38af9b228042f9 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Fri, 15 Sep 2023 16:59:06 +1000 Subject: [PATCH 25/34] [MINOR] test RLP used for encode/decode blob tx should contain to field (#5883) * validate to field on encode/decode for blob tx Signed-off-by: Sally MacFarlane * revert decode/encode checks - tis done later in tx validation Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane Signed-off-by: garyschulte --- .../ethereum/core/encoding/BlobTransactionEncodingTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java index 49461a75303..9487e476685 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java @@ -37,9 +37,9 @@ private static Stream provideOpaqueBytesNoBlobsWithCommitments() { createArgument( "0x03f89d850120b996ed3685012a1a646085012a1a64608303345094ffb38a7a99e3e2335be83fc74b7faa19d55312418308a80280c085012a1a6460e1a00153a6a1e053cf4c5a09e84088ed8ad7cb53d76c8168f1b82f7cfebfcd06da1a01a007785223eec68459d72265f10bdb30ec3415252a63100605a03142fa211ebbe9a07dbbf9e081fa7b9a01202e4d9ee0e0e513f80efbbab6c784635429905389ce86"), createArgument( - "0x03f889850120b996ed81f0847735940084b2d05e158307a1208001855f495f4955c084b2d05e15e1a001d343d3cd62abd9c5754cbe5128c25ea90786a8ae75fb79c8cf95f4dcdd08ec80a014103732b5a9789bbf5ea859ed904155398abbef343f8fd63007efb70795d382a07272e847382789a092eadf08e2b9002e727376f8466fff0e4d4639fd60a528f2"), + "0x03f89d850120b996ed81f0847735940084b2d05e158307a12094000000000000000000000000000000000010101001855f495f4955c084b2d05e15e1a001d343d3cd62abd9c5754cbe5128c25ea90786a8ae75fb79c8cf95f4dcdd08ec80a014103732b5a9789bbf5ea859ed904155398abbef343f8fd63007efb70795d382a07272e847382789a092eadf08e2b9002e727376f8466fff0e4d4639fd60a528f2"), createArgument( - "0x03f889850120b996ed81f1843b9aca00847735940e8307a1208001855f495f4955c0847735940ee1a001d552e24560ec2f168be1d4a6385df61c70afe4288f00a3ad172da1a6f2b4f280a0b6690786e5fe79df67dcb60e8a9e8555142c3c96ffd5097c838717f0a7f64129a0112f01ed0cd3b86495f01736fbbc1b793f71565223aa26f093471a4d8605d198"), + "0x03f89d850120b996ed81f1843b9aca00847735940e8307a12094000000000000000000000000000000000010101001855f495f4955c0847735940ee1a001d552e24560ec2f168be1d4a6385df61c70afe4288f00a3ad172da1a6f2b4f280a0b6690786e5fe79df67dcb60e8a9e8555142c3c96ffd5097c838717f0a7f64129a0112f01ed0cd3b86495f01736fbbc1b793f71565223aa26f093471a4d8605d198"), createArgument( "0x03f897850120b996ed80840bebc200843b9aca078303345094c8d369b164361a8961286cfbab3bc10f962185a88080c08411e1a300e1a0011df88a2971c8a7ac494a7ba37ec1acaa1fc1edeeb38c839b5d1693d47b69b080a032f122f06e5802224db4c8a58fd22c75173a713f63f89936f811c144b9e40129a043a2a872cbfa5727007adf6a48febe5f190d2e4cd5ed6122823fb6ff47ecda32")); } From 36df90a15cf32bc81d2b796ba3be1ef6e824810d Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Mon, 18 Sep 2023 01:26:46 +0200 Subject: [PATCH 26/34] Fix: correctly convert percentage options in TOML configuration file (#5886) Signed-off-by: Fabio Di Fabio Signed-off-by: garyschulte --- .../besu/cli/util/TomlConfigFileDefaultProvider.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigFileDefaultProvider.java b/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigFileDefaultProvider.java index 9ec3f1ef640..c765b7f5dfc 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigFileDefaultProvider.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigFileDefaultProvider.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.cli.util; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.util.number.Fraction; import org.hyperledger.besu.util.number.Percentage; import java.io.File; @@ -92,6 +93,8 @@ private String getConfigurationValue(final OptionSpec optionSpec) { defaultValue = getNumericEntryAsString(optionSpec); } else if (optionSpec.type().equals(Percentage.class)) { defaultValue = getNumericEntryAsString(optionSpec); + } else if (optionSpec.type().equals(Fraction.class)) { + defaultValue = getNumericEntryAsString(optionSpec); } else { // else will be treated as String defaultValue = getEntryAsString(optionSpec); } From 8f31b77f6b2f15038427e402622db529546f8059 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 18 Sep 2023 20:08:41 +1000 Subject: [PATCH 27/34] EIP7516 - Add BlobBaseFee opcode to Cancun EVM (#5884) Signed-off-by: Gabriel-Trintinalia Signed-off-by: garyschulte --- .../mainnet/MainnetTransactionProcessor.java | 1 + .../core/MessageFrameTestFixture.java | 7 ++++ .../besu/evmtool/EvmToolCommand.java | 7 ++++ .../org/hyperledger/besu/evm/MainnetEVMs.java | 4 ++ .../besu/evm/fluent/EVMExecutor.java | 13 ++++++ .../besu/evm/frame/MessageFrame.java | 23 +++++++++++ .../hyperledger/besu/evm/frame/TxValues.java | 1 + .../evm/operation/BlobBaseFeeOperation.java | 41 +++++++++++++++++++ .../testutils/TestMessageFrameBuilder.java | 7 ++++ 9 files changed, 104 insertions(+) create mode 100644 evm/src/main/java/org/hyperledger/besu/evm/operation/BlobBaseFeeOperation.java diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 7d235fb3a39..927e4cd8a29 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -363,6 +363,7 @@ public TransactionProcessingResult processTransaction( .initialGas(gasAvailable) .originator(senderAddress) .gasPrice(transactionGasPrice) + .blobGasPrice(blobGasPrice) .sender(senderAddress) .value(transaction.getValue()) .apparentValue(transaction.getValue()) diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java index bfd56cbaa5d..262657872f5 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java @@ -48,6 +48,7 @@ public class MessageFrameTestFixture { private Address originator = DEFAUT_ADDRESS; private Address contract = DEFAUT_ADDRESS; private Wei gasPrice = Wei.ZERO; + private Wei blobGasPrice = Wei.ZERO; private Wei value = Wei.ZERO; private Bytes inputData = Bytes.EMPTY; private Code code = CodeV0.EMPTY_CODE; @@ -117,6 +118,11 @@ public MessageFrameTestFixture gasPrice(final Wei gasPrice) { return this; } + public MessageFrameTestFixture blobGasPrice(final Wei blobGasPrice) { + this.blobGasPrice = blobGasPrice; + return this; + } + public MessageFrameTestFixture value(final Wei value) { this.value = value; return this; @@ -160,6 +166,7 @@ public MessageFrame build() { .address(address) .originator(originator) .gasPrice(gasPrice) + .blobGasPrice(blobGasPrice) .inputData(inputData) .sender(sender) .value(value) diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java index 4c51fc55998..d41dd56093b 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java @@ -116,6 +116,12 @@ void setBytes(final String optionValue) { paramLabel = "") private final Wei gasPriceGWei = Wei.ZERO; + @Option( + names = {"--blob-price"}, + description = "Price of blob gas for this invocation", + paramLabel = "") + private final Wei blobGasPrice = Wei.ZERO; + @Option( names = {"--sender"}, paramLabel = "
", @@ -376,6 +382,7 @@ public void run() { .originator(sender) .sender(sender) .gasPrice(gasPriceGWei) + .blobGasPrice(blobGasPrice) .inputData(callData) .value(ethValue) .apparentValue(ethValue) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java index 3aad40735d8..7884816ecf0 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.evm.operation.AndOperation; import org.hyperledger.besu.evm.operation.BalanceOperation; import org.hyperledger.besu.evm.operation.BaseFeeOperation; +import org.hyperledger.besu.evm.operation.BlobBaseFeeOperation; import org.hyperledger.besu.evm.operation.BlobHashOperation; import org.hyperledger.besu.evm.operation.BlockHashOperation; import org.hyperledger.besu.evm.operation.ByteOperation; @@ -856,6 +857,9 @@ public static void registerCancunOperations( // EIP-6780 nerf self destruct registry.put(new SelfDestructOperation(gasCalculator, true)); + + // EIP-7516 BLOBBASEFEE + registry.put(new BlobBaseFeeOperation(gasCalculator)); } /** diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java index f25d5259b96..9921f56e64b 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java @@ -58,6 +58,7 @@ public class EVMExecutor { private Address receiver = Address.ZERO; private Address sender = Address.ZERO; private Wei gasPriceGWei = Wei.ZERO; + private Wei blobGasPrice = Wei.ZERO; private Bytes callData = Bytes.EMPTY; private Wei ethValue = Wei.ZERO; private Code code = CodeV0.EMPTY_CODE; @@ -354,6 +355,7 @@ public Bytes execute() { .originator(sender) .sender(sender) .gasPrice(gasPriceGWei) + .blobGasPrice(blobGasPrice) .inputData(callData) .value(ethValue) .apparentValue(ethValue) @@ -457,6 +459,17 @@ public EVMExecutor gasPriceGWei(final Wei gasPriceGWei) { return this; } + /** + * Sets Blob Gas price. + * + * @param blobGasPrice the blob gas price g wei + * @return the evm executor + */ + public EVMExecutor blobGasPrice(final Wei blobGasPrice) { + this.blobGasPrice = blobGasPrice; + return this; + } + /** * Sets Call data. * diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java index a315e899b7a..ed711e3f181 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java @@ -1134,6 +1134,15 @@ public Wei getGasPrice() { return txValues.gasPrice(); } + /** + * Returns the current blob gas price. + * + * @return the current blob gas price + */ + public Wei getBlobGasPrice() { + return txValues.blobGasPrice(); + } + /** * Returns the recipient of the sender. * @@ -1365,6 +1374,7 @@ public static class Builder { private Address originator; private Address contract; private Wei gasPrice; + private Wei blobGasPrice = Wei.ZERO; private Bytes inputData; private Address sender; private Wei value; @@ -1472,6 +1482,17 @@ public Builder gasPrice(final Wei gasPrice) { return this; } + /** + * Sets Blob Gas price. + * + * @param blobGasPrice the blob gas price + * @return the builder + */ + public Builder blobGasPrice(final Wei blobGasPrice) { + this.blobGasPrice = blobGasPrice; + return this; + } + /** * Sets Input data. * @@ -1653,6 +1674,7 @@ private void validate() { checkState(worldUpdater != null, "Missing message frame world updater"); checkState(originator != null, "Missing message frame originator"); checkState(gasPrice != null, "Missing message frame getGasRemaining price"); + checkState(blobGasPrice != null, "Missing message frame blob gas price"); checkState(blockValues != null, "Missing message frame block header"); checkState(miningBeneficiary != null, "Missing mining beneficiary"); checkState(blockHashLookup != null, "Missing block hash lookup"); @@ -1689,6 +1711,7 @@ public MessageFrame build() { UndoTable.of(HashBasedTable.create()), originator, gasPrice, + blobGasPrice, blockValues, new ArrayDeque<>(), miningBeneficiary, diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java index 65f7f47b569..6ef1143530f 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java @@ -40,6 +40,7 @@ public record TxValues( UndoTable warmedUpStorage, Address originator, Wei gasPrice, + Wei blobGasPrice, BlockValues blockValues, Deque messageFrameStack, Address miningBeneficiary, diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/BlobBaseFeeOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/BlobBaseFeeOperation.java new file mode 100644 index 00000000000..a7168473882 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/BlobBaseFeeOperation.java @@ -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.evm.operation; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +/** The Blob Base fee operation. */ +public class BlobBaseFeeOperation extends AbstractFixedCostOperation { + + /** + * Instantiates a new Blob Base fee operation. + * + * @param gasCalculator the gas calculator + */ + public BlobBaseFeeOperation(final GasCalculator gasCalculator) { + super(0x4a, "BLOBBASEFEE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost()); + } + + @Override + public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) { + + final Wei blobGasPrice = frame.getBlobGasPrice(); + frame.pushStackItem(blobGasPrice.toBytes()); + return successResponse; + } +} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestMessageFrameBuilder.java b/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestMessageFrameBuilder.java index 0e7fdb50418..f6b2abd69d9 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestMessageFrameBuilder.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/testutils/TestMessageFrameBuilder.java @@ -47,6 +47,7 @@ public class TestMessageFrameBuilder { private Address originator = DEFAUT_ADDRESS; private Address contract = DEFAUT_ADDRESS; private Wei gasPrice = Wei.ZERO; + private Wei blobGasPrice = Wei.ZERO; private Wei value = Wei.ZERO; private Bytes inputData = Bytes.EMPTY; private Code code = CodeV0.EMPTY_CODE; @@ -91,6 +92,11 @@ public TestMessageFrameBuilder gasPrice(final Wei gasPrice) { return this; } + public TestMessageFrameBuilder blobGasPrice(final Wei blobGasPrice) { + this.blobGasPrice = blobGasPrice; + return this; + } + public TestMessageFrameBuilder value(final Wei value) { this.value = value; return this; @@ -145,6 +151,7 @@ public MessageFrame build() { .address(address) .originator(originator) .gasPrice(gasPrice) + .blobGasPrice(blobGasPrice) .inputData(inputData) .sender(sender) .value(value) From cc2904dd27b1cddae52af0af37ec33003a052d62 Mon Sep 17 00:00:00 2001 From: matkt Date: Mon, 18 Sep 2023 17:58:26 +0200 Subject: [PATCH 28/34] Fix snapsync heal (#5838) Signed-off-by: Karim TAAM Signed-off-by: garyschulte --- .../CheckpointDownloaderFactory.java | 2 +- .../sync/snapsync/SnapDownloaderFactory.java | 2 +- .../sync/snapsync/SnapWorldDownloadState.java | 127 +++++----- .../snapsync/SnapWorldStateDownloader.java | 10 +- .../SnapSyncStatePersistenceManager.java | 18 +- .../request/StorageRangeDataRequest.java | 7 +- ...ccountFlatDatabaseHealingRangeRequest.java | 46 ++-- .../heal/AccountTrieNodeHealingRequest.java | 36 ++- ...torageFlatDatabaseHealingRangeRequest.java | 19 +- .../heal/StorageTrieNodeHealingRequest.java | 30 +-- .../request/heal/TrieNodeHealingRequest.java | 2 + .../snapsync/AccountHealingTrackingTest.java | 218 ++++++++++++++++++ .../snapsync/SnapWorldDownloadStateTest.java | 35 ++- ...ntFlatDatabaseHealingRangeRequestTest.java | 4 +- .../StorageTrieNodeHealingRequestTest.java | 3 +- 15 files changed, 415 insertions(+), 144 deletions(-) create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java index 441dcfeb9d5..ff8187d8d21 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java @@ -88,7 +88,7 @@ public static Optional> createCheckpointDownloader( .getAccountToRepair() .ifPresent( address -> - snapContext.addAccountsToBeRepaired( + snapContext.addAccountToHealingList( CompactEncoding.bytesToPath(address.addressHash()))); } else if (fastSyncState.getPivotBlockHeader().isEmpty() && protocolContext.getBlockchain().getChainHeadBlockNumber() diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java index 3f6596cf0b8..65fb117788e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java @@ -83,7 +83,7 @@ public static Optional> createSnapDownloader( .getAccountToRepair() .ifPresent( address -> - snapContext.addAccountsToBeRepaired( + snapContext.addAccountToHealingList( CompactEncoding.bytesToPath(address.addressHash()))); } else if (fastSyncState.getPivotBlockHeader().isEmpty() && protocolContext.getBlockchain().getChainHeadBlockNumber() diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java index 3abd1b0d5ec..dd7481cdd00 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java @@ -28,7 +28,6 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.AccountFlatDatabaseHealingRangeRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.StorageFlatDatabaseHealingRangeRequest; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldDownloadState; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.BesuMetricCategory; @@ -43,6 +42,7 @@ import java.util.List; import java.util.Map; import java.util.OptionalLong; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; @@ -72,7 +72,7 @@ public class SnapWorldDownloadState extends WorldDownloadState protected final InMemoryTasksPriorityQueues pendingStorageFlatDatabaseHealingRequests = new InMemoryTasksPriorityQueues<>(); - private HashSet accountsToBeRepaired = new HashSet<>(); + private HashSet accountsHealingList = new HashSet<>(); private DynamicPivotBlockSelector pivotBlockSelector; private final SnapSyncStatePersistenceManager snapContext; @@ -156,6 +156,7 @@ protected synchronized void markAsStalled(final int maxNodeRequestRetries) { @Override public synchronized boolean checkCompletion(final BlockHeader header) { + // Check if all snapsync tasks are completed if (!internalFuture.isDone() && pendingAccountRequests.allTasksCompleted() && pendingCodeRequests.allTasksCompleted() @@ -164,29 +165,50 @@ public synchronized boolean checkCompletion(final BlockHeader header) { && pendingTrieNodeRequests.allTasksCompleted() && pendingAccountFlatDatabaseHealingRequests.allTasksCompleted() && pendingStorageFlatDatabaseHealingRequests.allTasksCompleted()) { + + // if all snapsync tasks are completed and the healing process was not running if (!snapSyncState.isHealTrieInProgress()) { + // Register blockchain observer if not already registered + blockObserverId = + blockObserverId.isEmpty() + ? OptionalLong.of(blockchain.observeBlockAdded(createBlockchainObserver())) + : blockObserverId; + // Start the healing process startTrieHeal(); - } else if (pivotBlockSelector.isBlockchainBehind()) { + } + // if all snapsync tasks are completed and the healing was running and blockchain is behind + // the pivot block + else if (pivotBlockSelector.isBlockchainBehind()) { LOG.info("Pausing world state download while waiting for sync to complete"); - if (blockObserverId.isEmpty()) - blockObserverId = OptionalLong.of(blockchain.observeBlockAdded(getBlockAddedListener())); + // Set the snapsync to wait for the blockchain to catch up snapSyncState.setWaitingBlockchain(true); - } else if (!snapSyncState.isHealFlatDatabaseInProgress() - && worldStateStorage.getFlatDbMode().equals(FlatDbMode.FULL)) { - // only doing a flat db heal for bonsai - startFlatDatabaseHeal(header); - } else { - final WorldStateStorage.Updater updater = worldStateStorage.updater(); - updater.saveWorldState(header.getHash(), header.getStateRoot(), rootNodeData); - updater.commit(); - metricsManager.notifySnapSyncCompleted(); - snapContext.clear(); - internalFuture.complete(null); - - return true; + } + // if all snapsync tasks are completed and the healing was running and the blockchain is not + // behind the pivot block + else { + // Remove the blockchain observer + blockObserverId.ifPresent(blockchain::removeObserver); + // If the flat database healing process is not in progress and the flat database mode is + // FULL + if (!snapSyncState.isHealFlatDatabaseInProgress() + && worldStateStorage.getFlatDbMode().equals(FlatDbMode.FULL)) { + // Start the flat database healing process + startFlatDatabaseHeal(header); + } + // If the flat database healing process is in progress or the flat database mode is not FULL + else { + final WorldStateStorage.Updater updater = worldStateStorage.updater(); + updater.saveWorldState(header.getHash(), header.getStateRoot(), rootNodeData); + updater.commit(); + // Notify that the snap sync has completed + metricsManager.notifySnapSyncCompleted(); + // Clear the snap context + snapContext.clear(); + internalFuture.complete(null); + return true; + } } } - return false; } @@ -200,10 +222,11 @@ protected synchronized void cleanupQueues() { pendingTrieNodeRequests.clear(); } + /** Method to start the healing process of the trie */ public synchronized void startTrieHeal() { snapContext.clearAccountRangeTasks(); snapSyncState.setHealTrieStatus(true); - // try to find new pivot block before healing + // Try to find a new pivot block before starting the healing process pivotBlockSelector.switchToNewPivotBlock( (blockHeader, newPivotBlockFound) -> { snapContext.clearAccountRangeTasks(); @@ -212,21 +235,25 @@ public synchronized void startTrieHeal() { blockHeader.getNumber()); enqueueRequest( createAccountTrieNodeDataRequest( - blockHeader.getStateRoot(), Bytes.EMPTY, accountsToBeRepaired)); + blockHeader.getStateRoot(), Bytes.EMPTY, accountsHealingList)); }); } + /** Method to reload the healing process of the trie */ public synchronized void reloadTrieHeal() { + // Clear the flat database and trie log from the world state storage if needed worldStateStorage.clearFlatDatabase(); worldStateStorage.clearTrieLog(); + // Clear pending trie node and code requests pendingTrieNodeRequests.clear(); pendingCodeRequests.clear(); + snapSyncState.setHealTrieStatus(false); checkCompletion(snapSyncState.getPivotBlockHeader().orElseThrow()); } public synchronized void startFlatDatabaseHeal(final BlockHeader header) { - LOG.info("Running flat database heal process"); + LOG.info("Initiating the healing process for the flat database"); snapSyncState.setHealFlatDatabaseInProgress(true); final Map ranges = RangeManager.generateAllRanges(16); ranges.forEach( @@ -235,10 +262,6 @@ public synchronized void startFlatDatabaseHeal(final BlockHeader header) { createAccountFlatHealingRangeRequest(header.getStateRoot(), key, value))); } - public boolean isBonsaiStorageFormat() { - return worldStateStorage.getDataStorageFormat().equals(DataStorageFormat.BONSAI); - } - @Override public synchronized void enqueueRequest(final SnapDataRequest request) { if (!internalFuture.isDone()) { @@ -263,8 +286,8 @@ public synchronized void enqueueRequest(final SnapDataRequest request) { } } - public synchronized void setAccountsToBeRepaired(final HashSet accountsToBeRepaired) { - this.accountsToBeRepaired = accountsToBeRepaired; + public synchronized void setAccountsHealingList(final HashSet addAccountToHealingList) { + this.accountsHealingList = addAccountToHealingList; } /** @@ -274,15 +297,15 @@ public synchronized void setAccountsToBeRepaired(final HashSet accountsTo * * @param account The account to be added for repair. */ - public synchronized void addAccountsToBeRepaired(final Bytes account) { - if (!accountsToBeRepaired.contains(account)) { - snapContext.addAccountsToBeRepaired(account); - accountsToBeRepaired.add(account); + public synchronized void addAccountToHealingList(final Bytes account) { + if (!accountsHealingList.contains(account)) { + snapContext.addAccountToHealingList(account); + accountsHealingList.add(account); } } - public HashSet getAccountsToBeRepaired() { - return accountsToBeRepaired; + public HashSet getAccountsHealingList() { + return accountsHealingList; } @Override @@ -385,25 +408,25 @@ public void setPivotBlockSelector(final DynamicPivotBlockSelector pivotBlockSele this.pivotBlockSelector = pivotBlockSelector; } - public BlockAddedObserver getBlockAddedListener() { + public BlockAddedObserver createBlockchainObserver() { return addedBlockContext -> { - if (snapSyncState.isWaitingBlockchain()) { - // if we receive a new pivot block we can restart the heal - pivotBlockSelector.check( - (____, isNewPivotBlock) -> { - if (isNewPivotBlock) { - snapSyncState.setWaitingBlockchain(false); - } - }); - // if we are close to the head we can also restart the heal and finish snapsync - if (!pivotBlockSelector.isBlockchainBehind()) { - snapSyncState.setWaitingBlockchain(false); - } - if (!snapSyncState.isWaitingBlockchain()) { - blockObserverId.ifPresent(blockchain::removeObserver); - blockObserverId = OptionalLong.empty(); - reloadTrieHeal(); - } + final AtomicBoolean foundNewPivotBlock = new AtomicBoolean(false); + pivotBlockSelector.check( + (____, isNewPivotBlock) -> { + if (isNewPivotBlock) { + foundNewPivotBlock.set(true); + } + }); + + final boolean isNewPivotBlockFound = foundNewPivotBlock.get(); + final boolean isBlockchainCaughtUp = + snapSyncState.isWaitingBlockchain() && !pivotBlockSelector.isBlockchainBehind(); + + if (isNewPivotBlockFound + || isBlockchainCaughtUp) { // restart heal if we found a new pivot block or if close to + // head again + snapSyncState.setWaitingBlockchain(false); + reloadTrieHeal(); } }; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java index ca2afbab347..91bdd83a0f3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java @@ -153,10 +153,10 @@ public CompletableFuture run( final List currentAccountRange = snapContext.getCurrentAccountRange(); - final HashSet inconsistentAccounts = snapContext.getAccountsToBeRepaired(); + final HashSet inconsistentAccounts = snapContext.getAccountsHealingList(); if (!currentAccountRange.isEmpty()) { // continue to download worldstate ranges - newDownloadState.setAccountsToBeRepaired(inconsistentAccounts); + newDownloadState.setAccountsHealingList(inconsistentAccounts); snapContext .getCurrentAccountRange() .forEach( @@ -165,14 +165,14 @@ public CompletableFuture run( DOWNLOAD, snapDataRequest.getStartKeyHash(), snapDataRequest.getEndKeyHash()); newDownloadState.enqueueRequest(snapDataRequest); }); - } else if (!snapContext.getAccountsToBeRepaired().isEmpty()) { // restart only the heal step + } else if (!snapContext.getAccountsHealingList().isEmpty()) { // restart only the heal step snapSyncState.setHealTrieStatus(true); worldStateStorage.clearFlatDatabase(); worldStateStorage.clearTrieLog(); - newDownloadState.setAccountsToBeRepaired(inconsistentAccounts); + newDownloadState.setAccountsHealingList(inconsistentAccounts); newDownloadState.enqueueRequest( SnapDataRequest.createAccountTrieNodeDataRequest( - stateRoot, Bytes.EMPTY, snapContext.getAccountsToBeRepaired())); + stateRoot, Bytes.EMPTY, snapContext.getAccountsHealingList())); } else { // start from scratch worldStateStorage.clear(); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/context/SnapSyncStatePersistenceManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/context/SnapSyncStatePersistenceManager.java index d038c3d4ba3..75ee91352ad 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/context/SnapSyncStatePersistenceManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/context/SnapSyncStatePersistenceManager.java @@ -41,7 +41,7 @@ */ public class SnapSyncStatePersistenceManager { - private final byte[] SNAP_ACCOUNT_TO_BE_REPAIRED_INDEX = + private final byte[] SNAP_ACCOUNT_HEALING_LIST_INDEX = "snapInconsistentAccountsStorageIndex".getBytes(StandardCharsets.UTF_8); private final GenericKeyValueStorageFacade @@ -104,20 +104,20 @@ public void updatePersistedTasks(final List accountRa } /** - * Persists the current accounts to be repaired in the database. + * Persists the current accounts to heal in the database. * - * @param accountsToBeRepaired The current list of accounts to persist. + * @param accountsHealingList The current list of accounts to heal. */ - public void addAccountsToBeRepaired(final Bytes accountsToBeRepaired) { + public void addAccountToHealingList(final Bytes accountsHealingList) { final BigInteger index = healContext - .get(SNAP_ACCOUNT_TO_BE_REPAIRED_INDEX) + .get(SNAP_ACCOUNT_HEALING_LIST_INDEX) .map(bytes -> new BigInteger(bytes.toArrayUnsafe()).add(BigInteger.ONE)) .orElse(BigInteger.ZERO); healContext.putAll( keyValueStorageTransaction -> { - keyValueStorageTransaction.put(SNAP_ACCOUNT_TO_BE_REPAIRED_INDEX, index.toByteArray()); - keyValueStorageTransaction.put(index.toByteArray(), accountsToBeRepaired.toArrayUnsafe()); + keyValueStorageTransaction.put(SNAP_ACCOUNT_HEALING_LIST_INDEX, index.toByteArray()); + keyValueStorageTransaction.put(index.toByteArray(), accountsHealingList.toArrayUnsafe()); }); } @@ -127,9 +127,9 @@ public List getCurrentAccountRange() { .collect(Collectors.toList()); } - public HashSet getAccountsToBeRepaired() { + public HashSet getAccountsHealingList() { return healContext - .streamValuesFromKeysThat(notEqualsTo(SNAP_ACCOUNT_TO_BE_REPAIRED_INDEX)) + .streamValuesFromKeysThat(notEqualsTo(SNAP_ACCOUNT_HEALING_LIST_INDEX)) .collect(Collectors.toCollection(HashSet::new)); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java index 58c1702cbf5..c18d063d74d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java @@ -124,6 +124,11 @@ public void addResponse( if (!slots.isEmpty() || !proofs.isEmpty()) { if (!worldStateProofProvider.isValidRangeProof( startKeyHash, endKeyHash, storageRoot, proofs, slots)) { + // If the proof is invalid, it means that the storage will be a mix of several blocks. + // Therefore, it will be necessary to heal the account's storage subsequently + downloadState.addAccountToHealingList(CompactEncoding.bytesToPath(accountHash)); + // We will request the new storage root of the account because it is apparently no longer + // valid with the new pivot block. downloadState.enqueueRequest( createAccountDataRequest( getRootHash(), Hash.wrap(accountHash), startKeyHash, endKeyHash)); @@ -173,7 +178,7 @@ public Stream getChildRequests( }); if (startKeyHash.equals(MIN_RANGE) && endKeyHash.equals(MAX_RANGE)) { // need to heal this account storage - downloadState.addAccountsToBeRepaired(CompactEncoding.bytesToPath(accountHash)); + downloadState.addAccountToHealingList(CompactEncoding.bytesToPath(accountHash)); } }); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequest.java index c96b39e44c6..a40a4fb11a3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequest.java @@ -59,7 +59,7 @@ public class AccountFlatDatabaseHealingRangeRequest extends SnapDataRequest { private final Bytes32 endKeyHash; private TreeMap existingAccounts; - private TreeMap removedAccounts; + private TreeMap flatDbAccounts; private boolean isProofValid; public AccountFlatDatabaseHealingRangeRequest( @@ -68,7 +68,7 @@ public AccountFlatDatabaseHealingRangeRequest( this.startKeyHash = startKeyHash; this.endKeyHash = endKeyHash; this.existingAccounts = new TreeMap<>(); - this.removedAccounts = new TreeMap<>(); + this.flatDbAccounts = new TreeMap<>(); this.isProofValid = false; } @@ -95,12 +95,12 @@ public Stream getChildRequests( downloadState.getMetricsManager().notifyRangeProgress(HEAL_FLAT, endKeyHash, endKeyHash); } - Stream.of(existingAccounts.entrySet(), removedAccounts.entrySet()) + Stream.of(existingAccounts.entrySet(), flatDbAccounts.entrySet()) .flatMap(Collection::stream) .forEach( account -> { if (downloadState - .getAccountsToBeRepaired() + .getAccountsHealingList() .contains(CompactEncoding.bytesToPath(account.getKey()))) { final StateTrieAccountValue accountValue = StateTrieAccountValue.readFrom(RLP.input(account.getValue())); @@ -174,7 +174,7 @@ protected int doPersist( // put all flat accounts in the list, and gradually keep only those that are not in the trie // to remove and heal them. - removedAccounts = new TreeMap<>(existingAccounts); + flatDbAccounts = new TreeMap<>(existingAccounts); final TrieIterator visitor = RangeStorageEntriesCollector.createVisitor(collector); existingAccounts = @@ -184,27 +184,33 @@ protected int doPersist( RangeStorageEntriesCollector.collectEntries( collector, visitor, root, startKeyHash)); - // doing the fix + // Process each existing account existingAccounts.forEach( (key, value) -> { - if (removedAccounts.containsKey(key)) { - removedAccounts.remove(key); - } else { - final Hash accountHash = Hash.wrap(key); - // if the account was missing in the flat db we need to heal the storage - downloadState.addAccountsToBeRepaired(CompactEncoding.bytesToPath(accountHash)); + // Remove the key from the flat db list and get its associated value + Bytes flatDbEntry = flatDbAccounts.remove(key); + // If the key was in flat db and its associated value is different from the + // current value + if (!value.equals(flatDbEntry)) { + Hash accountHash = Hash.wrap(key); + // Add the account to the list of accounts to be repaired + downloadState.addAccountToHealingList(CompactEncoding.bytesToPath(accountHash)); + // Update the account info state bonsaiUpdater.putAccountInfoState(accountHash, value); } }); - removedAccounts.forEach( - (key, value) -> { - final Hash accountHash = Hash.wrap(key); - // if the account was removed we will have to heal the storage - downloadState.addAccountsToBeRepaired(CompactEncoding.bytesToPath(accountHash)); - bonsaiUpdater.removeAccountInfoState(accountHash); - }); + // For each remaining account in flat db list, remove the account info state and add it to + // the list of accounts to be repaired + flatDbAccounts + .keySet() + .forEach( + key -> { + Hash accountHash = Hash.wrap(key); + downloadState.addAccountToHealingList(CompactEncoding.bytesToPath(accountHash)); + bonsaiUpdater.removeAccountInfoState(accountHash); + }); } - return existingAccounts.size() + removedAccounts.size(); + return existingAccounts.size() + flatDbAccounts.size(); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountTrieNodeHealingRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountTrieNodeHealingRequest.java index 07089b20878..d9297217146 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountTrieNodeHealingRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountTrieNodeHealingRequest.java @@ -112,6 +112,15 @@ public Stream getRootStorageRequests(final WorldStateStorage wo account.size() - getLocation().size())) .map(RLP::input) .map(StateTrieAccountValue::readFrom) + .filter( + stateTrieAccountValue -> + // We need to ensure that the accounts to be healed do not have empty storage. + // Therefore, it is unnecessary to create trie heal requests for storage in this + // case. + // If we were to do so, we would be attempting to request storage that does not + // exist from our peers, + // which would cause sync issues. + !stateTrieAccountValue.getStorageRoot().equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) .ifPresent( stateTrieAccountValue -> { // an account need a heal step @@ -129,6 +138,7 @@ public Stream getRootStorageRequests(final WorldStateStorage wo @Override protected Stream getRequestsFromTrieNodeValue( final WorldStateStorage worldStateStorage, + final SnapWorldDownloadState downloadState, final Bytes location, final Bytes path, final Bytes value) { @@ -151,13 +161,25 @@ protected Stream getRequestsFromTrieNodeValue( if (!accountValue.getCodeHash().equals(Hash.EMPTY)) { builder.add(createBytecodeRequest(accountHash, getRootHash(), accountValue.getCodeHash())); } - // Add storage, if appropriate - if (!accountValue.getStorageRoot().equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { - // If we detect an account storage we fill it with snapsync before completing with a heal - final SnapDataRequest storageTrieRequest = - createStorageTrieNodeDataRequest( - accountValue.getStorageRoot(), accountHash, getRootHash(), Bytes.EMPTY); - builder.add(storageTrieRequest); + + // Retrieve the storage root from the database, if available + final Hash storageRootFoundInDb = + worldStateStorage + .getTrieNodeUnsafe(Bytes.concatenate(accountHash, Bytes.EMPTY)) + .map(Hash::hash) + .orElse(Hash.wrap(MerkleTrie.EMPTY_TRIE_NODE_HASH)); + if (!storageRootFoundInDb.equals(accountValue.getStorageRoot())) { + // If the storage root is not found in the database, add the account to the list of accounts + // to be repaired + downloadState.addAccountToHealingList(CompactEncoding.bytesToPath(accountHash)); + // If the account's storage root is not empty, + // fill it with trie heal before completing with a flat heal + if (!accountValue.getStorageRoot().equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { + SnapDataRequest storageTrieRequest = + createStorageTrieNodeDataRequest( + accountValue.getStorageRoot(), accountHash, getRootHash(), Bytes.EMPTY); + builder.add(storageTrieRequest); + } } return builder.build(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequest.java index 45380e49985..a94424f023f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequest.java @@ -152,7 +152,7 @@ protected int doPersist( Function.identity(), Function.identity()); - Map remainingKeys = new TreeMap<>(slots); + Map flatDbSlots = new TreeMap<>(slots); // Retrieve the data from the trie in order to know what needs to be fixed in the flat // database @@ -172,18 +172,23 @@ protected int doPersist( RangeStorageEntriesCollector.collectEntries( collector, visitor, root, startKeyHash)); - // Perform the fix by updating the flat database + // Process each slot slots.forEach( (key, value) -> { - if (remainingKeys.containsKey(key)) { - remainingKeys.remove(key); - } else { + // Remove the key from the flat db and get its associated value + final Bytes flatDbEntry = flatDbSlots.remove(key); + // If the key was not in flat db and its associated value is different from the + // current value + if (!value.equals(flatDbEntry)) { + // Update the storage value bonsaiUpdater.putStorageValueBySlotHash( accountHash, Hash.wrap(key), Bytes32.leftPad(RLP.decodeValue(value))); } }); - remainingKeys.forEach( - (key, value) -> bonsaiUpdater.removeStorageValueBySlotHash(accountHash, Hash.wrap(key))); + // For each remaining key, remove the storage value + flatDbSlots + .keySet() + .forEach(key -> bonsaiUpdater.removeStorageValueBySlotHash(accountHash, Hash.wrap(key))); } return slots.size(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java index 779a5a72c8a..ffcdb3e77b7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java @@ -21,8 +21,6 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapWorldDownloadState; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.trie.CompactEncoding; -import org.hyperledger.besu.ethereum.trie.MerkleTrie; -import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; @@ -60,31 +58,8 @@ protected int doPersist( @Override public Optional getExistingData( final SnapWorldDownloadState downloadState, final WorldStateStorage worldStateStorage) { - - final Optional storageTrieNode; - if (worldStateStorage.getDataStorageFormat().equals(DataStorageFormat.FOREST)) { - storageTrieNode = worldStateStorage.getTrieNodeUnsafe(getNodeHash()); - } else { - storageTrieNode = - worldStateStorage.getTrieNodeUnsafe(Bytes.concatenate(getAccountHash(), getLocation())); - } - - if (storageTrieNode.isPresent()) { - return storageTrieNode - .filter(node -> Hash.hash(node).equals(getNodeHash())) - .or( - () -> { // if we have a storage in database but not the good one we will need to fix - // the account later - downloadState.addAccountsToBeRepaired( - CompactEncoding.bytesToPath(getAccountHash())); - return Optional.empty(); - }); - } else { - if (getNodeHash().equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { - return Optional.of(MerkleTrie.EMPTY_TRIE_NODE); - } - return Optional.empty(); - } + return worldStateStorage.getAccountStorageTrieNode( + getAccountHash(), getLocation(), getNodeHash()); } @Override @@ -96,6 +71,7 @@ protected SnapDataRequest createChildNodeDataRequest(final Hash childHash, final @Override protected Stream getRequestsFromTrieNodeValue( final WorldStateStorage worldStateStorage, + final SnapWorldDownloadState downloadState, final Bytes location, final Bytes path, final Bytes value) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java index 2cb8ee3ca8a..c04066141d8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java @@ -104,6 +104,7 @@ public Stream getChildRequests( value -> getRequestsFromTrieNodeValue( worldStateStorage, + downloadState, node.getLocation().orElse(Bytes.EMPTY), node.getPath(), value)) @@ -179,6 +180,7 @@ public Stream getRootStorageRequests(final WorldStateStorage wo protected abstract Stream getRequestsFromTrieNodeValue( final WorldStateStorage worldStateStorage, + final SnapWorldDownloadState downloadState, final Bytes location, final Bytes path, final Bytes value); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java new file mode 100644 index 00000000000..ca39d0c86fe --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java @@ -0,0 +1,218 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.sync.snapsync; + +import static org.hyperledger.besu.ethereum.eth.sync.snapsync.RangeManager.MAX_RANGE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; +import org.hyperledger.besu.ethereum.core.TrieGenerator; +import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; +import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.StorageRangeDataRequest; +import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.StorageTrieNodeHealingRequest; +import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider; +import org.hyperledger.besu.ethereum.rlp.RLP; +import org.hyperledger.besu.ethereum.trie.MerkleTrie; +import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; +import org.hyperledger.besu.ethereum.trie.TrieIterator; +import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; +import org.hyperledger.besu.ethereum.trie.patricia.StoredNodeFactory; +import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; + +import java.util.List; +import java.util.TreeMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +import kotlin.collections.ArrayDeque; +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; + +@ExtendWith(MockitoExtension.class) +public class AccountHealingTrackingTest { + + private final List
accounts = List.of(Address.fromHexString("0xdeadbeef")); + private final WorldStateStorage worldStateStorage = + new BonsaiWorldStateKeyValueStorage( + new InMemoryKeyValueStorageProvider(), new NoOpMetricsSystem()); + + private WorldStateProofProvider worldStateProofProvider; + + private MerkleTrie accountStateTrie; + + @Mock SnapWorldDownloadState snapWorldDownloadState; + + @BeforeEach + public void setup() { + accountStateTrie = + TrieGenerator.generateTrie( + worldStateStorage, + accounts.stream().map(Address::addressHash).collect(Collectors.toList())); + worldStateProofProvider = new WorldStateProofProvider(worldStateStorage); + } + + @Test + void avoidMarkingAccountWhenStorageProofValid() { + + // generate valid proof + final Hash accountHash = Hash.hash(accounts.get(0)); + final StateTrieAccountValue stateTrieAccountValue = + StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow())); + + final StoredMerklePatriciaTrie storageTrie = + new StoredMerklePatriciaTrie<>( + new StoredNodeFactory<>( + (location, hash) -> + worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), + Function.identity(), + Function.identity()), + stateTrieAccountValue.getStorageRoot()); + + final RangeStorageEntriesCollector collector = + RangeStorageEntriesCollector.createCollector(Hash.ZERO, MAX_RANGE, 10, Integer.MAX_VALUE); + final TrieIterator visitor = RangeStorageEntriesCollector.createVisitor(collector); + final TreeMap slots = + (TreeMap) + storageTrie.entriesFrom( + root -> + RangeStorageEntriesCollector.collectEntries( + collector, visitor, root, Hash.ZERO)); + // generate the proof + final List proofs = + worldStateProofProvider.getStorageProofRelatedNodes( + Hash.wrap(storageTrie.getRootHash()), accountHash, Hash.ZERO); + proofs.addAll( + worldStateProofProvider.getStorageProofRelatedNodes( + Hash.wrap(storageTrie.getRootHash()), accountHash, slots.lastKey())); + + final StorageRangeDataRequest storageRangeDataRequest = + SnapDataRequest.createStorageRangeDataRequest( + Hash.wrap(accountStateTrie.getRootHash()), + accountHash, + storageTrie.getRootHash(), + Hash.ZERO, + MAX_RANGE); + storageRangeDataRequest.addResponse( + snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>(proofs)); + storageRangeDataRequest.getChildRequests(snapWorldDownloadState, worldStateStorage, null); + verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class)); + } + + @Test + void markAccountOnInvalidStorageProof() { + final Hash accountHash = Hash.hash(accounts.get(0)); + final StateTrieAccountValue stateTrieAccountValue = + StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow())); + + final List proofs = + List.of( + worldStateStorage + .getAccountStorageTrieNode( + accountHash, Bytes.EMPTY, stateTrieAccountValue.getStorageRoot()) + .get()); + + final StorageRangeDataRequest storageRangeDataRequest = + SnapDataRequest.createStorageRangeDataRequest( + Hash.wrap(accountStateTrie.getRootHash()), + accountHash, + stateTrieAccountValue.getStorageRoot(), + Hash.ZERO, + MAX_RANGE); + storageRangeDataRequest.addResponse( + snapWorldDownloadState, worldStateProofProvider, new TreeMap<>(), new ArrayDeque<>(proofs)); + + verify(snapWorldDownloadState).addAccountToHealingList(any(Bytes.class)); + } + + @Test + void markAccountOnPartialStorageRange() { + // generate valid proof + final Hash accountHash = Hash.hash(accounts.get(0)); + final StateTrieAccountValue stateTrieAccountValue = + StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow())); + + final StoredMerklePatriciaTrie storageTrie = + new StoredMerklePatriciaTrie<>( + new StoredNodeFactory<>( + (location, hash) -> + worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), + Function.identity(), + Function.identity()), + stateTrieAccountValue.getStorageRoot()); + + final RangeStorageEntriesCollector collector = + RangeStorageEntriesCollector.createCollector( + Hash.ZERO, + MAX_RANGE, + 1, + Integer.MAX_VALUE); // limit to 1 in order to have a partial range + final TrieIterator visitor = RangeStorageEntriesCollector.createVisitor(collector); + final TreeMap slots = + (TreeMap) + storageTrie.entriesFrom( + root -> + RangeStorageEntriesCollector.collectEntries( + collector, visitor, root, Hash.ZERO)); + // generate the proof + final List proofs = + worldStateProofProvider.getStorageProofRelatedNodes( + Hash.wrap(storageTrie.getRootHash()), accountHash, Hash.ZERO); + proofs.addAll( + worldStateProofProvider.getStorageProofRelatedNodes( + Hash.wrap(storageTrie.getRootHash()), accountHash, slots.lastKey())); + + final StorageRangeDataRequest storageRangeDataRequest = + SnapDataRequest.createStorageRangeDataRequest( + Hash.wrap(accountStateTrie.getRootHash()), + accountHash, + storageTrie.getRootHash(), + Hash.ZERO, + MAX_RANGE); + storageRangeDataRequest.addResponse( + snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>(proofs)); + verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class)); + + // should mark during the getchild request + storageRangeDataRequest.getChildRequests(snapWorldDownloadState, worldStateStorage, null); + verify(snapWorldDownloadState).addAccountToHealingList(any(Bytes.class)); + } + + @Test + void avoidMarkingAccountOnValidStorageTrieNodeDetection() { + final Hash accountHash = Hash.hash(accounts.get(0)); + final StateTrieAccountValue stateTrieAccountValue = + StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow())); + final StorageTrieNodeHealingRequest storageTrieNodeHealingRequest = + SnapDataRequest.createStorageTrieNodeDataRequest( + stateTrieAccountValue.getStorageRoot(), + accountHash, + Hash.wrap(accountStateTrie.getRootHash()), + Bytes.EMPTY); + storageTrieNodeHealingRequest.getExistingData(snapWorldDownloadState, worldStateStorage); + verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class)); + } +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java index 14305363cd3..22c2b73765d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java @@ -325,13 +325,12 @@ public void shouldRestartHealWhenNewPivotBlock( @ParameterizedTest @ArgumentsSource(SnapWorldDownloadStateTestArguments.class) - public void shouldWaitingBlockchainWhenTooBehind( + public void shouldListeningBlockchainDuringHeal( final DataStorageFormat storageFormat, final boolean isFlatDbHealingEnabled) { setUp(storageFormat); - when(snapSyncState.isHealTrieInProgress()).thenReturn(true); + when(snapSyncState.isHealTrieInProgress()).thenReturn(false); downloadState.setPivotBlockSelector(dynamicPivotBlockManager); - when(dynamicPivotBlockManager.isBlockchainBehind()).thenReturn(true); downloadState.checkCompletion(header); @@ -339,7 +338,7 @@ public void shouldWaitingBlockchainWhenTooBehind( // should register only one time verify(blockchain, times(1)).observeBlockAdded(any()); - verify(snapSyncState, atLeastOnce()).setWaitingBlockchain(true); + verify(snapSyncState, atLeastOnce()).setHealTrieStatus(true); assertThat(future).isNotDone(); assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)).isEmpty(); @@ -374,7 +373,14 @@ public void shouldStopWaitingBlockchainWhenNewPivotBlockAvailable( .when(dynamicPivotBlockManager) .check(any()); - final BlockAddedObserver blockAddedListener = downloadState.getBlockAddedListener(); + final Block newBlock = + new Block( + new BlockHeaderTestFixture().number(500).buildHeader(), + new BlockBody(emptyList(), emptyList())); + + when(snapSyncState.getPivotBlockHeader()).thenReturn(Optional.of(newBlock.getHeader())); + + final BlockAddedObserver blockAddedListener = downloadState.createBlockchainObserver(); blockAddedListener.onBlockAdded( BlockAddedEvent.createForHeadAdvancement( new Block( @@ -383,7 +389,9 @@ public void shouldStopWaitingBlockchainWhenNewPivotBlockAvailable( Collections.emptyList(), Collections.emptyList())); + // reload heal verify(snapSyncState).setWaitingBlockchain(false); + verify(snapSyncState).setHealTrieStatus(false); } @ParameterizedTest @@ -395,6 +403,7 @@ public void shouldStopWaitingBlockchainWhenCloseToTheHead( when(snapSyncState.isHealTrieInProgress()).thenReturn(true); downloadState.setPivotBlockSelector(dynamicPivotBlockManager); + when(dynamicPivotBlockManager.isBlockchainBehind()).thenReturn(true); downloadState.checkCompletion(header); @@ -402,17 +411,21 @@ public void shouldStopWaitingBlockchainWhenCloseToTheHead( verify(snapSyncState).setWaitingBlockchain(true); when(snapSyncState.isWaitingBlockchain()).thenReturn(true); + final Block newBlock = + new Block( + new BlockHeaderTestFixture().number(500).buildHeader(), + new BlockBody(emptyList(), emptyList())); + when(dynamicPivotBlockManager.isBlockchainBehind()).thenReturn(false); - final BlockAddedObserver blockAddedListener = downloadState.getBlockAddedListener(); + when(snapSyncState.getPivotBlockHeader()).thenReturn(Optional.of(newBlock.getHeader())); + + final BlockAddedObserver blockAddedListener = downloadState.createBlockchainObserver(); blockAddedListener.onBlockAdded( BlockAddedEvent.createForHeadAdvancement( - new Block( - new BlockHeaderTestFixture().number(500).buildHeader(), - new BlockBody(emptyList(), emptyList())), - Collections.emptyList(), - Collections.emptyList())); + newBlock, Collections.emptyList(), Collections.emptyList())); verify(snapSyncState).setWaitingBlockchain(false); + verify(snapSyncState).setHealTrieStatus(false); } @ParameterizedTest diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java index 0f07056296e..a95d4c34114 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java @@ -67,7 +67,7 @@ public class AccountFlatDatabaseHealingRangeRequestTest { public void setup() { Mockito.when(downloadState.getMetricsManager()) .thenReturn(Mockito.mock(SnapsyncMetricsManager.class)); - Mockito.when(downloadState.getAccountsToBeRepaired()).thenReturn(new HashSet<>()); + Mockito.when(downloadState.getAccountsHealingList()).thenReturn(new HashSet<>()); } @Test @@ -120,7 +120,7 @@ public void shouldReturnChildRequests() { Assertions.assertThat(snapDataRequest.getStartKeyHash()).isGreaterThan(accounts.lastKey()); // Verify that we have storage healing request when the account need to be repaired - Mockito.when(downloadState.getAccountsToBeRepaired()) + Mockito.when(downloadState.getAccountsHealingList()) .thenReturn( new HashSet<>( accounts.keySet().stream() diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java index 14e4d551f72..447b37d14ce 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java @@ -57,7 +57,6 @@ class StorageTrieNodeHealingRequestTest { Address.fromHexString("0xdeadbeeb")); private WorldStateStorage worldStateStorage; - private Hash account0Hash; private Hash account0StorageRoot; @@ -81,6 +80,7 @@ public void setup(final DataStorageFormat storageFormat) { TrieGenerator.generateTrie( worldStateStorage, accounts.stream().map(Address::addressHash).collect(Collectors.toList())); + account0Hash = accounts.get(0).addressHash(); account0StorageRoot = trie.get(account0Hash) @@ -94,6 +94,7 @@ public void setup(final DataStorageFormat storageFormat) { @ArgumentsSource(StorageFormatArguments.class) void shouldDetectExistingData(final DataStorageFormat storageFormat) { setup(storageFormat); + final StorageTrieNodeHealingRequest request = new StorageTrieNodeHealingRequest( account0StorageRoot, account0Hash, Hash.EMPTY, Bytes.EMPTY); From ea9a6d6dbf53125786314fa938f2dc12ba1dbd6b Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 19 Sep 2023 10:04:51 -0600 Subject: [PATCH 29/34] Upgrade besu-native (#5893) Upgrade besu-native to 0.8.2 Signed-off-by: Danno Ferrin Signed-off-by: garyschulte --- gradle/verification-metadata.xml | 66 ++++++++++++++++++++++++++++++++ gradle/versions.gradle | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 19dd9582b90..f9abaf556a3 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4167,6 +4167,17 @@ + + + + + + + + + + + @@ -4178,6 +4189,17 @@ + + + + + + + + + + + @@ -4189,6 +4211,17 @@ + + + + + + + + + + + @@ -4200,6 +4233,17 @@ + + + + + + + + + + + @@ -4211,6 +4255,17 @@ + + + + + + + + + + + @@ -4222,6 +4277,17 @@ + + + + + + + + + + + diff --git a/gradle/versions.gradle b/gradle/versions.gradle index dc6bdb97da9..1548ca5baee 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -160,7 +160,7 @@ dependencyManagement { dependency 'org.openjdk.jol:jol-core:0.17' dependency 'tech.pegasys:jc-kzg-4844:0.7.0' - dependencySet(group: 'org.hyperledger.besu', version: '0.8.1') { + dependencySet(group: 'org.hyperledger.besu', version: '0.8.2') { entry 'arithmetic' entry 'ipa-multipoint' entry 'bls12-381' From c8bb644257f11fc1dbe68fa9a012e4c9fd8dddf9 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 19 Sep 2023 21:06:42 +0200 Subject: [PATCH 30/34] Tune G1GC to reduce Besu memory footprint (#5879) Signed-off-by: Fabio Di Fabio Signed-off-by: garyschulte --- CHANGELOG.md | 1 + build.gradle | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad2cc26475f..c6a1af9b925 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ### Additions and Improvements - Layered transaction pool implementation is now stable and enabled by default. If you want still to use the legacy implementation, use `--tx-pool=legacy` [#5772](https://github.com/hyperledger/besu) +- Tune G1GC to reduce Besu memory footprint, and new `besu-untuned` start scripts to run without any specific G1GC flags [#5879](https://github.com/hyperledger/besu/pull/5879) ### Bug Fixes - do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) diff --git a/build.gradle b/build.gradle index 05f32e6c2e6..8ce41eb46f1 100644 --- a/build.gradle +++ b/build.gradle @@ -551,6 +551,22 @@ def tweakStartScript(createScriptTask) { } startScripts { + defaultJvmOpts = applicationDefaultJvmArgs + [ + "-XX:G1ConcRefinementThreads=2", + "-XX:G1HeapWastePercent=15", + "-XX:MaxGCPauseMillis=100" + ] + unixStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/unixStartScript.txt") + windowsStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/windowsStartScript.txt") + doLast { tweakStartScript(startScripts) } +} + +task untunedStartScripts(type: CreateStartScripts) { + mainClass = 'org.hyperledger.besu.Besu' + classpath = startScripts.classpath + outputDir = startScripts.outputDir + applicationName = 'besu-untuned' + defaultJvmOpts = applicationDefaultJvmArgs unixStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/unixStartScript.txt") windowsStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/windowsStartScript.txt") doLast { tweakStartScript(startScripts) } @@ -587,10 +603,10 @@ task autocomplete(type: JavaExec) { } } -installDist { dependsOn checkLicenses, evmToolStartScripts } +installDist { dependsOn checkLicenses, untunedStartScripts, evmToolStartScripts } distTar { - dependsOn checkLicenses, autocomplete, evmToolStartScripts + dependsOn checkLicenses, autocomplete, untunedStartScripts, evmToolStartScripts doFirst { delete fileTree(dir: 'build/distributions', include: '*.tar.gz') } @@ -599,7 +615,7 @@ distTar { } distZip { - dependsOn checkLicenses, autocomplete, evmToolStartScripts + dependsOn checkLicenses, autocomplete, untunedStartScripts, evmToolStartScripts doFirst { delete fileTree(dir: 'build/distributions', include: '*.zip') } From d4aeaea879dd3a06ae19ec2cd2c2404e49928e3e Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 19 Sep 2023 17:07:09 -0600 Subject: [PATCH 31/34] Add updated storage to evmtool json trace (#5892) Add the EIP-3155 "storage" option to the standard tracer, with the caveat only updated storage is logged. Signed-off-by: Danno Ferrin Signed-off-by: garyschulte --- .../internal/processor/TransactionTracer.java | 36 +++++----- .../besu/evmtool/EvmToolCommand.java | 14 +++- .../besu/evmtool/StateTestSubCommand.java | 3 +- .../besu/evmtool/T8nSubCommand.java | 3 +- .../besu/evm/tracing/StandardJsonTracer.java | 57 +++++++++++++--- .../besu/evm/StandardJsonTracerTest.java | 68 ++++++++++++++----- .../besu/evm/toy/EvmToyCommand.java | 9 ++- 7 files changed, 140 insertions(+), 50 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java index 71628c88969..2811a01135b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java @@ -69,24 +69,22 @@ public Optional traceTransaction( final Hash blockHash, final Hash transactionHash, final DebugOperationTracer tracer) { - Optional transactionTrace = - blockReplay.beforeTransactionInBlock( - mutableWorldState, - blockHash, - transactionHash, - (transaction, header, blockchain, transactionProcessor, blobGasPrice) -> { - final TransactionProcessingResult result = - processTransaction( - header, - blockchain, - mutableWorldState.updater(), - transaction, - transactionProcessor, - tracer, - blobGasPrice); - return new TransactionTrace(transaction, result, tracer.getTraceFrames()); - }); - return transactionTrace; + return blockReplay.beforeTransactionInBlock( + mutableWorldState, + blockHash, + transactionHash, + (transaction, header, blockchain, transactionProcessor, blobGasPrice) -> { + final TransactionProcessingResult result = + processTransaction( + header, + blockchain, + mutableWorldState.updater(), + transaction, + transactionProcessor, + tracer, + blobGasPrice); + return new TransactionTrace(transaction, result, tracer.getTraceFrames()); + }); } public List traceTransactionToFile( @@ -139,7 +137,7 @@ public List traceTransactionToFile( stackedUpdater, transaction, transactionProcessor, - new StandardJsonTracer(out, showMemory, true, true), + new StandardJsonTracer(out, showMemory, true, true, false), blobGasPrice); out.println( summaryTrace( diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java index d41dd56093b..0e2daf96eb6 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java @@ -181,6 +181,14 @@ void setBytes(final String optionValue) { negatable = true) final Boolean showReturnData = false; + @Option( + names = {"--trace.storage"}, + description = + "Show the updated storage slots for the current account. Default is to not show updated storage.", + scope = INHERIT, + negatable = true) + final Boolean showStorage = false; + @Option( names = {"--notime"}, description = "Don't include time data in summary output.", @@ -365,7 +373,7 @@ public void run() { final OperationTracer tracer = // You should have picked Mercy. lastLoop && showJsonResults - ? new StandardJsonTracer(out, showMemory, !hideStack, showReturnData) + ? new StandardJsonTracer(out, showMemory, !hideStack, showReturnData, showStorage) : OperationTracer.NO_TRACING; WorldUpdater updater = component.getWorldUpdater(); @@ -466,10 +474,10 @@ public static void dumpWorldState(final WorldState worldState, final PrintWriter " \"" + accountStorageEntry .getKey() - .map(UInt256::toHexString) + .map(UInt256::toQuantityHexString) .orElse("-") + "\": \"" - + accountStorageEntry.getValue().toHexString() + + accountStorageEntry.getValue().toQuantityHexString() + "\"") .toList())); out.println(" },"); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java index 2bc5f815309..a2d966f0675 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java @@ -182,7 +182,8 @@ private void traceTestSpecs(final String test, final List stack; @@ -52,6 +53,7 @@ public class StandardJsonTracer implements OperationTracer { private Bytes memory; private int memorySize; private int depth; + private String storageString; /** * Instantiates a new Standard json tracer. @@ -60,16 +62,19 @@ public class StandardJsonTracer implements OperationTracer { * @param showMemory show memory in trace lines * @param showStack show the stack in trace lines * @param showReturnData show return data in trace lines + * @param showStorage show the updated storage */ public StandardJsonTracer( final PrintWriter out, final boolean showMemory, final boolean showStack, - final boolean showReturnData) { + final boolean showReturnData, + final boolean showStorage) { this.out = out; this.showMemory = showMemory; this.showStack = showStack; this.showReturnData = showReturnData; + this.showStorage = showStorage; } /** @@ -79,13 +84,20 @@ public StandardJsonTracer( * @param showMemory show memory in trace lines * @param showStack show the stack in trace lines * @param showReturnData show return data in trace lines + * @param showStorage show updated storage */ public StandardJsonTracer( final PrintStream out, final boolean showMemory, final boolean showStack, - final boolean showReturnData) { - this(new PrintWriter(out, true, StandardCharsets.UTF_8), showMemory, showStack, showReturnData); + final boolean showReturnData, + final boolean showStorage) { + this( + new PrintWriter(out, true, StandardCharsets.UTF_8), + showMemory, + showStack, + showReturnData, + showStorage); } /** @@ -130,6 +142,33 @@ public void tracePreExecution(final MessageFrame messageFrame) { memory = null; } depth = messageFrame.getMessageStackSize(); + + StringBuilder sb = new StringBuilder(); + if (showStorage) { + var updater = messageFrame.getWorldUpdater(); + var account = updater.getAccount(messageFrame.getRecipientAddress()); + if (account != null && !account.getUpdatedStorage().isEmpty()) { + boolean[] shownEntry = {false}; + sb.append(",\"storage\":{"); + account + .getUpdatedStorage() + .forEach( + (k, v) -> { + if (shownEntry[0]) { + sb.append(","); + } else { + shownEntry[0] = true; + } + sb.append("\"") + .append(k.toQuantityHexString()) + .append("\":\"") + .append(v.toQuantityHexString()) + .append("\""); + }); + sb.append("}"); + } + } + storageString = sb.toString(); } @Override @@ -155,7 +194,7 @@ public void tracePostExecution( if (showStack) { sb.append("\"stack\":[").append(commaJoiner.join(stack)).append("],"); } - if (showReturnData && returnData.size() > 0) { + if (showReturnData && !returnData.isEmpty()) { sb.append("\"returnData\":\"").append(returnData.toHexString()).append("\","); } sb.append("\"depth\":").append(depth).append(","); @@ -164,14 +203,14 @@ public void tracePostExecution( if (executeResult.getHaltReason() != null) { sb.append(",\"error\":\"") .append(executeResult.getHaltReason().getDescription()) - .append("\"}"); + .append("\""); } else if (messageFrame.getRevertReason().isPresent()) { sb.append(",\"error\":\"") .append(quoteEscape(messageFrame.getRevertReason().orElse(Bytes.EMPTY))) - .append("\"}"); - } else { - sb.append("}"); + .append("\""); } + + sb.append(storageString).append("}"); out.println(sb); } @@ -229,7 +268,7 @@ public void traceEndTransaction( final long timeNs) { final StringBuilder sb = new StringBuilder(1024); sb.append("{"); - if (output.size() > 0) { + if (!output.isEmpty()) { sb.append("\"output\":\"").append(output.toShortHexString()).append("\","); } else { sb.append("\"output\":\"\","); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java b/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java index a65ab05d62a..9ba9ebf96ae 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java @@ -38,7 +38,7 @@ void eip3155ModifiedTestCase() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream out = new PrintStream(baos); var executor = EVMExecutor.istanbul(EvmConfiguration.DEFAULT); - StandardJsonTracer tracer = new StandardJsonTracer(out, true, true, true); + StandardJsonTracer tracer = new StandardJsonTracer(out, true, true, true, false); executor.tracer(tracer); executor.gas(10_000_000_000L); @@ -58,20 +58,56 @@ void eip3155ModifiedTestCase() { // (g) if error is zero length or null it is not included. assertThat(baos) .hasToString( - "{\"pc\":0,\"op\":96,\"gas\":\"0x2540be400\",\"gasCost\":\"0x3\",\"memSize\":0,\"stack\":[],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"}\n" - + "{\"pc\":2,\"op\":128,\"gas\":\"0x2540be3fd\",\"gasCost\":\"0x3\",\"memSize\":0,\"stack\":[\"0x40\"],\"depth\":1,\"refund\":0,\"opName\":\"DUP1\"}\n" - + "{\"pc\":3,\"op\":83,\"gas\":\"0x2540be3fa\",\"gasCost\":\"0xc\",\"memSize\":0,\"stack\":[\"0x40\",\"0x40\"],\"depth\":1,\"refund\":0,\"opName\":\"MSTORE8\"}\n" - + "{\"pc\":4,\"op\":96,\"gas\":\"0x2540be3ee\",\"gasCost\":\"0x3\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"}\n" - + "{\"pc\":6,\"op\":96,\"gas\":\"0x2540be3eb\",\"gasCost\":\"0x3\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x40\"],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"}\n" - + "{\"pc\":8,\"op\":85,\"gas\":\"0x2540be3e8\",\"gasCost\":\"0x4e20\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x40\",\"0x40\"],\"depth\":1,\"refund\":0,\"opName\":\"SSTORE\"}\n" - + "{\"pc\":9,\"op\":96,\"gas\":\"0x2540b95c8\",\"gasCost\":\"0x3\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"}\n" - + "{\"pc\":11,\"op\":96,\"gas\":\"0x2540b95c5\",\"gasCost\":\"0x3\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x40\"],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"}\n" - + "{\"pc\":13,\"op\":96,\"gas\":\"0x2540b95c2\",\"gasCost\":\"0x3\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x40\",\"0x0\"],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"}\n" - + "{\"pc\":15,\"op\":96,\"gas\":\"0x2540b95bf\",\"gasCost\":\"0x3\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x40\",\"0x0\",\"0x40\"],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"}\n" - + "{\"pc\":17,\"op\":96,\"gas\":\"0x2540b95bc\",\"gasCost\":\"0x3\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x40\",\"0x0\",\"0x40\",\"0x0\"],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"}\n" - + "{\"pc\":19,\"op\":90,\"gas\":\"0x2540b95b9\",\"gasCost\":\"0x2\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x40\",\"0x0\",\"0x40\",\"0x0\",\"0x2\"],\"depth\":1,\"refund\":0,\"opName\":\"GAS\"}\n" - + "{\"pc\":20,\"op\":250,\"gas\":\"0x2540b95b7\",\"gasCost\":\"0x2bc\",\"memory\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x40\",\"0x0\",\"0x40\",\"0x0\",\"0x2\",\"0x2540b95b7\"],\"depth\":1,\"refund\":0,\"opName\":\"STATICCALL\"}\n" - + "{\"pc\":21,\"op\":96,\"gas\":\"0x2540b92a7\",\"gasCost\":\"0x3\",\"memory\":\"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x1\"],\"returnData\":\"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b\",\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"}\n" - + "{\"pc\":23,\"op\":243,\"gas\":\"0x2540b92a4\",\"gasCost\":\"0x0\",\"memory\":\"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000\",\"memSize\":96,\"stack\":[\"0x1\",\"0x40\"],\"returnData\":\"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b\",\"depth\":1,\"refund\":0,\"opName\":\"RETURN\"}\n"); + """ + {"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":2,"op":128,"gas":"0x2540be3fd","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"DUP1"} + {"pc":3,"op":83,"gas":"0x2540be3fa","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"MSTORE8"} + {"pc":4,"op":96,"gas":"0x2540be3ee","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":6,"op":96,"gas":"0x2540be3eb","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":8,"op":85,"gas":"0x2540be3e8","gasCost":"0x4e20","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"SSTORE"} + {"pc":9,"op":96,"gas":"0x2540b95c8","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":11,"op":96,"gas":"0x2540b95c5","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":13,"op":96,"gas":"0x2540b95c2","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":15,"op":96,"gas":"0x2540b95bf","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":17,"op":96,"gas":"0x2540b95bc","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":19,"op":90,"gas":"0x2540b95b9","gasCost":"0x2","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2"],"depth":1,"refund":0,"opName":"GAS"} + {"pc":20,"op":250,"gas":"0x2540b95b7","gasCost":"0x2bc","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2","0x2540b95b7"],"depth":1,"refund":0,"opName":"STATICCALL"} + {"pc":21,"op":96,"gas":"0x2540b92a7","gasCost":"0x3","memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1"],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"PUSH1"} + {"pc":23,"op":243,"gas":"0x2540b92a4","gasCost":"0x0","memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1","0x40"],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"RETURN"} + """); + } + + @Test + void updatedStorageTestCase() { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(baos); + var executor = EVMExecutor.istanbul(EvmConfiguration.DEFAULT); + StandardJsonTracer tracer = new StandardJsonTracer(out, false, false, false, true); + executor.tracer(tracer); + executor.gas(10_000_000_000L); + + var codeBytes = Bytes.fromHexString("0x604080536040604055604060006040600060025afa6040f3"); + executor.execute(codeBytes, Bytes.EMPTY, Wei.ZERO, Address.ZERO); + + assertThat(baos) + .hasToString( + """ + {"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memSize":0,"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":2,"op":128,"gas":"0x2540be3fd","gasCost":"0x3","memSize":0,"depth":1,"refund":0,"opName":"DUP1"} + {"pc":3,"op":83,"gas":"0x2540be3fa","gasCost":"0xc","memSize":0,"depth":1,"refund":0,"opName":"MSTORE8"} + {"pc":4,"op":96,"gas":"0x2540be3ee","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":6,"op":96,"gas":"0x2540be3eb","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":8,"op":85,"gas":"0x2540be3e8","gasCost":"0x4e20","memSize":96,"depth":1,"refund":0,"opName":"SSTORE"} + {"pc":9,"op":96,"gas":"0x2540b95c8","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":11,"op":96,"gas":"0x2540b95c5","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":13,"op":96,"gas":"0x2540b95c2","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":15,"op":96,"gas":"0x2540b95bf","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":17,"op":96,"gas":"0x2540b95bc","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":19,"op":90,"gas":"0x2540b95b9","gasCost":"0x2","memSize":96,"depth":1,"refund":0,"opName":"GAS","storage":{"0x40":"0x40"}} + {"pc":20,"op":250,"gas":"0x2540b95b7","gasCost":"0x2bc","memSize":96,"depth":1,"refund":0,"opName":"STATICCALL","storage":{"0x40":"0x40"}} + {"pc":21,"op":96,"gas":"0x2540b92a7","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":23,"op":243,"gas":"0x2540b92a4","gasCost":"0x0","memSize":96,"depth":1,"refund":0,"opName":"RETURN","storage":{"0x40":"0x40"}} + """); } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java b/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java index 76934e041f0..368dbffabd0 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java @@ -122,6 +122,12 @@ public class EvmToyCommand implements Runnable { scope = ScopeType.INHERIT) final Boolean showReturnData = false; + @CommandLine.Option( + names = {"--trace.storage"}, + description = "When tracing, show the updated storage contents.", + scope = ScopeType.INHERIT) + final Boolean showStorage = false; + @CommandLine.Option( names = {"--repeat"}, description = "Number of times to repeat for benchmarking.") @@ -164,7 +170,8 @@ public void run() { final OperationTracer tracer = // You should have picked Mercy. lastLoop && showJsonResults - ? new StandardJsonTracer(System.out, showMemory, showStack, showReturnData) + ? new StandardJsonTracer( + System.out, showMemory, showStack, showReturnData, showStorage) : OperationTracer.NO_TRACING; MessageFrame initialMessageFrame = From fd499a362e3cdbd0abda0cd6e59ba0d837c667f1 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Wed, 20 Sep 2023 10:11:40 +1000 Subject: [PATCH 32/34] Update holesky with fixed extraData, genesis time, shanghaiTime (#5890) Signed-off-by: Simon Dudley Signed-off-by: garyschulte --- CHANGELOG.md | 4 +- .../besu/ForkIdsNetworkConfigTest.java | 7 +- config/src/main/resources/holesky.json | 369 +++++++++--------- 3 files changed, 189 insertions(+), 191 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6a1af9b925..1f4524b0870 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,6 @@ # Changelog ## 23.7.3 -### Additions and Improvements -- Add access to an immutable world view to start/end transaction hooks in the tracing API[#5836](https://github.com/hyperledger/besu/pull/5836) ### Breaking Changes - Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816) @@ -11,8 +9,10 @@ - `--Xlayered-tx-pool-layer-max-capacity`, `--Xlayered-tx-pool-max-prioritized` and `--Xlayered-tx-pool-max-future-by-sender` just drop the `X` and keep the same behavior ### Additions and Improvements +- Add access to an immutable world view to start/end transaction hooks in the tracing API[#5836](https://github.com/hyperledger/besu/pull/5836) - Layered transaction pool implementation is now stable and enabled by default. If you want still to use the legacy implementation, use `--tx-pool=legacy` [#5772](https://github.com/hyperledger/besu) - Tune G1GC to reduce Besu memory footprint, and new `besu-untuned` start scripts to run without any specific G1GC flags [#5879](https://github.com/hyperledger/besu/pull/5879) +- Update Holesky config for re-launch [#5890](https://github.com/hyperledger/besu/pull/5890) ### Bug Fixes - do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java index df5607120e5..bfa55c261aa 100644 --- a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java +++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java @@ -84,10 +84,9 @@ public static Collection parameters() { new Object[] { NetworkName.HOLESKY, List.of( - new ForkId(Bytes.ofUnsignedInt(0xa200f558L), 1694790240L), - new ForkId(Bytes.ofUnsignedInt(0x840a3b53L), 2000000000L), - new ForkId(Bytes.ofUnsignedInt(0x30771f90), 0L), - new ForkId(Bytes.ofUnsignedInt(0x30771f90), 0L)) + new ForkId(Bytes.ofUnsignedInt(0xc61a6098L), 1696000704L), + new ForkId(Bytes.ofUnsignedInt(0xfd4f016bL), 0L), + new ForkId(Bytes.ofUnsignedInt(0xfd4f016bL), 0L)) }, new Object[] { NetworkName.GOERLI, diff --git a/config/src/main/resources/holesky.json b/config/src/main/resources/holesky.json index 0b3c875fba2..a8ae193c856 100644 --- a/config/src/main/resources/holesky.json +++ b/config/src/main/resources/holesky.json @@ -13,9 +13,8 @@ "londonBlock": 0, "preMergeForkBlock": 0, "terminalTotalDifficulty": 0, - "shanghaiTime": 1694790240, + "shanghaiTime": 1696000704, "ethash": {}, - "cancunTime": 2000000000, "discovery": { "bootnodes": [ "enode://ac906289e4b7f12df423d654c5a962b6ebe5b3a74cc9e06292a85221f9a64a6f1cfdd6b714ed6dacef51578f92b34c60ee91e9ede9c7f8fadc4d347326d95e2b@146.190.13.128:30303", @@ -827,196 +826,196 @@ "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" - }, - "0x0000006916a87b82333f4245046623b23794C65C": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x0be949928Ff199c9EBA9E110db210AA5C94EFAd0": { - "balance": "0x7c13bc4b2c133c56000000" - }, - "0x0C100000006d7b5e23a1eAEE637f28cA32Cd5b31": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x0C35317B7a96C454E2CB3d1A255D775Ab112cCc8": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x0d731cfabC5574329823F26d488416451d2ea376": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x0e79065B5F11b5BD1e62B935A600976ffF3754B9": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x105083929bF9bb22C26cB1777Ec92661170D4285": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x10F5d45854e038071485AC9e402308cF80D2d2fE": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x1268AD189526AC0b386faF06eFfC46779c340eE6": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x12Cba59f5A74DB81a12ff63C349Bd82CBF6007C2": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x1446D7f6dF00380F246d8211dE7f0FaBC4Fd248C": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x164e38a375247A784A81d420201AA8fe4E513921": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x1B7aA44088a0eA95bdc65fef6E5071E946Bf7d8f": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x222222222222cF64a76AE3d36859958c864fDA2c": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x2f14582947E292a2eCd20C430B46f2d27CFE213c": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x2f2c75B5Dd5D246194812b00eEb3B09c2c66e2eE": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x341c40b94bf2afbfa42573cb78f16ee15a056238": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x34f845773D4364999f2fbC7AA26ABDeE902cBb46": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x3C75594181e03E8ECD8468A0037F058a9dAfad79": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x462396E69dBfa455F405f4DD82F3014Af8003B72": { - "balance": "0xa56fa5b99019a5c8000000" - }, - "0x49Df3CCa2670eB0D591146B16359fe336e476F29": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x4D0b04b405c6b62C7cFC3aE54759747e2C0b4662": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x4D496CcC28058B1D74B7a19541663E21154f9c84": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x509a7667aC8D0320e36172c192506a6188aA84f6": { - "balance": "0x7c13bc4b2c133c56000000" - }, - "0x5180db0237291A6449DdA9ed33aD90a38787621c": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x52730f347dEf6BA09adfF62EaC60D5fEe8205BC4": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x5EAC0fBd3dfef8aE3efa3c5dc1aa193bc6033dFd": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x6a7aA9b882d50Bb7bc5Da1a244719C99f12F06a3": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x6Cc9397c3B38739daCbfaA68EaD5F5D77Ba5F455": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x762cA62ca2549ad806763B3Aa1eA317c429bDBDa": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x778F5F13C4Be78A3a4d7141BCB26999702f407CF": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x875D25Ee4bC604C71BaF6236a8488F22399BED4b": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x8dF7878d3571BEF5e5a744F96287C8D20386d75A": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0x9E415A096fF77650dc925dEA546585B4adB322B6": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xA0766B65A4f7B1da79a1AF79aC695456eFa28644": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xA29B144A449E414A472c60C7AAf1aaFfE329021D": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xa55395566b0b54395B3246f96A0bDc4b8a483df9": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xAC9ba72fb61aA7c31A95df0A8b6ebA6f41EF875e": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xB0498C15879db2eE5471d4926c5fAA25C9a09683": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xB19Fb4c1f280327e60Ed37b1Dc6EE77533539314": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0xC21cB9C99C316d1863142F7dD86dd5496D81A8D6": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xc473d412dc52e349862209924c8981b2ee420768": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xC48E23C5F6e1eA0BaEf6530734edC3968f79Af2e": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0xc6e2459991BfE27cca6d86722F35da23A1E4Cb97": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0xD3994e4d3202dD23c8497d7F75bF1647d1DA1bb1": { - "balance": "0x19D971E4FE8401E74000000" - }, - "0xDCA6e9B48Ea86AeBFDf9929949124042296b6e34": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xe0a2Bd4258D2768837BAa26A28fE71Dc079f84c7": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0xEA28d002042fd9898D0Db016be9758eeAFE35C1E": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xEfA7454f1116807975A4750B46695E967850de5D": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xFBFd6Fa9F73Ac6A058E01259034C28001BEf8247": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0xe0991E844041bE6F11B99da5b114b6bCf84EBd57": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x15E719b6AcAf1E4411Bf0f9576CB1D0dB161DdFc": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x346D827a75F98F0A7a324Ff80b7C3F90252E8baC": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x73b2e0E54510239E22cC936F0b4a6dE1acf0AbdE": { - "balance": "0x52b7d2dcc80cd2e4000000" - }, - "0xBb977B2EE8a111D788B3477D242078d0B837E72b": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x834Dbf5A03e29c25bc55459cCe9c021EeBE676Ad": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xD1F77E4C1C45186e8653C489F90e008a73597296": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xb04aeF2a3d2D86B01006cCD4339A2e943d9c6480": { - "balance": "0xd3c21bcecceda1000000" - }, - "0xC9CA2bA9A27De1Db589d8c33Ab8EDFa2111b31fb": { - "balance": "0xd3c21bcecceda1000000" - }, - "0x4BC656B34De23896fa6069C9862F355b740401aF": { - "balance": "0x084595161401484a000000" } + }, + "0x0000006916a87b82333f4245046623b23794C65C": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x0be949928Ff199c9EBA9E110db210AA5C94EFAd0": { + "balance": "0x7c13bc4b2c133c56000000" + }, + "0x0C100000006d7b5e23a1eAEE637f28cA32Cd5b31": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x0C35317B7a96C454E2CB3d1A255D775Ab112cCc8": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x0d731cfabC5574329823F26d488416451d2ea376": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x0e79065B5F11b5BD1e62B935A600976ffF3754B9": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x105083929bF9bb22C26cB1777Ec92661170D4285": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x10F5d45854e038071485AC9e402308cF80D2d2fE": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x1268AD189526AC0b386faF06eFfC46779c340eE6": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x12Cba59f5A74DB81a12ff63C349Bd82CBF6007C2": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x1446D7f6dF00380F246d8211dE7f0FaBC4Fd248C": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x164e38a375247A784A81d420201AA8fe4E513921": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x1B7aA44088a0eA95bdc65fef6E5071E946Bf7d8f": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x222222222222cF64a76AE3d36859958c864fDA2c": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x2f14582947E292a2eCd20C430B46f2d27CFE213c": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x2f2c75B5Dd5D246194812b00eEb3B09c2c66e2eE": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x341c40b94bf2afbfa42573cb78f16ee15a056238": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x34f845773D4364999f2fbC7AA26ABDeE902cBb46": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x3C75594181e03E8ECD8468A0037F058a9dAfad79": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x462396E69dBfa455F405f4DD82F3014Af8003B72": { + "balance": "0xa56fa5b99019a5c8000000" + }, + "0x49Df3CCa2670eB0D591146B16359fe336e476F29": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x4D0b04b405c6b62C7cFC3aE54759747e2C0b4662": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x4D496CcC28058B1D74B7a19541663E21154f9c84": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x509a7667aC8D0320e36172c192506a6188aA84f6": { + "balance": "0x7c13bc4b2c133c56000000" + }, + "0x5180db0237291A6449DdA9ed33aD90a38787621c": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x52730f347dEf6BA09adfF62EaC60D5fEe8205BC4": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x5EAC0fBd3dfef8aE3efa3c5dc1aa193bc6033dFd": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x6a7aA9b882d50Bb7bc5Da1a244719C99f12F06a3": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x6Cc9397c3B38739daCbfaA68EaD5F5D77Ba5F455": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x762cA62ca2549ad806763B3Aa1eA317c429bDBDa": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x778F5F13C4Be78A3a4d7141BCB26999702f407CF": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x875D25Ee4bC604C71BaF6236a8488F22399BED4b": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x8dF7878d3571BEF5e5a744F96287C8D20386d75A": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0x9E415A096fF77650dc925dEA546585B4adB322B6": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xA0766B65A4f7B1da79a1AF79aC695456eFa28644": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xA29B144A449E414A472c60C7AAf1aaFfE329021D": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xa55395566b0b54395B3246f96A0bDc4b8a483df9": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xAC9ba72fb61aA7c31A95df0A8b6ebA6f41EF875e": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xB0498C15879db2eE5471d4926c5fAA25C9a09683": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xB19Fb4c1f280327e60Ed37b1Dc6EE77533539314": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0xC21cB9C99C316d1863142F7dD86dd5496D81A8D6": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xc473d412dc52e349862209924c8981b2ee420768": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xC48E23C5F6e1eA0BaEf6530734edC3968f79Af2e": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0xc6e2459991BfE27cca6d86722F35da23A1E4Cb97": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0xD3994e4d3202dD23c8497d7F75bF1647d1DA1bb1": { + "balance": "0x19D971E4FE8401E74000000" + }, + "0xDCA6e9B48Ea86AeBFDf9929949124042296b6e34": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xe0a2Bd4258D2768837BAa26A28fE71Dc079f84c7": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0xEA28d002042fd9898D0Db016be9758eeAFE35C1E": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xEfA7454f1116807975A4750B46695E967850de5D": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xFBFd6Fa9F73Ac6A058E01259034C28001BEf8247": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0xe0991E844041bE6F11B99da5b114b6bCf84EBd57": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x15E719b6AcAf1E4411Bf0f9576CB1D0dB161DdFc": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x346D827a75F98F0A7a324Ff80b7C3F90252E8baC": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x73b2e0E54510239E22cC936F0b4a6dE1acf0AbdE": { + "balance": "0x52b7d2dcc80cd2e4000000" + }, + "0xBb977B2EE8a111D788B3477D242078d0B837E72b": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x834Dbf5A03e29c25bc55459cCe9c021EeBE676Ad": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xD1F77E4C1C45186e8653C489F90e008a73597296": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xb04aeF2a3d2D86B01006cCD4339A2e943d9c6480": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xC9CA2bA9A27De1Db589d8c33Ab8EDFa2111b31fb": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x4BC656B34De23896fa6069C9862F355b740401aF": { + "balance": "0x084595161401484a000000" } }, "coinbase": "0x0000000000000000000000000000000000000000", "baseFeePerGas": "0x3B9ACA00", "difficulty": "0x01", - "extraData": "0x686f77206d7563682069732074686520666973683f", + "extraData": "", "gasLimit": "0x17D7840", "nonce": "0x1234", "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "1694786100" -} + "timestamp": "1695902100" +} \ No newline at end of file From 7c1acf79d7fd589b408f368cae869875b409b8d0 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Wed, 20 Sep 2023 13:40:09 +1000 Subject: [PATCH 33/34] [CHANGELOG] removed duplicated line (#5904) * removed duplicated line [skip ci] Signed-off-by: Sally MacFarlane * fixed spelling on Holesky Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane Signed-off-by: garyschulte --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f4524b0870..8c064c2e8a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,12 +12,11 @@ - Add access to an immutable world view to start/end transaction hooks in the tracing API[#5836](https://github.com/hyperledger/besu/pull/5836) - Layered transaction pool implementation is now stable and enabled by default. If you want still to use the legacy implementation, use `--tx-pool=legacy` [#5772](https://github.com/hyperledger/besu) - Tune G1GC to reduce Besu memory footprint, and new `besu-untuned` start scripts to run without any specific G1GC flags [#5879](https://github.com/hyperledger/besu/pull/5879) -- Update Holesky config for re-launch [#5890](https://github.com/hyperledger/besu/pull/5890) +- Update Holešky config for re-launch [#5890](https://github.com/hyperledger/besu/pull/5890) ### Bug Fixes - do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) - fix duplicate key errors in EthScheduler-Transactions [#5857](https://github.com/hyperledger/besu/pull/5857) -- do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) ### Download Links From 7372e74ccfce12b973150abf0c78de60add73789 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 19 Sep 2023 22:53:37 -0700 Subject: [PATCH 34/34] add 23.7.2 release SHAs and bump to 23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-23.7.3-RC version Signed-off-by: garyschulte --- CHANGELOG.md | 4 ++-- gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c064c2e8a4..429ae790c0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,8 +44,8 @@ - Fixing snapsync issue with forest during the heal step [#5776](https://github.com/hyperledger/besu/pull/5776) ### Download Links -https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.2/besu-23.7.2.tar.gz / sha256: TBA -https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.2/besu-23.7.2.zip / sha256: TBA +https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.2/besu-23.7.2.tar.gz / sha256: f74b32c1a343cbad90a88aa59276b4c5eefea4643ee542aba2bbf898f85ae242 +https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.2/besu-23.7.2.zip / sha256: a233c83591fc277e3d1530c84bb5ea896abad717d796b5e3b856c79199132b75 ## 23.7.1 diff --git a/gradle.properties b/gradle.properties index 32a11f7cc8c..c5e65ab051f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=23.7.3-SNAPSHOT +version=23.7.3-RC org.gradle.welcome=never # Set exports/opens flags required by Google Java Format and ErrorProne plugins. (JEP-396)