diff --git a/CHANGELOG.md b/CHANGELOG.md index c849de7c608..6eecf3a4c86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,19 @@ # Changelog -## Next release -- Cache last n blocks by using a new Besu flag --cache-last-blocks=n -- Optimize performances of RPC method Eth_feeHistory +### Breaking Changes + +### Deprecations + +### Additions and Improvements +- TraceService: Better error handling for internal errors in TransactionProcessor [#6086](https://github.com/hyperledger/besu/pull/6086) + +### Bug Fixes + +### Download Links + +## 23.10.1 +- Cache last n blocks by using a new Besu flag --cache-last-blocks=n [#6009](https://github.com/hyperledger/besu/pull/6009) +- Optimize performances of RPC method Eth_feeHistory [#6011](https://github.com/hyperledger/besu/pull/6011) ### Breaking Changes diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java index 048e40553ba..f01c58549bc 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java @@ -110,9 +110,11 @@ public void startNode(final BesuNode node) { params.add( Integer.toString(node.getMiningParameters().getMinTransactionGasPrice().intValue())); params.add("--Xminer-remote-sealers-limit"); - params.add(Integer.toString(node.getMiningParameters().getRemoteSealersLimit())); + params.add( + Integer.toString(node.getMiningParameters().getUnstable().getRemoteSealersLimit())); params.add("--Xminer-remote-sealers-hashrate-ttl"); - params.add(Long.toString(node.getMiningParameters().getRemoteSealersTimeToLive())); + params.add( + Long.toString(node.getMiningParameters().getUnstable().getRemoteSealersTimeToLive())); } if (node.getMiningParameters().isStratumMiningEnabled()) { params.add("--miner-stratum-enabled"); diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java index 4943aaf60eb..fea87c35088 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java @@ -22,7 +22,6 @@ import org.hyperledger.besu.cli.config.NetworkName; import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; @@ -30,6 +29,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.tls.FileBasedPasswordProvider; import org.hyperledger.besu.ethereum.core.AddressHelpers; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; @@ -56,11 +57,11 @@ public class BesuNodeConfigurationBuilder { private String name; private Optional dataPath = Optional.empty(); private MiningParameters miningParameters = - new MiningParameters.Builder() - .miningEnabled(false) - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.of(1000)) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder().coinbase(AddressHelpers.ofValue(1)).build()) .build(); + private JsonRpcConfiguration jsonRpcConfiguration = JsonRpcConfiguration.createDefault(); private JsonRpcConfiguration engineRpcConfiguration = JsonRpcConfiguration.createEngineDefault(); private WebSocketConfiguration webSocketConfiguration = WebSocketConfiguration.createDefault(); @@ -113,12 +114,7 @@ public BesuNodeConfigurationBuilder miningEnabled() { } public BesuNodeConfigurationBuilder miningEnabled(final boolean enabled) { - this.miningParameters = - new MiningParameters.Builder() - .miningEnabled(enabled) - .minTransactionGasPrice(Wei.of(1000)) - .coinbase(AddressHelpers.ofValue(1)) - .build(); + this.miningParameters = miningParameters.setMiningEnabled(enabled); this.jsonRpcConfiguration.addRpcApi(RpcApis.MINER.name()); return this; } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java index bd635c6bfcf..9e35d09f2fc 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java @@ -26,6 +26,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.core.AddressHelpers; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.InMemoryPrivacyStorageProvider; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; @@ -303,10 +305,13 @@ public BesuNode createNodeWithMultiTenantedPrivacy( .build(); final MiningParameters miningParameters = - new MiningParameters.Builder() - .minTransactionGasPrice(Wei.ZERO) - .coinbase(AddressHelpers.ofValue(1)) - .miningEnabled(true) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(AddressHelpers.ofValue(1)) + .build()) .build(); return create( diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/BftMiningAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/BftMiningAcceptanceTest.java index e529268cb59..a109a3b8567 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/BftMiningAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/BftMiningAcceptanceTest.java @@ -17,6 +17,8 @@ import org.hyperledger.besu.config.JsonUtil; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.AddressHelpers; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.tests.acceptance.dsl.account.Account; import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount; @@ -59,10 +61,13 @@ public void shouldMineOnSingleNodeWithPaidGas_Berlin() throws Exception { public void shouldMineOnSingleNodeWithFreeGas_Berlin() throws Exception { final BesuNode minerNode = nodeFactory.createNode(besu, "miner1"); final MiningParameters zeroGasMiningParams = - new MiningParameters.Builder() - .miningEnabled(true) - .minTransactionGasPrice(Wei.ZERO) - .coinbase(AddressHelpers.ofValue(1)) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(AddressHelpers.ofValue(1)) + .build()) .build(); minerNode.setMiningParameters(zeroGasMiningParams); diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/02_cancun_getPayloadV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/02_cancun_getPayloadV3.json index 805709fe86f..73cbe51bdeb 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/02_cancun_getPayloadV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/02_cancun_getPayloadV3.json @@ -14,7 +14,7 @@ "executionPayload": { "parentHash": "0x26118cf71453320edcebbc4ebb34af5b578087a32385b80108bf691fa23efc42", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "stateRoot": "0x23e3e21a839dbba902efaad82e5c3e1ddd64ea067ce0f979a68dabcc46be4e8b", + "stateRoot": "0x9b8c4a9a86cb49252075c0db2f0e72fb1e49350a0f70ea36f26f700201961e62", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", @@ -22,22 +22,22 @@ "timestamp": "0x10", "extraData": "0x", "baseFeePerGas": "0x7", - "excessBlobGas" : "0x0", - "parentBeaconBlockRoot" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "excessBlobGas": "0x0", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactions": [], "withdrawals": [], "blockNumber": "0x1", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "blockHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", - "blobGasUsed" : "0x0" + "blockHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", + "blobGasUsed": "0x0" }, "blockValue": "0x0", - "blobsBundle" : { - "commitments" : [], - "proofs" : [], - "blobs" : [] + "blobsBundle": { + "commitments": [], + "proofs": [], + "blobs": [] }, - "shouldOverrideBuilder" : false + "shouldOverrideBuilder": false } }, "statusCode": 200 diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/03_cancun_newPayloadV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/03_cancun_newPayloadV3.json index ba9f69b47ae..d4d76df31de 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/03_cancun_newPayloadV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/03_cancun_newPayloadV3.json @@ -6,7 +6,7 @@ { "parentHash": "0x26118cf71453320edcebbc4ebb34af5b578087a32385b80108bf691fa23efc42", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "stateRoot": "0x23e3e21a839dbba902efaad82e5c3e1ddd64ea067ce0f979a68dabcc46be4e8b", + "stateRoot": "0x9b8c4a9a86cb49252075c0db2f0e72fb1e49350a0f70ea36f26f700201961e62", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", @@ -17,10 +17,10 @@ "transactions": [], "withdrawals": [], "blockNumber": "0x1", - "blockHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", + "blockHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "excessBlobGas" : "0x0", - "blobGasUsed" : "0x0" + "excessBlobGas": "0x0", + "blobGasUsed": "0x0" }, [], "0x0000000000000000000000000000000000000000000000000000000000000000" @@ -32,7 +32,7 @@ "id": 67, "result": { "status": "VALID", - "latestValidHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", + "latestValidHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", "validationError": null } }, diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/04_cancun_forkchoiceUpdatedV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/04_cancun_forkchoiceUpdatedV3.json index 49e803ecc03..80610561a0f 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/04_cancun_forkchoiceUpdatedV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/04_cancun_forkchoiceUpdatedV3.json @@ -4,9 +4,9 @@ "method": "engine_forkchoiceUpdatedV3", "params": [ { - "headBlockHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", - "safeBlockHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", - "finalizedBlockHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c" + "headBlockHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", + "safeBlockHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", + "finalizedBlockHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356" }, null ], @@ -18,7 +18,7 @@ "result": { "payloadStatus": { "status": "VALID", - "latestValidHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", + "latestValidHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", "validationError": null }, "payloadId": null diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/05_eip6110_forkchoiceUpdatedV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/05_eip6110_forkchoiceUpdatedV3.json index e47346cc308..4f83ac7dcee 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/05_eip6110_forkchoiceUpdatedV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/05_eip6110_forkchoiceUpdatedV3.json @@ -4,8 +4,8 @@ "method": "engine_forkchoiceUpdatedV3", "params": [ { - "headBlockHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", - "safeBlockHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", + "headBlockHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", + "safeBlockHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", "finalizedBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000" }, { @@ -24,11 +24,11 @@ "result": { "payloadStatus": { "status": "VALID", - "latestValidHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", + "latestValidHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", "validationError": null }, - "payloadId": "0x282643962616abdf" + "payloadId": "0x282643b9c2d2a4df" } }, - "statusCode" : 200 + "statusCode": 200 } \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/06_eip6110_getPayloadV6110.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/06_eip6110_getPayloadV6110.json index eb1bf8a5f80..9b1653a198d 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/06_eip6110_getPayloadV6110.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/06_eip6110_getPayloadV6110.json @@ -3,7 +3,7 @@ "jsonrpc": "2.0", "method": "engine_getPayloadV6110", "params": [ - "0x282643962616abdf" + "0x282643b9c2d2a4df" ], "id": 67 }, @@ -12,9 +12,9 @@ "id": 67, "result": { "executionPayload": { - "parentHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", + "parentHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "stateRoot": "0x6a88816cf7e94f1f44cf82c63521bb7f2e49e99ab0ad2e4e46ef1ab8f6ccad84", + "stateRoot": "0x9b8c4a9a86cb49252075c0db2f0e72fb1e49350a0f70ea36f26f700201961e62", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", @@ -22,23 +22,23 @@ "timestamp": "0x20", "extraData": "0x", "baseFeePerGas": "0x7", - "excessBlobGas" : "0x0", - "parentBeaconBlockRoot" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "excessBlobGas": "0x0", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactions": [], "withdrawals": [], - "depositReceipts" : [], + "depositReceipts": [], "blockNumber": "0x2", - "blockHash": "0x6d4f567f7afe59226a1400fd0c11797f0bb69bec74b8eb99a066f899e0bd1d0f", + "blockHash": "0xf6c3f1180ba58d6ea4c69c9328c7afb1fda41df06c368741c1f8310567879de7", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "blobGasUsed" : "0x0" + "blobGasUsed": "0x0" }, "blockValue": "0x0", - "blobsBundle" : { - "commitments" : [], - "proofs" : [], - "blobs" : [] + "blobsBundle": { + "commitments": [], + "proofs": [], + "blobs": [] }, - "shouldOverrideBuilder" : false + "shouldOverrideBuilder": false } }, "statusCode": 200 diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/08_eip6110_invalid_null_deposits_execute_payload.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/08_eip6110_invalid_null_deposits_execute_payload.json index e19897ff471..ebf5de77500 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/08_eip6110_invalid_null_deposits_execute_payload.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/08_eip6110_invalid_null_deposits_execute_payload.json @@ -4,9 +4,9 @@ "method": "engine_newPayloadV6110", "params": [ { - "parentHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", + "parentHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "stateRoot": "0x6a88816cf7e94f1f44cf82c63521bb7f2e49e99ab0ad2e4e46ef1ab8f6ccad84", + "stateRoot": "0x9b8c4a9a86cb49252075c0db2f0e72fb1e49350a0f70ea36f26f700201961e62", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", @@ -14,14 +14,14 @@ "timestamp": "0x20", "extraData": "0x", "baseFeePerGas": "0x7", - "excessBlobGas" : "0x0", + "excessBlobGas": "0x0", "transactions": [], "withdrawals": [], "depositReceipts" : null, "blockNumber": "0x2", - "blockHash": "0x6d4f567f7afe59226a1400fd0c11797f0bb69bec74b8eb99a066f899e0bd1d0f", + "blockHash": "0xf6c3f1180ba58d6ea4c69c9328c7afb1fda41df06c368741c1f8310567879de7", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "blobGasUsed" : "0x0" + "blobGasUsed": "0x0" }, [], "0x0000000000000000000000000000000000000000000000000000000000000000" diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/09_eip6110_newPayloadV6110.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/09_eip6110_newPayloadV6110.json index d0a4c229044..0964114e62c 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/09_eip6110_newPayloadV6110.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/09_eip6110_newPayloadV6110.json @@ -4,9 +4,9 @@ "method": "engine_newPayloadV6110", "params": [ { - "parentHash": "0x17da7aea0f4e4ba1d905dbb7d60f6ab4133f3009ae1a1ba99e6e9cb37c15412c", + "parentHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "stateRoot": "0x7ffa22d9c7d856687bbec0700c17288ee6aff2bfd14e92a8921b08ed1d0c6030", + "stateRoot": "0x14208ac0e218167936e220b72d5d5887a963cb858ea2f2d268518f014a3da3fa", "logsBloom": "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", @@ -14,7 +14,7 @@ "timestamp": "0x20", "extraData": "0x", "baseFeePerGas": "0x7", - "excessBlobGas" : "0x0", + "excessBlobGas": "0x0", "transactions": [ "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452" ], @@ -23,9 +23,9 @@ {"amount":"0x773594000","index":"0x0","pubkey":"0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9","signature":"0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9","withdrawalCredentials":"0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2"} ], "blockNumber": "0x2", - "blockHash": "0xe6763c709abac0b477073c1efd980e12728c1ea22361c03e41db6fbd6a271832", + "blockHash": "0xb3b483867217b83b1e4a2f95c84d2da30cbff12eb8636f2becbcc05f4507fa7a", "receiptsRoot": "0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", - "blobGasUsed" : "0x0" + "blobGasUsed": "0x0" }, [], "0x0000000000000000000000000000000000000000000000000000000000000000" @@ -37,7 +37,7 @@ "id": 67, "result": { "status": "VALID", - "latestValidHash": "0xe6763c709abac0b477073c1efd980e12728c1ea22361c03e41db6fbd6a271832", + "latestValidHash": "0xb3b483867217b83b1e4a2f95c84d2da30cbff12eb8636f2becbcc05f4507fa7a", "validationError": null } }, diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/10_eip6110_forkchoiceUpdatedV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/10_eip6110_forkchoiceUpdatedV3.json index 9b1c62070bb..5a32569d611 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/10_eip6110_forkchoiceUpdatedV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/10_eip6110_forkchoiceUpdatedV3.json @@ -4,8 +4,8 @@ "method": "engine_forkchoiceUpdatedV3", "params": [ { - "headBlockHash": "0xe6763c709abac0b477073c1efd980e12728c1ea22361c03e41db6fbd6a271832", - "safeBlockHash": "0xe6763c709abac0b477073c1efd980e12728c1ea22361c03e41db6fbd6a271832", + "headBlockHash": "0xb3b483867217b83b1e4a2f95c84d2da30cbff12eb8636f2becbcc05f4507fa7a", + "safeBlockHash": "0xb3b483867217b83b1e4a2f95c84d2da30cbff12eb8636f2becbcc05f4507fa7a", "finalizedBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000" }, { @@ -24,10 +24,10 @@ "result": { "payloadStatus": { "status": "VALID", - "latestValidHash": "0xe6763c709abac0b477073c1efd980e12728c1ea22361c03e41db6fbd6a271832", + "latestValidHash": "0xb3b483867217b83b1e4a2f95c84d2da30cbff12eb8636f2becbcc05f4507fa7a", "validationError": null }, - "payloadId": "0x28264382a1f291cf" + "payloadId": "0x282643daa04b7631" } }, "statusCode" : 200 diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/11_eip6110_getPayloadV6110.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/11_eip6110_getPayloadV6110.json index 3aff1f3e40f..6c546cd267d 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/11_eip6110_getPayloadV6110.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/eip6110/test-cases/11_eip6110_getPayloadV6110.json @@ -3,7 +3,7 @@ "jsonrpc": "2.0", "method": "engine_getPayloadV6110", "params": [ - "0x28264382a1f291cf" + "0x282643daa04b7631" ], "id": 67 }, @@ -12,9 +12,9 @@ "id": 67, "result": { "executionPayload": { - "parentHash": "0xe6763c709abac0b477073c1efd980e12728c1ea22361c03e41db6fbd6a271832", + "parentHash": "0xb3b483867217b83b1e4a2f95c84d2da30cbff12eb8636f2becbcc05f4507fa7a", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "stateRoot": "0x2d60598bb65d4a9451c097884d1fb07e015c242e2a3475f4ef902ed23e319d3b", + "stateRoot": "0x14208ac0e218167936e220b72d5d5887a963cb858ea2f2d268518f014a3da3fa", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", @@ -22,23 +22,23 @@ "timestamp": "0x30", "extraData": "0x", "baseFeePerGas": "0x7", - "excessBlobGas" : "0x0", - "parentBeaconBlockRoot" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "excessBlobGas": "0x0", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactions": [], "withdrawals": [], - "depositReceipts" : [], + "depositReceipts": [], "blockNumber": "0x3", - "blockHash": "0xa489adae4826ac6a342c382243e8841d3e3b33168e7fd6e31b2c36c17a25f702", + "blockHash": "0xa28bf4db3363ce5b67848eb2ad52dbfead62ddb2287ae7eed36daa002528d1af", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "blobGasUsed" : "0x0" + "blobGasUsed": "0x0" }, "blockValue": "0x0", - "blobsBundle" : { - "commitments" : [], - "proofs" : [], - "blobs" : [] + "blobsBundle": { + "commitments": [], + "proofs": [], + "blobs": [] }, - "shouldOverrideBuilder" : false + "shouldOverrideBuilder": false } }, "statusCode": 200 diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index 857fd4e093e..12ec2f3d849 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -768,7 +768,7 @@ public Runner build() { powMiningCoordinator, miningParameters.getStratumPort(), miningParameters.getStratumNetworkInterface(), - miningParameters.getStratumExtranonce(), + miningParameters.getUnstable().getStratumExtranonce(), metricsSystem)); miningCoordinator.addEthHashObserver(stratumServer.get()); LOG.debug("added ethash observer: {}", stratumServer.get()); @@ -802,6 +802,7 @@ public Runner build() { blockchainQueries, synchronizer, transactionPool, + miningParameters, miningCoordinator, metricsSystem, supportedCapabilities, @@ -847,6 +848,7 @@ public Runner build() { blockchainQueries, synchronizer, transactionPool, + miningParameters, miningCoordinator, metricsSystem, supportedCapabilities, @@ -937,6 +939,7 @@ public Runner build() { blockchainQueries, synchronizer, transactionPool, + miningParameters, miningCoordinator, metricsSystem, supportedCapabilities, @@ -1019,6 +1022,7 @@ public Runner build() { blockchainQueries, synchronizer, transactionPool, + miningParameters, miningCoordinator, metricsSystem, supportedCapabilities, @@ -1187,6 +1191,7 @@ private Map jsonRpcMethods( final BlockchainQueries blockchainQueries, final Synchronizer synchronizer, final TransactionPool transactionPool, + final MiningParameters miningParameters, final MiningCoordinator miningCoordinator, final ObservableMetricsSystem metricsSystem, final Set supportedCapabilities, @@ -1218,6 +1223,7 @@ private Map jsonRpcMethods( protocolContext, filterManager, transactionPool, + miningParameters, miningCoordinator, metricsSystem, supportedCapabilities, 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 47463d2c997..6d6bed2bfcf 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -53,6 +53,7 @@ import org.hyperledger.besu.cli.custom.RpcAuthFileValidator; import org.hyperledger.besu.cli.error.BesuExecutionExceptionHandler; import org.hyperledger.besu.cli.error.BesuParameterExceptionHandler; +import org.hyperledger.besu.cli.options.MiningOptions; import org.hyperledger.besu.cli.options.stable.DataStorageOptions; import org.hyperledger.besu.cli.options.stable.EthstatsOptions; import org.hyperledger.besu.cli.options.stable.LoggingLevelOption; @@ -65,7 +66,6 @@ import org.hyperledger.besu.cli.options.unstable.EvmOptions; import org.hyperledger.besu.cli.options.unstable.IpcOptions; import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; -import org.hyperledger.besu.cli.options.unstable.MiningOptions; import org.hyperledger.besu.cli.options.unstable.NatOptions; import org.hyperledger.besu.cli.options.unstable.NativeLibraryOptions; import org.hyperledger.besu.cli.options.unstable.NetworkingOptions; @@ -287,7 +287,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable { 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(); private final NativeLibraryOptions unstableNativeLibraryOptions = NativeLibraryOptions.create(); private final RPCOptions unstableRPCOptions = RPCOptions.create(); @@ -307,6 +306,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable { final org.hyperledger.besu.cli.options.stable.TransactionPoolOptions stableTransactionPoolOptions = TransactionPoolOptions.create(); + @CommandLine.ArgGroup(validate = false, heading = "@|bold Block Builder Options|@%n") + final MiningOptions miningOptions = MiningOptions.create(); + private final RunnerBuilder runnerBuilder; private final BesuController.Builder controllerBuilderFactory; private final BesuPluginContextImpl besuPluginContext; @@ -1068,63 +1070,6 @@ static class MetricsOptionGroup { "How deep a chain reorganization must be in order for it to be logged (default: ${DEFAULT-VALUE})") private final Long reorgLoggingThreshold = 6L; - // Miner options group - @CommandLine.ArgGroup(validate = false, heading = "@|bold Miner Options|@%n") - MinerOptionGroup minerOptionGroup = new MinerOptionGroup(); - - static class MinerOptionGroup { - @Option( - names = {"--miner-enabled"}, - description = "Set if node will perform mining (default: ${DEFAULT-VALUE})") - private final Boolean isMiningEnabled = false; - - @Option( - names = {"--miner-stratum-enabled"}, - description = "Set if node will perform Stratum mining (default: ${DEFAULT-VALUE})") - private final Boolean iStratumMiningEnabled = false; - - @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. - @Option( - names = {"--miner-stratum-host"}, - description = "Host for Stratum network mining service (default: ${DEFAULT-VALUE})") - private String stratumNetworkInterface = "0.0.0.0"; - - @Option( - names = {"--miner-stratum-port"}, - description = "Stratum port binding (default: ${DEFAULT-VALUE})") - private final Integer stratumPort = 8008; - - @Option( - names = {"--miner-coinbase"}, - description = - "Account to which mining rewards are paid. You must specify a valid coinbase if " - + "mining is enabled using --miner-enabled option", - arity = "1") - private final Address coinbase = null; - - @Option( - names = {"--miner-extra-data"}, - description = - "A hex string representing the (32) bytes to be included in the extra data " - + "field of a mined block (default: ${DEFAULT-VALUE})", - arity = "1") - private final Bytes extraData = DEFAULT_EXTRA_DATA; - } - - @Option( - names = {"--min-gas-price"}, - description = - "Minimum price (in Wei) offered by a transaction for it to be included in a mined " - + "block (default: ${DEFAULT-VALUE})", - arity = "1") - private final Wei minTransactionGasPrice = DEFAULT_MIN_TRANSACTION_GAS_PRICE; - - @Option( - names = {"--min-block-occupancy-ratio"}, - description = "Minimum occupancy ratio for a mined block (default: ${DEFAULT-VALUE})", - arity = "1") - private final Double minBlockOccupancyRatio = DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; - @Option( names = {"--pruning-enabled"}, description = @@ -1204,12 +1149,6 @@ static class PermissionsOptionGroup { split = ",") private final Map requiredBlocks = new HashMap<>(); - @Option( - names = {"--target-gas-limit"}, - description = - "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; - @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. @Option( names = {"--key-value-storage"}, @@ -1316,6 +1255,7 @@ static class PermissionsOptionGroup { private Collection staticNodes; private BesuController besuController; private BesuConfiguration pluginCommonConfiguration; + private MiningParameters miningParameters; private BesuComponent besuComponent; private final Supplier metricsSystem = @@ -1586,7 +1526,6 @@ private void handleUnstableOptions() { .put("Privacy Plugin Configuration", unstablePrivacyPluginOptions) .put("Synchronizer", unstableSynchronizerOptions) .put("TransactionPool", unstableTransactionPoolOptions) - .put("Mining", unstableMiningOptions) .put("Native Library", unstableNativeLibraryOptions) .put("EVM Options", unstableEvmOptions) .put("IPC Options", unstableIpcOptions) @@ -1728,7 +1667,7 @@ private void validatePluginOptions() { "--privacy-marker-transaction-signing-key-file can not be used in conjunction with a plugin that specifies a PrivateMarkerTransactionFactory"); } - if (Wei.ZERO.compareTo(minTransactionGasPrice) < 0 + if (Wei.ZERO.compareTo(getMiningParameters().getMinTransactionGasPrice()) < 0 && (privacyOptionGroup.privateMarkerTransactionSigningKeyPath == null && (privacyPluginService == null || privacyPluginService.getPrivateMarkerTransactionFactory() == null))) { @@ -1871,35 +1810,9 @@ private void validateRequiredOptions() { }); } - @SuppressWarnings("ConstantConditions") private void validateMiningParams() { - if (Boolean.TRUE.equals(minerOptionGroup.isMiningEnabled) - && minerOptionGroup.coinbase == null) { - throw new ParameterException( - this.commandLine, - "Unable to mine without a valid coinbase. Either disable mining (remove --miner-enabled) " - + "or specify the beneficiary of mining (via --miner-coinbase
)"); - } - if (Boolean.FALSE.equals(minerOptionGroup.isMiningEnabled) - && Boolean.TRUE.equals(minerOptionGroup.iStratumMiningEnabled)) { - throw new ParameterException( - this.commandLine, - "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) " - + "or specify mining is enabled (--miner-enabled)"); - } - if (unstableMiningOptions.getPosBlockCreationMaxTime() <= 0 - || unstableMiningOptions.getPosBlockCreationMaxTime() - > MiningParameters.DEFAULT_POS_BLOCK_CREATION_MAX_TIME) { - throw new ParameterException( - this.commandLine, "--Xpos-block-creation-max-time must be positive and ≤ 12000"); - } - - if (unstableMiningOptions.getPosBlockCreationRepetitionMinDuration() <= 0 - || unstableMiningOptions.getPosBlockCreationRepetitionMinDuration() > 2000) { - throw new ParameterException( - this.commandLine, - "--Xpos-block-creation-repetition-min-duration must be positive and ≤ 2000"); - } + miningOptions.validate( + commandLine, logger, isMergeEnabled(), getActualGenesisConfigOptions().isEthHash()); } /** @@ -2072,31 +1985,6 @@ private void issueOptionWarnings() { "--p2p-port", "--remote-connections-max-percentage")); - // Check that block producer options work - if (!isMergeEnabled() && getActualGenesisConfigOptions().isEthHash()) { - CommandLineUtils.checkOptionDependencies( - logger, - commandLine, - "--miner-enabled", - !minerOptionGroup.isMiningEnabled, - asList( - "--miner-coinbase", - "--min-gas-price", - "--min-block-occupancy-ratio", - "--miner-extra-data")); - - // Check that mining options are able to work - CommandLineUtils.checkOptionDependencies( - logger, - commandLine, - "--miner-enabled", - !minerOptionGroup.isMiningEnabled, - asList( - "--miner-stratum-enabled", - "--Xminer-remote-sealers-limit", - "--Xminer-remote-sealers-hashrate-ttl")); - } - CommandLineUtils.failIfOptionDoesntMeetRequirement( commandLine, "--fast-sync-min-peers can't be used with FULL sync-mode", @@ -2250,26 +2138,7 @@ public BesuControllerBuilder getControllerBuilder() { .transactionSelectorFactory(getTransactionSelectorFactory()) .pluginTransactionValidatorFactory(getPluginTransactionValidatorFactory()) .dataDirectory(dataDir()) - .miningParameters( - new MiningParameters.Builder() - .coinbase(minerOptionGroup.coinbase) - .targetGasLimit(targetGasLimit) - .minTransactionGasPrice(minTransactionGasPrice) - .extraData(minerOptionGroup.extraData) - .miningEnabled(minerOptionGroup.isMiningEnabled) - .stratumMiningEnabled(minerOptionGroup.iStratumMiningEnabled) - .stratumNetworkInterface(minerOptionGroup.stratumNetworkInterface) - .stratumPort(minerOptionGroup.stratumPort) - .stratumExtranonce(unstableMiningOptions.getStratumExtranonce()) - .minBlockOccupancyRatio(minBlockOccupancyRatio) - .remoteSealersLimit(unstableMiningOptions.getRemoteSealersLimit()) - .remoteSealersTimeToLive(unstableMiningOptions.getRemoteSealersTimeToLive()) - .powJobTimeToLive(unstableMiningOptions.getPowJobTimeToLive()) - .maxOmmerDepth(unstableMiningOptions.getMaxOmmersDepth()) - .posBlockCreationMaxTime(unstableMiningOptions.getPosBlockCreationMaxTime()) - .posBlockCreationRepetitionMinDuration( - unstableMiningOptions.getPosBlockCreationRepetitionMinDuration()) - .build()) + .miningParameters(getMiningParameters()) .transactionPoolConfiguration(buildTransactionPoolConfiguration()) .nodeKey(new NodeKey(securityModule())) .metricsSystem(metricsSystem.get()) @@ -2284,9 +2153,9 @@ public BesuControllerBuilder getControllerBuilder() { new PrunerConfiguration(pruningBlockConfirmations, pruningBlocksRetained)) .genesisConfigOverrides(genesisConfigOverrides) .gasLimitCalculator( - Optional.ofNullable(targetGasLimit) - .map(z -> new FrontierTargetingGasLimitCalculator()) - .orElse(GasLimitCalculator.constant())) + getMiningParameters().getTargetGasLimit().isPresent() + ? new FrontierTargetingGasLimitCalculator() + : GasLimitCalculator.constant()) .requiredBlocks(requiredBlocks) .reorgLoggingThreshold(reorgLoggingThreshold) .evmConfiguration(unstableEvmOptions.toDomainObject()) @@ -2613,7 +2482,8 @@ private ApiConfiguration apiConfiguration() { return ImmutableApiConfiguration.builder() .gasPriceBlocks(apiGasPriceBlocks) .gasPricePercentile(apiGasPricePercentile) - .gasPriceMin(minTransactionGasPrice.toLong()) + .gasPriceMinSupplier( + getMiningParameters().getMinTransactionGasPrice().getAsBigInteger()::longValueExact) .gasPriceMax(apiGasPriceMax) .build(); } @@ -2949,6 +2819,13 @@ private TransactionPoolConfiguration buildTransactionPoolConfiguration() { .build(); } + private MiningParameters getMiningParameters() { + if (miningParameters == null) { + miningParameters = miningOptions.toDomainObject(); + } + return miningParameters; + } + private boolean isPruningEnabled() { return pruningEnabled; } @@ -3344,7 +3221,9 @@ private List getEffectivePorts() { addPortIfEnabled( effectivePorts, metricsOptionGroup.metricsPort, metricsOptionGroup.isMetricsEnabled); addPortIfEnabled( - effectivePorts, minerOptionGroup.stratumPort, minerOptionGroup.iStratumMiningEnabled); + effectivePorts, + getMiningParameters().getStratumPort(), + getMiningParameters().isStratumMiningEnabled()); return effectivePorts; } @@ -3555,6 +3434,8 @@ private String generateConfigurationOverview() { builder.setTxPoolImplementation(buildTransactionPoolConfiguration().getTxPoolImplementation()); + builder.setPluginContext(besuComponent.getBesuPluginContext()); + 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 e017caa9ddf..508b195a8eb 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.BesuInfo; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.util.log.FramedLogMessage; import org.hyperledger.besu.util.platform.PlatformDetector; @@ -50,6 +51,7 @@ public class ConfigurationOverviewBuilder { private boolean isHighSpec = false; private TransactionPoolConfiguration.Implementation txPoolImplementation; private Map environment; + private BesuPluginContextImpl besuPluginContext; /** * @param logger the logger @@ -277,6 +279,12 @@ public String build() { lines.add("Total memory: " + normalizeSize(hardwareInfo.getMemory().getTotal())); lines.add("CPU cores: " + hardwareInfo.getProcessor().getLogicalProcessorCount()); + lines.add(""); + + if (besuPluginContext != null) { + lines.addAll(besuPluginContext.getPluginsSummaryLog()); + } + return FramedLogMessage.generate(lines); } @@ -308,4 +316,13 @@ private void detectJemalloc(final List lines) { private String normalizeSize(final long size) { return String.format("%.02f", (double) (size) / 1024 / 1024 / 1024) + " GB"; } + + /** + * set the plugin context + * + * @param besuPluginContext the plugin context + */ + public void setPluginContext(final BesuPluginContextImpl besuPluginContext) { + this.besuPluginContext = besuPluginContext; + } } 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 8b837268327..b7d603b8caa 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.cli; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration; import org.hyperledger.besu.nat.NatMethod; @@ -28,7 +27,6 @@ import java.nio.file.Paths; import java.util.List; -import org.apache.tuweni.bytes.Bytes; import picocli.CommandLine; /** The interface Default command values. */ @@ -58,12 +56,6 @@ public interface DefaultCommandValues { String MANDATORY_NETWORK_FORMAT_HELP = ""; /** The constant MANDATORY_NODE_ID_FORMAT_HELP. */ 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_MIN_BLOCK_OCCUPANCY_RATIO. */ - Double DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO = 0.8; - /** The constant DEFAULT_EXTRA_DATA. */ - Bytes DEFAULT_EXTRA_DATA = Bytes.EMPTY; /** The constant PERMISSIONING_CONFIG_LOCATION. */ String PERMISSIONING_CONFIG_LOCATION = "permissions_config.toml"; /** The constant MANDATORY_HOST_FORMAT_HELP. */ diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java new file mode 100644 index 00000000000..8890f295515 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java @@ -0,0 +1,316 @@ +/* + * 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; + +import static java.util.Arrays.asList; +import static org.hyperledger.besu.ethereum.core.MiningParameters.MutableInitValues.DEFAULT_EXTRA_DATA; +import static org.hyperledger.besu.ethereum.core.MiningParameters.MutableInitValues.DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; +import static org.hyperledger.besu.ethereum.core.MiningParameters.MutableInitValues.DEFAULT_MIN_PRIORITY_FEE_PER_GAS; +import static org.hyperledger.besu.ethereum.core.MiningParameters.MutableInitValues.DEFAULT_MIN_TRANSACTION_GAS_PRICE; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_MAX_OMMERS_DEPTH; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_POS_BLOCK_CREATION_MAX_TIME; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_POW_JOB_TTL; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_REMOTE_SEALERS_LIMIT; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_REMOTE_SEALERS_TTL; + +import org.hyperledger.besu.cli.util.CommandLineUtils; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +import java.util.List; + +import org.apache.tuweni.bytes.Bytes; +import org.slf4j.Logger; +import picocli.CommandLine; +import picocli.CommandLine.Option; +import picocli.CommandLine.ParameterException; + +/** The Mining CLI options. */ +public class MiningOptions implements CLIOptions { + + @Option( + names = {"--miner-enabled"}, + description = "Set if node will perform mining (default: ${DEFAULT-VALUE})") + private Boolean isMiningEnabled = false; + + @Option( + names = {"--miner-stratum-enabled"}, + description = "Set if node will perform Stratum mining (default: ${DEFAULT-VALUE})") + private Boolean iStratumMiningEnabled = false; + + @Option( + names = {"--miner-stratum-host"}, + description = "Host for Stratum network mining service (default: ${DEFAULT-VALUE})") + private String stratumNetworkInterface = "0.0.0.0"; + + @Option( + names = {"--miner-stratum-port"}, + description = "Stratum port binding (default: ${DEFAULT-VALUE})") + private Integer stratumPort = 8008; + + @Option( + names = {"--miner-coinbase"}, + description = + "Account to which mining rewards are paid. You must specify a valid coinbase if " + + "mining is enabled using --miner-enabled option", + arity = "1") + private Address coinbase = null; + + @Option( + names = {"--miner-extra-data"}, + description = + "A hex string representing the (32) bytes to be included in the extra data " + + "field of a mined block (default: ${DEFAULT-VALUE})", + arity = "1") + private Bytes extraData = DEFAULT_EXTRA_DATA; + + @Option( + names = {"--min-block-occupancy-ratio"}, + description = "Minimum occupancy ratio for a mined block (default: ${DEFAULT-VALUE})", + arity = "1") + private Double minBlockOccupancyRatio = DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; + + @Option( + names = {"--min-gas-price"}, + description = + "Minimum price (in Wei) offered by a transaction for it to be included in a mined " + + "block (default: ${DEFAULT-VALUE})", + arity = "1") + private Wei minTransactionGasPrice = DEFAULT_MIN_TRANSACTION_GAS_PRICE; + + @Option( + names = {"--min-priority-fee"}, + description = + "Minimum priority fee per gas (in Wei) offered by a transaction for it to be included in a " + + "block (default: ${DEFAULT-VALUE})", + arity = "1") + private Wei minPriorityFeePerGas = DEFAULT_MIN_PRIORITY_FEE_PER_GAS; + + @Option( + names = {"--target-gas-limit"}, + description = + "Sets target gas limit per block." + + " If set, each block's gas limit will approach this setting over time.") + private Long targetGasLimit = null; + + @CommandLine.ArgGroup(validate = false) + private final Unstable unstableOptions = new Unstable(); + + static class Unstable { + @CommandLine.Option( + hidden = true, + names = {"--Xminer-remote-sealers-limit"}, + description = + "Limits the number of remote sealers that can submit their hashrates (default: ${DEFAULT-VALUE})") + private Integer remoteSealersLimit = DEFAULT_REMOTE_SEALERS_LIMIT; + + @CommandLine.Option( + hidden = true, + names = {"--Xminer-remote-sealers-hashrate-ttl"}, + description = + "Specifies the lifetime of each entry in the cache. An entry will be automatically deleted if no update has been received before the deadline (default: ${DEFAULT-VALUE} minutes)") + private Long remoteSealersTimeToLive = DEFAULT_REMOTE_SEALERS_TTL; + + @CommandLine.Option( + hidden = true, + names = {"--Xminer-pow-job-ttl"}, + description = + "Specifies the time PoW jobs are kept in cache and will accept a solution from miners (default: ${DEFAULT-VALUE} milliseconds)") + private Long powJobTimeToLive = DEFAULT_POW_JOB_TTL; + + @CommandLine.Option( + hidden = true, + names = {"--Xmax-ommers-depth"}, + description = + "Specifies the depth of ommer blocks to accept when receiving solutions (default: ${DEFAULT-VALUE})") + private Integer maxOmmersDepth = DEFAULT_MAX_OMMERS_DEPTH; + + @CommandLine.Option( + hidden = true, + names = {"--Xminer-stratum-extranonce"}, + description = "Extranonce for Stratum network miners (default: ${DEFAULT-VALUE})") + private String stratumExtranonce = "080c"; + + @CommandLine.Option( + hidden = true, + names = {"--Xpos-block-creation-max-time"}, + description = + "Specifies the maximum time, in milliseconds, a PoS block creation jobs is allowed to run. Must be positive and ≤ 12000 (default: ${DEFAULT-VALUE} milliseconds)") + private Long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME; + + @CommandLine.Option( + hidden = true, + names = {"--Xpos-block-creation-repetition-min-duration"}, + description = + "If a PoS block creation repetition takes less than this duration, in milliseconds," + + " then it waits before next repetition. Must be positive and ≤ 2000 (default: ${DEFAULT-VALUE} milliseconds)") + private Long posBlockCreationRepetitionMinDuration = + DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; + } + + private MiningOptions() {} + + /** + * Create mining options. + * + * @return the mining options + */ + public static MiningOptions create() { + return new MiningOptions(); + } + + /** + * 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 + * @param logger the logger + * @param isMergeEnabled is the Merge enabled? + * @param isEthHash is EthHash? + */ + public void validate( + final CommandLine commandLine, + final Logger logger, + final boolean isMergeEnabled, + final boolean isEthHash) { + if (Boolean.TRUE.equals(isMiningEnabled) && coinbase == null) { + throw new ParameterException( + commandLine, + "Unable to mine without a valid coinbase. Either disable mining (remove --miner-enabled) " + + "or specify the beneficiary of mining (via --miner-coinbase
)"); + } + if (Boolean.FALSE.equals(isMiningEnabled) && Boolean.TRUE.equals(iStratumMiningEnabled)) { + throw new ParameterException( + commandLine, + "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) " + + "or specify mining is enabled (--miner-enabled)"); + } + + // Check that block producer options work + if (!isMergeEnabled && isEthHash) { + CommandLineUtils.checkOptionDependencies( + logger, + commandLine, + "--miner-enabled", + !isMiningEnabled, + asList( + "--miner-coinbase", + "--min-gas-price", + "--min-priority-fee", + "--min-block-occupancy-ratio", + "--miner-extra-data")); + + // Check that mining options are able to work + CommandLineUtils.checkOptionDependencies( + logger, + commandLine, + "--miner-enabled", + !isMiningEnabled, + asList( + "--miner-stratum-enabled", + "--Xminer-remote-sealers-limit", + "--Xminer-remote-sealers-hashrate-ttl")); + } + + if (unstableOptions.posBlockCreationMaxTime <= 0 + || unstableOptions.posBlockCreationMaxTime > DEFAULT_POS_BLOCK_CREATION_MAX_TIME) { + throw new ParameterException( + commandLine, "--Xpos-block-creation-max-time must be positive and ≤ 12000"); + } + + if (unstableOptions.posBlockCreationRepetitionMinDuration <= 0 + || unstableOptions.posBlockCreationRepetitionMinDuration > 2000) { + throw new ParameterException( + commandLine, "--Xpos-block-creation-repetition-min-duration must be positive and ≤ 2000"); + } + } + + static MiningOptions fromConfig(final MiningParameters miningParameters) { + final MiningOptions miningOptions = MiningOptions.create(); + miningOptions.isMiningEnabled = miningParameters.isMiningEnabled(); + miningOptions.iStratumMiningEnabled = miningParameters.isStratumMiningEnabled(); + miningOptions.stratumNetworkInterface = miningParameters.getStratumNetworkInterface(); + miningOptions.stratumPort = miningParameters.getStratumPort(); + miningOptions.extraData = miningParameters.getExtraData(); + miningOptions.minTransactionGasPrice = miningParameters.getMinTransactionGasPrice(); + miningOptions.minPriorityFeePerGas = miningParameters.getMinPriorityFeePerGas(); + miningOptions.minBlockOccupancyRatio = miningParameters.getMinBlockOccupancyRatio(); + miningOptions.unstableOptions.remoteSealersLimit = + miningParameters.getUnstable().getRemoteSealersLimit(); + miningOptions.unstableOptions.remoteSealersTimeToLive = + miningParameters.getUnstable().getRemoteSealersTimeToLive(); + miningOptions.unstableOptions.powJobTimeToLive = + miningParameters.getUnstable().getPowJobTimeToLive(); + miningOptions.unstableOptions.maxOmmersDepth = + miningParameters.getUnstable().getMaxOmmerDepth(); + miningOptions.unstableOptions.stratumExtranonce = + miningParameters.getUnstable().getStratumExtranonce(); + miningOptions.unstableOptions.posBlockCreationMaxTime = + miningParameters.getUnstable().getPosBlockCreationMaxTime(); + miningOptions.unstableOptions.posBlockCreationRepetitionMinDuration = + miningParameters.getUnstable().getPosBlockCreationRepetitionMinDuration(); + + miningParameters.getCoinbase().ifPresent(coinbase -> miningOptions.coinbase = coinbase); + miningParameters.getTargetGasLimit().ifPresent(tgl -> miningOptions.targetGasLimit = tgl); + return miningOptions; + } + + @Override + public MiningParameters toDomainObject() { + final var updatableInitValuesBuilder = + MutableInitValues.builder() + .isMiningEnabled(isMiningEnabled) + .extraData(extraData) + .minTransactionGasPrice(minTransactionGasPrice) + .minPriorityFeePerGas(minPriorityFeePerGas) + .minBlockOccupancyRatio(minBlockOccupancyRatio); + + if (targetGasLimit != null) { + updatableInitValuesBuilder.targetGasLimit(targetGasLimit); + } + if (coinbase != null) { + updatableInitValuesBuilder.coinbase(coinbase); + } + + final var miningParametersBuilder = + ImmutableMiningParameters.builder() + .mutableInitValues(updatableInitValuesBuilder.build()) + .isStratumMiningEnabled(iStratumMiningEnabled) + .stratumNetworkInterface(stratumNetworkInterface) + .stratumPort(stratumPort) + .unstable( + ImmutableMiningParameters.Unstable.builder() + .remoteSealersLimit(unstableOptions.remoteSealersLimit) + .remoteSealersTimeToLive(unstableOptions.remoteSealersTimeToLive) + .powJobTimeToLive(unstableOptions.powJobTimeToLive) + .maxOmmerDepth(unstableOptions.maxOmmersDepth) + .stratumExtranonce(unstableOptions.stratumExtranonce) + .posBlockCreationMaxTime(unstableOptions.posBlockCreationMaxTime) + .posBlockCreationRepetitionMinDuration( + unstableOptions.posBlockCreationRepetitionMinDuration) + .build()); + + return miningParametersBuilder.build(); + } + + @Override + public List getCLIOptions() { + return CommandLineUtils.getCLIOptions(this, new MiningOptions()); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java deleted file mode 100644 index 232554722e2..00000000000 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java +++ /dev/null @@ -1,151 +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.unstable; - -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_MAX_OMMERS_DEPTH; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POS_BLOCK_CREATION_MAX_TIME; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POW_JOB_TTL; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_LIMIT; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_TTL; - -import picocli.CommandLine; - -/** The Mining CLI options. */ -public class MiningOptions { - - @CommandLine.Option( - hidden = true, - names = {"--Xminer-remote-sealers-limit"}, - description = - "Limits the number of remote sealers that can submit their hashrates (default: ${DEFAULT-VALUE})") - private final Integer remoteSealersLimit = DEFAULT_REMOTE_SEALERS_LIMIT; - - @CommandLine.Option( - hidden = true, - names = {"--Xminer-remote-sealers-hashrate-ttl"}, - description = - "Specifies the lifetime of each entry in the cache. An entry will be automatically deleted if no update has been received before the deadline (default: ${DEFAULT-VALUE} minutes)") - private final Long remoteSealersTimeToLive = DEFAULT_REMOTE_SEALERS_TTL; - - @CommandLine.Option( - hidden = true, - names = {"--Xminer-pow-job-ttl"}, - description = - "Specifies the time PoW jobs are kept in cache and will accept a solution from miners (default: ${DEFAULT-VALUE} milliseconds)") - private final Long powJobTimeToLive = DEFAULT_POW_JOB_TTL; - - @CommandLine.Option( - hidden = true, - names = {"--Xmax-ommers-depth"}, - description = - "Specifies the depth of ommer blocks to accept when receiving solutions (default: ${DEFAULT-VALUE})") - private final Integer maxOmmersDepth = DEFAULT_MAX_OMMERS_DEPTH; - - @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. - @CommandLine.Option( - hidden = true, - names = {"--Xminer-stratum-extranonce"}, - description = "Extranonce for Stratum network miners (default: ${DEFAULT-VALUE})") - private String stratumExtranonce = "080c"; - - @CommandLine.Option( - hidden = true, - names = {"--Xpos-block-creation-max-time"}, - description = - "Specifies the maximum time, in milliseconds, a PoS block creation jobs is allowed to run. Must be positive and ≤ 12000 (default: ${DEFAULT-VALUE} milliseconds)") - private final Long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME; - - @CommandLine.Option( - hidden = true, - names = {"--Xpos-block-creation-repetition-min-duration"}, - description = - "If a PoS block creation repetition takes less than this duration, in milliseconds," - + " then it waits before next repetition. Must be positive and ≤ 2000 (default: ${DEFAULT-VALUE} milliseconds)") - private final Long posBlockCreationRepetitionMinDuration = - DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; - - /** - * Create mining options. - * - * @return the mining options - */ - public static MiningOptions create() { - return new MiningOptions(); - } - - /** - * Gets remote sealers limit. - * - * @return the remote sealers limit - */ - public Integer getRemoteSealersLimit() { - return remoteSealersLimit; - } - - /** - * Gets remote sealers time to live. - * - * @return the remote sealers time to live - */ - public Long getRemoteSealersTimeToLive() { - return remoteSealersTimeToLive; - } - - /** - * Gets stratum extra nonce. - * - * @return the stratum extra nonce - */ - public String getStratumExtranonce() { - return stratumExtranonce; - } - - /** - * Gets pow job time to live. - * - * @return the pow job time to live - */ - public Long getPowJobTimeToLive() { - return powJobTimeToLive; - } - - /** - * Gets max ommers depth. - * - * @return the max ommers depth - */ - public int getMaxOmmersDepth() { - return maxOmmersDepth; - } - - /** - * Gets pos block creation max time. - * - * @return the pos block creation max time - */ - public Long getPosBlockCreationMaxTime() { - return posBlockCreationMaxTime; - } - - /** - * Gets pos block creation repetition min duration. - * - * @return the pos block creation repetition min duration. - */ - public Long getPosBlockCreationRepetitionMinDuration() { - return posBlockCreationRepetitionMinDuration; - } -} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java index 9417aad8f55..ea8bfab8d14 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java @@ -16,10 +16,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static org.hyperledger.besu.cli.subcommands.blocks.BlocksSubCommand.COMMAND_NAME; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_MAX_OMMERS_DEPTH; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POW_JOB_TTL; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_LIMIT; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_TTL; import org.hyperledger.besu.chainexport.RlpBlockExporter; import org.hyperledger.besu.chainimport.JsonBlockImporter; @@ -35,6 +31,8 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.IncrementingNonceGenerator; import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.metrics.MetricsService; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; @@ -271,21 +269,14 @@ private MiningParameters getMiningParameters() { // Extradata and coinbase can be configured on a per-block level via the json file final Address coinbase = Address.ZERO; final Bytes extraData = Bytes.EMPTY; - return new MiningParameters.Builder() - .coinbase(coinbase) - .minTransactionGasPrice(minTransactionGasPrice) - .extraData(extraData) - .miningEnabled(false) - .stratumMiningEnabled(false) - .stratumNetworkInterface("0.0.0.0") - .stratumPort(8008) - .stratumExtranonce("080c") - .maybeNonceGenerator(new IncrementingNonceGenerator(0)) - .minBlockOccupancyRatio(0.0) - .remoteSealersLimit(DEFAULT_REMOTE_SEALERS_LIMIT) - .remoteSealersTimeToLive(DEFAULT_REMOTE_SEALERS_TTL) - .powJobTimeToLive(DEFAULT_POW_JOB_TTL) - .maxOmmerDepth(DEFAULT_MAX_OMMERS_DEPTH) + return ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .nonceGenerator(new IncrementingNonceGenerator(0)) + .extraData(extraData) + .minTransactionGasPrice(minTransactionGasPrice) + .coinbase(coinbase) + .build()) .build(); } @@ -381,7 +372,11 @@ public void run() { } private BesuController createBesuController() { - return parentCommand.parentCommand.buildController(); + return parentCommand + .parentCommand + .getControllerBuilder() + .miningParameters(MiningParameters.newDefault()) + .build(); } private void exportRlpFormat(final BesuController controller) throws IOException { 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 0115420005e..33b531b5903 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 @@ -110,7 +110,7 @@ public static void checkMultiOptionDependencies( } /** - * Fail if option doesnt meet requirement. + * Fail if option doesn't meet requirement. * * @param commandLine the command line * @param errorMessage the error message @@ -126,7 +126,8 @@ public static void failIfOptionDoesntMeetRequirement( final String affectedOptions = getAffectedOptions(commandLine, dependentOptionsNames); if (!affectedOptions.isEmpty()) { - throw new CommandLine.ParameterException(commandLine, errorMessage); + throw new CommandLine.ParameterException( + commandLine, errorMessage + " [" + affectedOptions + "]"); } } } @@ -177,9 +178,8 @@ public static List getCLIOptions(final Object currOptions, final Object 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)); + cliOpts.add(optAnn.names()[0] + "=" + formatValue(optConverter, optVal)); } } catch (IllegalAccessException e) { throw new RuntimeException(e); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java index 1e894e0d9c5..baad246a76b 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java @@ -148,6 +148,6 @@ protected CliqueContext createConsensusContext( @Override public MiningParameters getMiningParameterOverrides(final MiningParameters fromCli) { // Clique mines by default, reflect that with in the mining parameters: - return new MiningParameters.Builder(fromCli).miningEnabled(true).build(); + return fromCli.setMiningEnabled(true); } } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java index 0fce7f484ce..6f034e6f759 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java @@ -55,17 +55,15 @@ protected MiningCoordinator createMiningCoordinator( MainnetBlockHeaderValidator.MINIMUM_SECONDS_SINCE_PARENT, MainnetBlockHeaderValidator.TIMESTAMP_TOLERANCE_S, clock), - epochCalculator, - miningParameters.getPowJobTimeToLive(), - miningParameters.getMaxOmmerDepth()); + epochCalculator); final PoWMiningCoordinator miningCoordinator = new PoWMiningCoordinator( protocolContext.getBlockchain(), executor, syncState, - miningParameters.getRemoteSealersLimit(), - miningParameters.getRemoteSealersTimeToLive()); + miningParameters.getUnstable().getRemoteSealersLimit(), + miningParameters.getUnstable().getRemoteSealersTimeToLive()); miningCoordinator.addMinedBlockObserver(ethProtocolManager); miningCoordinator.setStratumMiningEnabled(miningParameters.isStratumMiningEnabled()); if (miningParameters.isMiningEnabled()) { diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index 6db71ef81ca..d4541d91b9c 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -134,7 +134,7 @@ protected MiningCoordinator createMiningCoordinator( transitionProtocolSchedule.getPreMergeSchedule(), protocolContext, transactionPool, - new MiningParameters.Builder(miningParameters).miningEnabled(false).build(), + MiningParameters.MINING_DISABLED, syncState, ethProtocolManager), mergeBesuControllerBuilder.createTransitionMiningCoordinator( diff --git a/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java index 0a0f5019a52..184c85f45de 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java @@ -21,7 +21,6 @@ import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.services.BesuService; import org.hyperledger.besu.plugin.services.PluginVersionsProvider; -import org.hyperledger.besu.util.log.FramedLogMessage; import java.io.IOException; import java.net.MalformedURLException; @@ -76,6 +75,7 @@ private enum Lifecycle { private final Map, ? super BesuService> serviceRegistry = new HashMap<>(); private final List plugins = new ArrayList<>(); private final List pluginVersions = new ArrayList<>(); + final List lines = new ArrayList<>(); /** * Add service. @@ -105,9 +105,7 @@ public Optional getService(final Class serviceType * @param pluginsDir the plugins dir */ public void registerPlugins(final Path pluginsDir) { - final List lines = new ArrayList<>(); - lines.add("plugins dir " + pluginsDir.toAbsolutePath()); - lines.add(""); + lines.add("Plugins:"); checkState( state == Lifecycle.UNINITIALIZED, "Besu plugins have already been registered. Cannot register additional plugins."); @@ -120,11 +118,13 @@ public void registerPlugins(final Path pluginsDir) { final ServiceLoader serviceLoader = ServiceLoader.load(BesuPlugin.class, pluginLoader); + int pluginsCount = 0; for (final BesuPlugin plugin : serviceLoader) { + pluginsCount++; try { plugin.register(this); LOG.info("Registered plugin of type {}.", plugin.getClass().getName()); - lines.add(String.format("SUCCESS %s", plugin.getClass().getSimpleName())); + lines.add(String.format(plugin.getClass().getSimpleName())); addPluginVersion(plugin); } catch (final Exception e) { LOG.error( @@ -139,13 +139,23 @@ public void registerPlugins(final Path pluginsDir) { } LOG.debug("Plugin registration complete."); - lines.add(""); - lines.add("TOTAL = " + plugins.size()); - LOG.debug(FramedLogMessage.generate(lines)); + lines.add( + String.format( + "TOTAL = %d of %d plugins successfully loaded", plugins.size(), pluginsCount)); + lines.add(String.format("from %s", pluginsDir.toAbsolutePath())); state = Lifecycle.REGISTERED; } + /** + * get the summary log, as a list of string lines + * + * @return the summary + */ + public List getPluginsSummaryLog() { + return lines; + } + private void addPluginVersion(final BesuPlugin plugin) { final Package pluginPackage = plugin.getClass().getPackage(); final String implTitle = diff --git a/besu/src/main/java/org/hyperledger/besu/services/RpcEndpointServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/RpcEndpointServiceImpl.java index 4513bf0bf39..94bb5560839 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/RpcEndpointServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/RpcEndpointServiceImpl.java @@ -28,7 +28,7 @@ import java.util.function.Function; import java.util.stream.Collectors; -/** The Rpc endpoint service implementation. */ +/** The RPC endpoint service implementation. */ public class RpcEndpointServiceImpl implements RpcEndpointService { private final Map> rpcMethods = new HashMap<>(); 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 485880ac50d..98c233197f3 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; @@ -33,6 +34,8 @@ 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.data.BlockTraceResult; +import org.hyperledger.besu.plugin.data.TransactionTraceResult; import org.hyperledger.besu.plugin.services.TraceService; import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; @@ -72,10 +75,9 @@ public TraceServiceImpl( * @param tracer an instance of OperationTracer */ @Override - public void traceBlock(final long blockNumber, final BlockAwareOperationTracer tracer) { - checkArgument(tracer != null); - final Optional block = blockchainQueries.getBlockchain().getBlockByNumber(blockNumber); - block.ifPresent(value -> trace(value, tracer)); + public BlockTraceResult traceBlock( + final long blockNumber, final BlockAwareOperationTracer tracer) { + return traceBlock(blockchainQueries.getBlockchain().getBlockByNumber(blockNumber), tracer); } /** @@ -85,10 +87,41 @@ public void traceBlock(final long blockNumber, final BlockAwareOperationTracer t * @param tracer an instance of OperationTracer */ @Override - public void traceBlock(final Hash hash, final BlockAwareOperationTracer tracer) { + public BlockTraceResult traceBlock(final Hash hash, final BlockAwareOperationTracer tracer) { + return traceBlock(blockchainQueries.getBlockchain().getBlockByHash(hash), tracer); + } + + private BlockTraceResult traceBlock( + final Optional maybeBlock, final BlockAwareOperationTracer tracer) { checkArgument(tracer != null); - final Optional block = blockchainQueries.getBlockchain().getBlockByHash(hash); - block.ifPresent(value -> trace(value, tracer)); + if (maybeBlock.isEmpty()) { + return BlockTraceResult.empty(); + } + + final Optional> results = trace(maybeBlock.get(), tracer); + + if (results.isEmpty()) { + return BlockTraceResult.empty(); + } + + final BlockTraceResult.Builder builder = BlockTraceResult.builder(); + + final List transactionProcessingResults = results.get(); + final List transactions = maybeBlock.get().getBody().getTransactions(); + for (int i = 0; i < transactionProcessingResults.size(); i++) { + final TransactionProcessingResult transactionProcessingResult = + transactionProcessingResults.get(i); + final TransactionTraceResult transactionTraceResult = + transactionProcessingResult.isInvalid() + ? TransactionTraceResult.error( + transactions.get(i).getHash(), + transactionProcessingResult.getValidationResult().getErrorMessage()) + : TransactionTraceResult.success(transactions.get(i).getHash()); + + builder.addTransactionTraceResult(transactionTraceResult); + } + + return builder.build(); } /** @@ -136,15 +169,20 @@ public void trace( }); } - private void trace(final Block block, final BlockAwareOperationTracer tracer) { + private Optional> 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))); + + final Optional> results = + Tracer.processTracing( + blockchainQueries, + block.getHash(), + traceableState -> + Optional.of(trace(blockchain, block, new ChainUpdater(traceableState), tracer))); tracer.traceEndBlock(block.getHeader(), block.getBody()); + + return results; } private List trace( diff --git a/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java b/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java index f831e1ecd59..276740fbfed 100644 --- a/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java +++ b/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java @@ -187,11 +187,7 @@ public void setUp() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters( - new MiningParameters.Builder() - .minTransactionGasPrice(Wei.of(1000)) - .miningEnabled(false) - .build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .dataDirectory(folder) diff --git a/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java b/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java index bfdd71b3d2a..c71d44284fb 100644 --- a/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java +++ b/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java @@ -111,7 +111,7 @@ private BesuController setUpControllerWithPrivacyEnabled(final boolean flexibleE .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .dataDirectory(dataDir) diff --git a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java index 93207b1d11a..43a4d2cd963 100644 --- a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java +++ b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java @@ -448,7 +448,7 @@ private BesuController getController( .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .dataDirectory(dataDir) .networkId(NETWORK_ID) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(nodeKey) .storageProvider(storageProvider) .metricsSystem(metricsSystem) diff --git a/besu/src/test/java/org/hyperledger/besu/chainexport/RlpBlockExporterTest.java b/besu/src/test/java/org/hyperledger/besu/chainexport/RlpBlockExporterTest.java index e6b60dad197..89e1b255479 100644 --- a/besu/src/test/java/org/hyperledger/besu/chainexport/RlpBlockExporterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/chainexport/RlpBlockExporterTest.java @@ -91,7 +91,7 @@ private static BesuController createController() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .privacyParameters(PrivacyParameters.DEFAULT) diff --git a/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java b/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java index 00c86133ea6..00ebc610823 100644 --- a/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java @@ -29,8 +29,9 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; -import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; @@ -421,9 +422,12 @@ protected BesuController createController(final GenesisConfigFile genesisConfigF .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.valueOf(10)) .miningParameters( - new MiningParameters.Builder() - .minTransactionGasPrice(Wei.ZERO) - .miningEnabled(true) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .build()) .build()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) diff --git a/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java b/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java index 3260b8ee55b..f9d543aca9f 100644 --- a/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java @@ -67,7 +67,7 @@ public void blockImport() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .privacyParameters(PrivacyParameters.DEFAULT) @@ -100,7 +100,7 @@ public void blockImportRejectsBadPow() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .privacyParameters(PrivacyParameters.DEFAULT) @@ -130,7 +130,7 @@ public void blockImportCanSkipPow() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .privacyParameters(PrivacyParameters.DEFAULT) 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 af28e7ba7c2..91a203ff576 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -35,7 +35,6 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.NET; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.PERM; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.WEB3; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POS_BLOCK_CREATION_MAX_TIME; import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.GOERLI_BOOTSTRAP_NODES; import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.GOERLI_DISCOVERY_URL; import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.MAINNET_BOOTSTRAP_NODES; @@ -48,7 +47,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -72,6 +70,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.tls.TlsConfiguration; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.eth.sync.SyncMode; @@ -161,20 +161,6 @@ public class BesuCommandTest extends CommandTestAbstract { (new JsonObject()).put("config", new JsonObject().put("ecCurve", "secp256k1")); private static final String ENCLAVE_PUBLIC_KEY_PATH = BesuCommand.class.getResource("/orion_publickey.pub").getPath(); - private static final JsonObject VALID_GENESIS_QBFT_POST_LONDON = - (new JsonObject()) - .put( - "config", - new JsonObject() - .put("londonBlock", 0) - .put("qbft", new JsonObject().put("blockperiodseconds", 5))); - private static final JsonObject VALID_GENESIS_IBFT2_POST_LONDON = - (new JsonObject()) - .put( - "config", - new JsonObject() - .put("londonBlock", 0) - .put("ibft2", new JsonObject().put("blockperiodseconds", 5))); private static final String[] VALID_ENODE_STRINGS = { "enode://" + VALID_NODE_ID + "@192.168.0.1:4567", @@ -916,11 +902,11 @@ public void envVariableOverridesValueFromConfigFile() { verify(mockControllerBuilder) .miningParameters( - new MiningParameters.Builder() - .coinbase(Address.fromHexString(expectedCoinbase)) - .minTransactionGasPrice(DefaultCommandValues.DEFAULT_MIN_TRANSACTION_GAS_PRICE) - .extraData(DefaultCommandValues.DEFAULT_EXTRA_DATA) - .miningEnabled(false) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .coinbase(Address.fromHexString(expectedCoinbase)) + .build()) .build()); } @@ -933,11 +919,11 @@ public void cliOptionOverridesEnvVariableAndConfig() { verify(mockControllerBuilder) .miningParameters( - new MiningParameters.Builder() - .coinbase(Address.fromHexString(expectedCoinbase)) - .minTransactionGasPrice(DefaultCommandValues.DEFAULT_MIN_TRANSACTION_GAS_PRICE) - .extraData(DefaultCommandValues.DEFAULT_EXTRA_DATA) - .miningEnabled(false) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .coinbase(Address.fromHexString(expectedCoinbase)) + .build()) .build()); } @@ -3652,261 +3638,6 @@ public void metricsAndMetricsPushMustNotBeUsedTogether() { .startsWith("--metrics-enabled option and --metrics-push-enabled option can't be used"); } - @Test - public void besuDoesNotStartInMiningModeIfCoinbaseNotSet() { - parseCommand("--miner-enabled"); - - Mockito.verifyNoInteractions(mockControllerBuilder); - } - - @Test - public void miningIsEnabledWhenSpecified() throws Exception { - final String coinbaseStr = String.format("%040x", 1); - parseCommand("--miner-enabled", "--miner-coinbase=" + coinbaseStr); - - final ArgumentCaptor miningArg = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningArg.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - assertThat(miningArg.getValue().isMiningEnabled()).isTrue(); - assertThat(miningArg.getValue().getCoinbase()) - .isEqualTo(Optional.of(Address.fromHexString(coinbaseStr))); - } - - @Test - public void stratumMiningIsEnabledWhenSpecified() throws Exception { - final String coinbaseStr = String.format("%040x", 1); - parseCommand("--miner-enabled", "--miner-coinbase=" + coinbaseStr, "--miner-stratum-enabled"); - - final ArgumentCaptor miningArg = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningArg.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - assertThat(miningArg.getValue().isMiningEnabled()).isTrue(); - assertThat(miningArg.getValue().getCoinbase()) - .isEqualTo(Optional.of(Address.fromHexString(coinbaseStr))); - assertThat(miningArg.getValue().isStratumMiningEnabled()).isTrue(); - } - - @Test - public void stratumMiningOptionsRequiresServiceToBeEnabled() { - - parseCommand("--network", "dev", "--miner-stratum-enabled"); - - verifyOptionsConstraintLoggerCall("--miner-enabled", "--miner-stratum-enabled"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)) - .startsWith( - "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) or specify mining is enabled (--miner-enabled)"); - } - - @Test - public void stratumMiningOptionsRequiresServiceToBeEnabledToml() throws IOException { - final Path toml = createTempFile("toml", "miner-stratum-enabled=true\n"); - - parseCommand("--network", "dev", "--config-file", toml.toString()); - - verifyOptionsConstraintLoggerCall("--miner-enabled", "--miner-stratum-enabled"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)) - .startsWith( - "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) or specify mining is enabled (--miner-enabled)"); - } - - @Test - public void blockProducingOptionsWarnsMinerShouldBeEnabled() { - - final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); - parseCommand( - "--network", - "dev", - "--miner-coinbase", - requestedCoinbase.toString(), - "--min-gas-price", - "42", - "--miner-extra-data", - "0x1122334455667788990011223344556677889900112233445566778899001122"); - - verifyOptionsConstraintLoggerCall( - "--miner-enabled", "--miner-coinbase", "--min-gas-price", "--miner-extra-data"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void blockProducingOptionsWarnsMinerShouldBeEnabledToml() throws IOException { - - final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); - - final Path toml = - createTempFile( - "toml", - "network=\"dev\"\n" - + "miner-coinbase=\"" - + requestedCoinbase - + "\"\n" - + "min-gas-price=42\n" - + "miner-extra-data=\"0x1122334455667788990011223344556677889900112233445566778899001122\"\n"); - - parseCommand("--config-file", toml.toString()); - - verifyOptionsConstraintLoggerCall( - "--miner-enabled", "--miner-coinbase", "--min-gas-price", "--miner-extra-data"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void blockProducingOptionsDoNotWarnWhenPoA() throws IOException { - - final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); - parseCommand( - "--genesis-file", - genesisFileQBFT.toString(), - "--min-gas-price", - "42", - "--miner-extra-data", - "0x1122334455667788990011223344556677889900112233445566778899001122"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - - final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); - parseCommand( - "--genesis-file", - genesisFileIBFT2.toString(), - "--min-gas-price", - "42", - "--miner-extra-data", - "0x1122334455667788990011223344556677889900112233445566778899001122"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void blockProducingOptionsDoNotWarnWhenMergeEnabled() { - - final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); - // TODO: once we have mainnet TTD, we can remove the TTD override parameter here - // https://github.com/hyperledger/besu/issues/3874 - parseCommand( - "--override-genesis-config", - "terminalTotalDifficulty=1337", - "--miner-coinbase", - requestedCoinbase.toString(), - "--min-gas-price", - "42", - "--miner-extra-data", - "0x1122334455667788990011223344556677889900112233445566778899001122"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void minGasPriceRequiresMainOption() { - parseCommand("--min-gas-price", "0", "--network", "dev"); - - verifyOptionsConstraintLoggerCall("--miner-enabled", "--min-gas-price"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void minGasPriceRequiresMainOptionToml() throws IOException { - final Path toml = createTempFile("toml", "min-gas-price=0\nnetwork=\"dev\"\n"); - - parseCommand("--config-file", toml.toString()); - - verifyOptionsConstraintLoggerCall("--miner-enabled", "--min-gas-price"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void minGasPriceDoesNotRequireMainOptionWhenPoA() throws IOException { - final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); - parseCommand("--genesis-file", genesisFileQBFT.toString(), "--min-gas-price", "0"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - - final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); - parseCommand("--genesis-file", genesisFileIBFT2.toString(), "--min-gas-price", "0"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void miningParametersAreCaptured() { - final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); - final String extraDataString = - "0x1122334455667788990011223344556677889900112233445566778899001122"; - parseCommand( - "--miner-enabled", - "--miner-coinbase=" + requestedCoinbase.toString(), - "--min-gas-price=15", - "--miner-extra-data=" + extraDataString); - - final ArgumentCaptor miningArg = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningArg.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - assertThat(miningArg.getValue().getCoinbase()).isEqualTo(Optional.of(requestedCoinbase)); - assertThat(miningArg.getValue().getMinTransactionGasPrice()).isEqualTo(Wei.of(15)); - assertThat(miningArg.getValue().getExtraData()).isEqualTo(Bytes.fromHexString(extraDataString)); - } - @Test public void colorCanBeEnabledOrDisabledExplicitly() { Stream.of(true, false) @@ -4471,31 +4202,6 @@ public void canNotUseFlexiblePrivacyWhenPrivacyPluginEnabled() { "No Payload Provider has been provided. You must register one when enabling privacy plugin!"); } - private Path createFakeGenesisFile(final JsonObject jsonGenesis) throws IOException { - final Path genesisFile = Files.createTempFile("genesisFile", ""); - Files.write(genesisFile, encodeJsonGenesis(jsonGenesis).getBytes(UTF_8)); - genesisFile.toFile().deleteOnExit(); - return genesisFile; - } - - private Path createTempFile(final String filename, final String contents) throws IOException { - final Path file = Files.createTempFile(filename, ""); - Files.write(file, contents.getBytes(UTF_8)); - file.toFile().deleteOnExit(); - return file; - } - - private Path createTempFile(final String filename, final byte[] contents) throws IOException { - final Path file = Files.createTempFile(filename, ""); - Files.write(file, contents); - file.toFile().deleteOnExit(); - return file; - } - - private String encodeJsonGenesis(final JsonObject jsonGenesis) { - return jsonGenesis.encodePrettily(); - } - private static String escapeTomlString(final String s) { return StringEscapeUtils.escapeJava(s); } @@ -4619,42 +4325,6 @@ public void tomlThatHasInvalidOptions() throws IOException { .contains("Unknown options in TOML configuration file: invalid_option, invalid_option2"); } - @Test - public void targetGasLimitIsEnabledWhenSpecified() { - parseCommand("--target-gas-limit=10000000"); - - @SuppressWarnings("unchecked") - final ArgumentCaptor miningParametersArgumentCaptor = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningParametersArgumentCaptor.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - - assertThat(miningParametersArgumentCaptor.getValue().getTargetGasLimit().get().longValue()) - .isEqualTo(10_000_000L); - } - - @Test - public void targetGasLimitIsDisabledWhenNotSpecified() { - parseCommand(); - - @SuppressWarnings("unchecked") - final ArgumentCaptor gasLimitCalculatorArgumentCaptor = - ArgumentCaptor.forClass(GasLimitCalculator.class); - - verify(mockControllerBuilder).gasLimitCalculator(gasLimitCalculatorArgumentCaptor.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - - assertThat(gasLimitCalculatorArgumentCaptor.getValue()) - .isEqualTo(GasLimitCalculator.constant()); - } - @Test public void requiredBlocksSetWhenSpecified() { final long blockNumber = 8675309L; @@ -5069,11 +4739,7 @@ public void assertThatCheckPortClashRejectsAsExpected() throws Exception { public void assertThatCheckPortClashRejectsAsExpectedForEngineApi() throws Exception { // use WS port for HTTP final int port = 8545; - // TODO: once we have mainnet TTD, we can remove the TTD override parameter here - // https://github.com/hyperledger/besu/issues/3874 parseCommand( - "--override-genesis-config", - "terminalTotalDifficulty=1337", "--rpc-http-enabled", "--rpc-http-port", String.valueOf(port), @@ -5275,37 +4941,6 @@ public void logWarnIfFastSyncMinPeersUsedWithFullSync() { .contains("--fast-sync-min-peers can't be used with FULL sync-mode"); } - @Test - public void posBlockCreationMaxTimeDefaultValue() { - parseCommand(); - assertThat(getPosBlockCreationMaxTimeValue()).isEqualTo(DEFAULT_POS_BLOCK_CREATION_MAX_TIME); - } - - @Test - public void posBlockCreationMaxTimeOption() { - parseCommand("--Xpos-block-creation-max-time", "7000"); - assertThat(getPosBlockCreationMaxTimeValue()).isEqualTo(7000L); - } - - private long getPosBlockCreationMaxTimeValue() { - final ArgumentCaptor miningArg = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningArg.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - return miningArg.getValue().getPosBlockCreationMaxTime(); - } - - @Test - public void posBlockCreationMaxTimeOutOfAllowedRange() { - parseCommand("--Xpos-block-creation-max-time", "17000"); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains("--Xpos-block-creation-max-time must be positive and ≤ 12000"); - } - @Test public void portInUseReportsError() throws IOException { final ServerSocket serverSocket = new ServerSocket(8545); 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 1c991d64935..bccf28c4522 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.chainimport.JsonBlockImporter; import org.hyperledger.besu.chainimport.RlpBlockImporter; import org.hyperledger.besu.cli.config.EthNetworkConfig; +import org.hyperledger.besu.cli.options.MiningOptions; import org.hyperledger.besu.cli.options.stable.EthstatsOptions; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; @@ -105,6 +106,7 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; +import io.vertx.core.json.JsonObject; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.awaitility.Awaitility; @@ -126,6 +128,20 @@ @RunWith(MockitoJUnitRunner.class) public abstract class CommandTestAbstract { private static final Logger TEST_LOGGER = LoggerFactory.getLogger(CommandTestAbstract.class); + protected static final JsonObject VALID_GENESIS_QBFT_POST_LONDON = + (new JsonObject()) + .put( + "config", + new JsonObject() + .put("londonBlock", 0) + .put("qbft", new JsonObject().put("blockperiodseconds", 5))); + protected static final JsonObject VALID_GENESIS_IBFT2_POST_LONDON = + (new JsonObject()) + .put( + "config", + new JsonObject() + .put("londonBlock", 0) + .put("ibft2", new JsonObject().put("blockperiodseconds", 5))); protected final PrintStream originalOut = System.out; protected final PrintStream originalErr = System.err; protected final ByteArrayOutputStream commandOutput = new ByteArrayOutputStream(); @@ -460,6 +476,25 @@ private TestBesuCommand getTestBesuCommand(final TestType testType) { } } + protected Path createTempFile(final String filename, final byte[] contents) throws IOException { + final Path file = Files.createTempFile(filename, ""); + Files.write(file, contents); + file.toFile().deleteOnExit(); + return file; + } + + protected Path createFakeGenesisFile(final JsonObject jsonGenesis) throws IOException { + return createTempFile("genesisFile", encodeJsonGenesis(jsonGenesis).getBytes(UTF_8)); + } + + protected String encodeJsonGenesis(final JsonObject jsonGenesis) { + return jsonGenesis.encodePrettily(); + } + + protected Path createTempFile(final String filename, final String contents) throws IOException { + return createTempFile(filename, contents.getBytes(UTF_8)); + } + @CommandLine.Command public static class TestBesuCommand extends BesuCommand { @@ -530,6 +565,10 @@ public EthProtocolOptions getEthProtocolOptions() { return stableTransactionPoolOptions; } + public MiningOptions getMiningOptions() { + return miningOptions; + } + public TransactionPoolOptions getUnstableTransactionPoolOptions() { return unstableTransactionPoolOptions; } 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 ef7da0c7669..09b4e3b1365 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 @@ -16,6 +16,9 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.verify; import org.hyperledger.besu.cli.CommandTestAbstract; @@ -113,6 +116,7 @@ protected void internalTestSuccess(final Consumer assertion, final String... assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + verify(mockControllerBuilder).build(); } protected void internalTestFailure(final String errorMsg, final String... args) { @@ -121,4 +125,29 @@ protected void internalTestFailure(final String errorMsg, final String... args) assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).contains(errorMsg); } + + /** + * Check logger calls + * + *

Here we check the calls to logger and not the result of the log line as we don't test the + * logger itself but the fact that we call it. + * + * @param dependentOptions the string representing the list of dependent options names + * @param mainOption the main option name + */ + protected void verifyOptionsConstraintLoggerCall( + final String mainOption, final String... dependentOptions) { + verify(mockLogger, atLeast(1)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()); + assertThat(stringArgumentCaptor.getAllValues().get(0)).isEqualTo(DEPENDENCY_WARNING_MSG); + + for (final String option : dependentOptions) { + assertThat(stringArgumentCaptor.getAllValues().get(1)).contains(option); + } + + assertThat(stringArgumentCaptor.getAllValues().get(2)).isEqualTo(mainOption); + } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java new file mode 100644 index 00000000000..7d6d3cfe06e --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java @@ -0,0 +1,340 @@ +/* + * 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; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_POS_BLOCK_CREATION_MAX_TIME; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.verify; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.Unstable; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class MiningOptionsTest extends AbstractCLIOptionsTest { + + @Test + public void besuDoesNotStartInMiningModeIfCoinbaseNotSet() { + internalTestFailure( + "Unable to mine without a valid coinbase. Either disable mining (remove --miner-enabled) or specify the beneficiary of mining (via --miner-coinbase

)", + "--miner-enabled"); + } + + @Test + public void miningIsEnabledWhenSpecified() { + final String coinbaseStr = String.format("%040x", 1); + internalTestSuccess( + miningOpts -> { + assertThat(miningOpts.isMiningEnabled()).isTrue(); + assertThat(miningOpts.getCoinbase()) + .isEqualTo(Optional.of(Address.fromHexString(coinbaseStr))); + }, + "--miner-enabled", + "--miner-coinbase=" + coinbaseStr); + } + + @Test + public void stratumMiningIsEnabledWhenSpecified() { + final String coinbaseStr = String.format("%040x", 1); + internalTestSuccess( + miningOpts -> { + assertThat(miningOpts.isMiningEnabled()).isTrue(); + assertThat(miningOpts.getCoinbase()) + .isEqualTo(Optional.of(Address.fromHexString(coinbaseStr))); + assertThat(miningOpts.isStratumMiningEnabled()).isTrue(); + }, + "--miner-enabled", + "--miner-coinbase=" + coinbaseStr, + "--miner-stratum-enabled"); + } + + @Test + public void stratumMiningOptionsRequiresServiceToBeEnabled() { + internalTestFailure( + "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) or specify mining is enabled (--miner-enabled)", + "--network", + "dev", + "--miner-stratum-enabled"); + } + + @Test + public void stratumMiningOptionsRequiresServiceToBeEnabledToml() throws IOException { + final Path toml = createTempFile("toml", "miner-stratum-enabled=true\n"); + internalTestFailure( + "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) or specify mining is enabled (--miner-enabled)", + "--network", + "dev", + "--config-file", + toml.toString()); + } + + @Test + public void blockProducingOptionsWarnsMinerShouldBeEnabled() { + final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); + internalTestSuccess( + miningOpts -> + verifyOptionsConstraintLoggerCall( + "--miner-enabled", "--miner-coinbase", "--min-gas-price", "--miner-extra-data"), + "--network", + "dev", + "--miner-coinbase", + requestedCoinbase.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + } + + @Test + public void blockProducingOptionsWarnsMinerShouldBeEnabledToml() throws IOException { + + final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); + + final Path toml = + createTempFile( + "toml", + "network=\"dev\"\n" + + "miner-coinbase=\"" + + requestedCoinbase + + "\"\n" + + "min-gas-price=42\n" + + "miner-extra-data=\"0x1122334455667788990011223344556677889900112233445566778899001122\"\n"); + + internalTestSuccess( + miningOpts -> + verifyOptionsConstraintLoggerCall( + "--miner-enabled", "--miner-coinbase", "--min-gas-price", "--miner-extra-data"), + "--config-file", + toml.toString()); + } + + @Test + public void blockProducingOptionsDoNotWarnWhenPoAQBFT() throws IOException { + + final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); + internalTestSuccess( + miningOpts -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--genesis-file", + genesisFileQBFT.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + } + + @Test + public void blockProducingOptionsDoNotWarnWhenPoAIBFT2() throws IOException { + + final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); + internalTestSuccess( + miningOpts -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--genesis-file", + genesisFileIBFT2.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + } + + @Test + public void blockProducingOptionsDoNotWarnWhenMergeEnabled() { + + final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); + internalTestSuccess( + miningOpt -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--miner-coinbase", + requestedCoinbase.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + } + + @Test + public void minGasPriceRequiresMainOption() { + internalTestSuccess( + miningOpt -> verifyOptionsConstraintLoggerCall("--miner-enabled", "--min-gas-price"), + "--min-gas-price", + "0", + "--network", + "dev"); + } + + @Test + public void minGasPriceRequiresMainOptionToml() throws IOException { + final Path toml = createTempFile("toml", "min-gas-price=0\nnetwork=\"dev\"\n"); + internalTestSuccess( + miningOpt -> verifyOptionsConstraintLoggerCall("--miner-enabled", "--min-gas-price"), + "--config-file", + toml.toString()); + } + + @Test + public void minGasPriceDoesNotRequireMainOptionWhenPoAQBFT() throws IOException { + final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); + internalTestSuccess( + miningOpt -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--genesis-file", + genesisFileQBFT.toString(), + "--min-gas-price", + "0"); + } + + @Test + public void minGasPriceDoesNotRequireMainOptionWhenPoAIBFT2() throws IOException { + final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); + + internalTestSuccess( + miningOpt -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--genesis-file", + genesisFileIBFT2.toString(), + "--min-gas-price", + "0"); + } + + @Test + public void miningParametersAreCaptured() { + final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); + final String extraDataString = + "0x1122334455667788990011223344556677889900112233445566778899001122"; + internalTestSuccess( + miningParams -> { + assertThat(miningParams.getCoinbase()).isEqualTo(Optional.of(requestedCoinbase)); + assertThat(miningParams.getMinTransactionGasPrice()).isEqualTo(Wei.of(15)); + assertThat(miningParams.getExtraData()).isEqualTo(Bytes.fromHexString(extraDataString)); + }, + "--miner-enabled", + "--miner-coinbase=" + requestedCoinbase.toString(), + "--min-gas-price=15", + "--miner-extra-data=" + extraDataString); + } + + @Test + public void targetGasLimitIsEnabledWhenSpecified() { + internalTestSuccess( + miningParams -> + assertThat(miningParams.getTargetGasLimit().getAsLong()).isEqualTo(10_000_000L), + "--target-gas-limit=10000000"); + } + + @Test + public void targetGasLimitIsDisabledWhenNotSpecified() { + internalTestSuccess( + miningParams -> { + final ArgumentCaptor gasLimitCalculatorArgumentCaptor = + ArgumentCaptor.forClass(GasLimitCalculator.class); + + verify(mockControllerBuilder) + .gasLimitCalculator(gasLimitCalculatorArgumentCaptor.capture()); + assertThat(gasLimitCalculatorArgumentCaptor.getValue()) + .isEqualTo(GasLimitCalculator.constant()); + }); + } + + @Test + public void posBlockCreationMaxTimeDefaultValue() { + internalTestSuccess( + miningParams -> + assertThat(miningParams.getUnstable().getPosBlockCreationMaxTime()) + .isEqualTo(DEFAULT_POS_BLOCK_CREATION_MAX_TIME)); + } + + @Test + public void posBlockCreationMaxTimeOption() { + internalTestSuccess( + miningParams -> + assertThat(miningParams.getUnstable().getPosBlockCreationMaxTime()).isEqualTo(7000L), + "--Xpos-block-creation-max-time", + "7000"); + } + + @Test + public void posBlockCreationMaxTimeOutOfAllowedRange() { + internalTestFailure( + "--Xpos-block-creation-max-time must be positive and ≤ 12000", + "--Xpos-block-creation-max-time", + "17000"); + } + + @Override + protected MiningParameters createDefaultDomainObject() { + return MiningParameters.newDefault(); + } + + @Override + protected MiningParameters createCustomizedDomainObject() { + return ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .extraData(Bytes.fromHexString("0xabc321")) + .minBlockOccupancyRatio(0.5) + .coinbase(Address.ZERO) + .build()) + .isStratumMiningEnabled(true) + .unstable(Unstable.builder().posBlockCreationMaxTime(1000).build()) + .build(); + } + + @Override + protected MiningOptions optionsFromDomainObject(final MiningParameters domainObject) { + return MiningOptions.fromConfig(domainObject); + } + + @Override + protected MiningOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { + return besuCommand.getMiningOptions(); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java index 6a0b5592d27..5c62076e692 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java @@ -174,7 +174,8 @@ public void callingBlockImportSubCommandWithJSONAndSkipPOWFails() { @Test public void callingBlockImportSubCommandHelpMustDisplayUsage() { parseCommand(BLOCK_SUBCOMMAND_NAME, BLOCK_IMPORT_SUBCOMMAND_NAME, "--help"); - assertThat(commandOutput.toString(UTF_8)).isEqualTo(EXPECTED_BLOCK_IMPORT_USAGE); + assertThat(commandOutput.toString(UTF_8)) + .isEqualToNormalizingNewlines(EXPECTED_BLOCK_IMPORT_USAGE); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } 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 c7c6466e602..a24479e8617 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java @@ -84,7 +84,6 @@ public class BesuControllerBuilderTest { @Mock CheckpointConfigOptions checkpointConfigOptions; @Mock SynchronizerConfiguration synchronizerConfiguration; @Mock EthProtocolConfiguration ethProtocolConfiguration; - @Mock MiningParameters miningParameters; @Mock PrivacyParameters privacyParameters; @Mock Clock clock; @Mock StorageProvider storageProvider; @@ -95,6 +94,8 @@ public class BesuControllerBuilderTest { @Mock WorldStatePreimageStorage worldStatePreimageStorage; private final TransactionPoolConfiguration poolConfiguration = TransactionPoolConfiguration.DEFAULT; + private final MiningParameters miningParameters = MiningParameters.newDefault(); + private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); BigInteger networkId = BigInteger.ONE; 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 b1f59554af3..33a539f8bc2 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java @@ -75,6 +75,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; +import org.mockito.Answers; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -89,7 +90,10 @@ public class MergeBesuControllerBuilderTest { @Mock SynchronizerConfiguration synchronizerConfiguration; @Mock EthProtocolConfiguration ethProtocolConfiguration; @Mock CheckpointConfigOptions checkpointConfigOptions; - @Mock MiningParameters miningParameters; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + MiningParameters miningParameters; + @Mock PrivacyParameters privacyParameters; @Mock Clock clock; @Mock StorageProvider storageProvider; @@ -143,6 +147,7 @@ public void setup() { when(worldStatePreimageStorage.updater()) .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class)); + when(miningParameters.getTargetGasLimit()).thenReturn(OptionalLong.empty()); besuControllerBuilder = visitWithMockConfigs(new MergeBesuControllerBuilder()); } diff --git a/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java index 9fc337095f2..0b1a98a210f 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java @@ -34,6 +34,8 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; @@ -99,7 +101,7 @@ public void setup() { .thenReturn(mock(CliqueContext.class)); when(protocolContext.getConsensusContext(PostMergeContext.class)).thenReturn(mergeContext); when(protocolContext.getConsensusContext(MergeContext.class)).thenReturn(mergeContext); - miningParameters = new MiningParameters.Builder().miningEnabled(false).build(); + miningParameters = MiningParameters.newDefault(); } @Test @@ -118,7 +120,10 @@ public void assertPoWIsNotMiningPreMerge() { @Test public void assertPowMiningPreMerge() { - miningParameters = new MiningParameters.Builder().miningEnabled(true).build(); + miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().isMiningEnabled(true).build()) + .build(); var transCoordinator = buildTransitionCoordinator(powBuilder, postMergeBuilder); assertThat(transCoordinator.isMiningBeforeMerge()).isTrue(); } diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 8b6b10f5493..921d4e7fbe6 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -33,7 +33,8 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; -import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; @@ -155,7 +156,10 @@ public void setUp() { TestClock.system(ZoneId.systemDefault()), new NoOpMetricsSystem(), syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder().minTransactionGasPrice(Wei.ZERO).build()) + .build(), txPoolConfig, null); 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 cb88a9b9730..30d51cfa737 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java @@ -26,6 +26,8 @@ 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.data.BlockTraceResult; +import org.hyperledger.besu.plugin.data.TransactionTraceResult; import org.hyperledger.besu.plugin.services.TraceService; import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; @@ -115,7 +117,18 @@ void shouldReturnTheCorrectWorldViewForTxStartEnd() { final TxStartEndTracer txStartEndTracer = new TxStartEndTracer(); // block contains 1 transaction - traceService.traceBlock(31, txStartEndTracer); + final BlockTraceResult blockTraceResult = traceService.traceBlock(31, txStartEndTracer); + + assertThat(blockTraceResult).isNotNull(); + + final List transactionTraceResults = + blockTraceResult.transactionTraceResults(); + assertThat(transactionTraceResults.size()).isEqualTo(1); + + assertThat(transactionTraceResults.get(0).getTxHash()).isNotNull(); + assertThat(transactionTraceResults.get(0).getStatus()) + .isEqualTo(TransactionTraceResult.Status.SUCCESS); + assertThat(transactionTraceResults.get(0).errorMessage()).isEmpty(); assertThat(txStartEndTracer.txStartWorldView).isNotNull(); assertThat(txStartEndTracer.txEndWorldView).isNotNull(); diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index f4c1d517d91..2bbf25a97d4 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -137,6 +137,7 @@ miner-stratum-enabled=false miner-coinbase="0x0000000000000000000000000000000000000002" miner-extra-data="0x444F4E27542050414E4943202120484F444C2C20484F444C2C20484F444C2021" min-gas-price=1 +min-priority-fee=0 min-block-occupancy-ratio=0.7 miner-stratum-host="0.0.0.0" miner-stratum-port=8008 diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java index 30bf9b6476d..d991fb9db4c 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java @@ -23,14 +23,13 @@ import org.hyperledger.besu.consensus.common.EpochManager; import org.hyperledger.besu.consensus.common.validator.ValidatorVote; import org.hyperledger.besu.cryptoservices.NodeKey; -import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator; 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.MiningParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; @@ -38,7 +37,6 @@ import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import java.util.Optional; -import java.util.function.Supplier; /** The Clique block creator. */ public class CliqueBlockCreator extends AbstractBlockCreator { @@ -49,40 +47,31 @@ public class CliqueBlockCreator extends AbstractBlockCreator { /** * Instantiates a new Clique block creator. * - * @param coinbase the coinbase - * @param targetGasLimitSupplier the target gas limit supplier + * @param miningParameters the mining parameters * @param extraDataCalculator the extra data calculator * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule * @param nodeKey the node key - * @param minTransactionGasPrice the min transaction gas price - * @param minBlockOccupancyRatio the min block occupancy ratio * @param parentHeader the parent header * @param epochManager the epoch manager */ public CliqueBlockCreator( - final Address coinbase, - final Supplier> targetGasLimitSupplier, + final MiningParameters miningParameters, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final NodeKey nodeKey, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader, final EpochManager epochManager) { super( - coinbase, + miningParameters, __ -> Util.publicKeyToAddress(nodeKey.getPublicKey()), - targetGasLimitSupplier, extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, Optional.empty()); this.nodeKey = nodeKey; diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java index 9f2be2e1e76..81b754b267c 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java @@ -35,7 +35,6 @@ import java.util.Collection; import java.util.List; import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import com.google.common.annotations.VisibleForTesting; @@ -72,6 +71,7 @@ public CliqueMinerExecutor( this.nodeKey = nodeKey; this.localAddress = Util.publicKeyToAddress(nodeKey.getPublicKey()); this.epochManager = epochManager; + miningParams.setCoinbase(localAddress); } @Override @@ -82,15 +82,12 @@ public CliqueBlockMiner createMiner( final Function blockCreator = (header) -> new CliqueBlockCreator( - localAddress, // TOOD(tmm): This can be removed (used for voting not coinbase). - () -> targetGasLimit.map(AtomicLong::longValue), + miningParameters, this::calculateExtraData, transactionPool, protocolContext, protocolSchedule, nodeKey, - minTransactionGasPrice, - minBlockOccupancyRatio, header, epochManager); @@ -106,7 +103,7 @@ public CliqueBlockMiner createMiner( @Override public Optional
getCoinbase() { - return Optional.of(localAddress); + return miningParameters.getCoinbase(); } /** @@ -120,7 +117,8 @@ Bytes calculateExtraData(final BlockHeader parentHeader) { final List
validators = Lists.newArrayList(); final Bytes vanityDataToInsert = - ConsensusHelpers.zeroLeftPad(extraData, CliqueExtraData.EXTRA_VANITY_LENGTH); + ConsensusHelpers.zeroLeftPad( + miningParameters.getExtraData(), CliqueExtraData.EXTRA_VANITY_LENGTH); // Building ON TOP of canonical head, if the next block is epoch, include validators. if (epochManager.isEpochBlock(parentHeader.getNumber() + 1)) { diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java index 0b0210d4ef3..3ddfdb1149d 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java @@ -47,6 +47,8 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -134,17 +136,17 @@ public void proposerAddressCanBeExtractFromAConstructedBlock() { CliqueExtraData.createWithoutProposerSeal(Bytes.wrap(new byte[32]), validatorList); final Address coinbase = AddressHelpers.ofValue(1); + + final MiningParameters miningParameters = createMiningParameters(extraData, coinbase); + final CliqueBlockCreator blockCreator = new CliqueBlockCreator( - coinbase, - () -> Optional.of(10_000_000L), + miningParameters, parent -> extraData, createTransactionPool(), protocolContext, protocolSchedule, proposerNodeKey, - Wei.ZERO, - 0.8, blockchain.getChainHeadHeader(), epochManager); @@ -163,17 +165,16 @@ public void insertsValidVoteIntoConstructedBlock() { when(voteProvider.getVoteAfterBlock(any(), any())) .thenReturn(Optional.of(new ValidatorVote(VoteType.ADD, coinbase, a1))); + final MiningParameters miningParameters = createMiningParameters(extraData, coinbase); + final CliqueBlockCreator blockCreator = new CliqueBlockCreator( - coinbase, - () -> Optional.of(10_000_000L), + miningParameters, parent -> extraData, createTransactionPool(), protocolContext, protocolSchedule, proposerNodeKey, - Wei.ZERO, - 0.8, blockchain.getChainHeadHeader(), epochManager); @@ -197,17 +198,16 @@ public void insertsNoVoteWhenAtEpoch() { when(mockVoteProvider.getVoteAfterBlock(any(), any())) .thenReturn(Optional.of(new ValidatorVote(VoteType.ADD, coinbase, a1))); + final MiningParameters miningParameters = createMiningParameters(extraData, coinbase); + final CliqueBlockCreator blockCreator = new CliqueBlockCreator( - coinbase, - () -> Optional.of(10_000_000L), + miningParameters, parent -> extraData, createTransactionPool(), protocolContext, protocolSchedule, proposerNodeKey, - Wei.ZERO, - 0.8, blockchain.getChainHeadHeader(), epochManager); @@ -240,4 +240,19 @@ private TransactionPool createTransactionPool() { transactionPool.setEnabled(); return transactionPool; } + + private static MiningParameters createMiningParameters( + final Bytes extraData, final Address coinbase) { + final MiningParameters miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(extraData) + .targetGasLimit(10_000_000L) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(coinbase) + .build()) + .build(); + return miningParameters; + } } diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java index 4a3bf5424d7..7a089f2ef37 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java @@ -37,6 +37,8 @@ import org.hyperledger.besu.ethereum.core.AddressHelpers; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -101,18 +103,15 @@ public void setup() { public void extraDataCreatedOnEpochBlocksContainsValidators() { final Bytes vanityData = generateRandomVanityData(); + final MiningParameters miningParameters = createMiningParameters(vanityData); + final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, cliqueProtocolSchedule, createTransactionPool(), proposerNodeKey, - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(vanityData) - .miningEnabled(false) - .build(), + miningParameters, mock(CliqueBlockScheduler.class), new EpochManager(EPOCH_LENGTH)); @@ -138,18 +137,15 @@ public void extraDataCreatedOnEpochBlocksContainsValidators() { public void extraDataForNonEpochBlocksDoesNotContainValidaors() { final Bytes vanityData = generateRandomVanityData(); + final MiningParameters miningParameters = createMiningParameters(vanityData); + final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, cliqueProtocolSchedule, createTransactionPool(), proposerNodeKey, - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(vanityData) - .miningEnabled(false) - .build(), + miningParameters, mock(CliqueBlockScheduler.class), new EpochManager(EPOCH_LENGTH)); @@ -175,18 +171,15 @@ public void shouldUseLatestVanityData() { final Bytes initialVanityData = generateRandomVanityData(); final Bytes modifiedVanityData = generateRandomVanityData(); + final MiningParameters miningParameters = createMiningParameters(initialVanityData); + final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, cliqueProtocolSchedule, createTransactionPool(), proposerNodeKey, - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(initialVanityData) - .miningEnabled(false) - .build(), + miningParameters, mock(CliqueBlockScheduler.class), new EpochManager(EPOCH_LENGTH)); @@ -240,4 +233,15 @@ private Bytes generateRandomVanityData() { random.nextBytes(vanityData); return Bytes.wrap(vanityData); } + + private static MiningParameters createMiningParameters(final Bytes vanityData) { + return ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(vanityData) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(AddressHelpers.ofValue(1)) + .build()) + .build(); + } } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java index 4e5a39f335f..4c5e773966f 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java @@ -20,17 +20,16 @@ import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; import org.hyperledger.besu.consensus.common.bft.BftHelpers; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import java.util.Optional; -import java.util.function.Supplier; /** The Bft block creator. */ // This class is responsible for creating a block without committer seals (basically it was just @@ -42,40 +41,33 @@ public class BftBlockCreator extends AbstractBlockCreator { /** * Instantiates a new Bft block creator. * + * @param miningParameters the mining parameters * @param forksSchedule the forks schedule * @param localAddress the local address - * @param targetGasLimitSupplier the target gas limit supplier * @param extraDataCalculator the extra data calculator * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule - * @param minTransactionGasPrice the min transaction gas price - * @param minBlockOccupancyRatio the min block occupancy ratio * @param parentHeader the parent header * @param bftExtraDataCodec the bft extra data codec */ public BftBlockCreator( + final MiningParameters miningParameters, final ForksSchedule forksSchedule, final Address localAddress, - final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader, final BftExtraDataCodec bftExtraDataCodec) { super( - localAddress, + miningParameters.setCoinbase(localAddress), miningBeneficiaryCalculator(localAddress, forksSchedule), - targetGasLimitSupplier, extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, Optional.empty()); this.bftExtraDataCodec = bftExtraDataCodec; diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java index 35c6a33c94e..fab04b1a770 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java @@ -40,7 +40,6 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; import org.apache.tuweni.bytes.Bytes; @@ -52,6 +51,8 @@ public class BftBlockCreatorFactory { /** The Forks schedule. */ protected final ForksSchedule forksSchedule; + /** The Mining parameters */ + protected final MiningParameters miningParameters; private final TransactionPool transactionPool; /** The Protocol context. */ @@ -63,13 +64,6 @@ public class BftBlockCreatorFactory { private final Address localAddress; - /** The Vanity data. */ - protected volatile Bytes vanityData; - - private volatile Wei minTransactionGasPrice; - private volatile Double minBlockOccupancyRatio; - private volatile Optional targetGasLimit; - /** * Instantiates a new Bft block creator factory. * @@ -94,11 +88,8 @@ public BftBlockCreatorFactory( this.protocolSchedule = protocolSchedule; this.forksSchedule = forksSchedule; this.localAddress = localAddress; - this.minTransactionGasPrice = miningParams.getMinTransactionGasPrice(); - this.minBlockOccupancyRatio = miningParams.getMinBlockOccupancyRatio(); - this.vanityData = miningParams.getExtraData(); + this.miningParameters = miningParams; this.bftExtraDataCodec = bftExtraDataCodec; - this.targetGasLimit = miningParams.getTargetGasLimit(); } /** @@ -110,15 +101,13 @@ public BftBlockCreatorFactory( */ public BlockCreator create(final BlockHeader parentHeader, final int round) { return new BftBlockCreator( + miningParameters, forksSchedule, localAddress, - () -> targetGasLimit.map(AtomicLong::longValue), ph -> createExtraData(round, ph), transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, bftExtraDataCodec); } @@ -129,7 +118,8 @@ public BlockCreator create(final BlockHeader parentHeader, final int round) { * @param extraData the extra data */ public void setExtraData(final Bytes extraData) { - this.vanityData = extraData.copy(); + + miningParameters.setExtraData(extraData.copy()); } /** @@ -138,7 +128,7 @@ public void setExtraData(final Bytes extraData) { * @param minTransactionGasPrice the min transaction gas price */ public void setMinTransactionGasPrice(final Wei minTransactionGasPrice) { - this.minTransactionGasPrice = minTransactionGasPrice; + miningParameters.setMinTransactionGasPrice(minTransactionGasPrice); } /** @@ -147,7 +137,7 @@ public void setMinTransactionGasPrice(final Wei minTransactionGasPrice) { * @return the min transaction gas price */ public Wei getMinTransactionGasPrice() { - return minTransactionGasPrice; + return miningParameters.getMinTransactionGasPrice(); } /** @@ -171,7 +161,8 @@ public Bytes createExtraData(final int round, final BlockHeader parentHeader) { final BftExtraData extraData = new BftExtraData( - ConsensusHelpers.zeroLeftPad(vanityData, BftExtraDataCodec.EXTRA_VANITY_LENGTH), + ConsensusHelpers.zeroLeftPad( + miningParameters.getExtraData(), BftExtraDataCodec.EXTRA_VANITY_LENGTH), Collections.emptyList(), toVote(proposal), round, @@ -187,9 +178,7 @@ public Bytes createExtraData(final int round, final BlockHeader parentHeader) { */ public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { - this.targetGasLimit.ifPresentOrElse( - existing -> existing.set(newTargetGasLimit), - () -> this.targetGasLimit = Optional.of(new AtomicLong(newTargetGasLimit))); + miningParameters.setTargetGasLimit(newTargetGasLimit); } else { throw new UnsupportedOperationException("Specified target gas limit is invalid"); } diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java index 42d68250821..9b0d9f65ad9 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java @@ -77,6 +77,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -304,11 +306,14 @@ private static ControllerAndState createControllerAndFinalState( final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); final MiningParameters miningParams = - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(Bytes.wrap("Ibft Int tests".getBytes(UTF_8))) - .miningEnabled(true) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .extraData(Bytes.wrap("Ibft Int tests".getBytes(UTF_8))) + .coinbase(AddressHelpers.ofValue(1)) + .build()) .build(); final StubGenesisConfigOptions genesisConfigOptions = new StubGenesisConfigOptions(); diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java index 1039b3579c1..6065c269be7 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java @@ -41,6 +41,8 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -150,11 +152,28 @@ public BlockHeaderValidator.Builder createBlockHeaderRuleset( transactionPool.setEnabled(); + final MiningParameters miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData( + bftExtraDataEncoder.encode( + new BftExtraData( + Bytes.wrap(new byte[32]), + Collections.emptyList(), + Optional.empty(), + 0, + initialValidatorList))) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(AddressHelpers.ofValue(1)) + .build()) + .build(); + final BftBlockCreator blockCreator = new BftBlockCreator( + miningParameters, forksSchedule, initialValidatorList.get(0), - () -> Optional.of(10_000_000L), parent -> bftExtraDataEncoder.encode( new BftExtraData( @@ -166,8 +185,6 @@ public BlockHeaderValidator.Builder createBlockHeaderRuleset( transactionPool, protContext, protocolSchedule, - Wei.ZERO, - 0.8, parentHeader, bftExtraDataEncoder); diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java index dd8adae7e9b..b81a941816a 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java @@ -15,12 +15,12 @@ package org.hyperledger.besu.consensus.merge.blockcreation; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Withdrawal; @@ -30,55 +30,37 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.function.Supplier; import org.apache.tuweni.bytes.Bytes32; /** The Merge block creator. */ class MergeBlockCreator extends AbstractBlockCreator { - /** - * On PoS you do not need to compete with other nodes for block production, since you have an - * allocated slot for that, so in this case make sense to always try to fill the block, if there - * are enough pending transactions, until the remaining gas is less than the minimum needed for - * the smaller transaction. So for PoS the min-block-occupancy-ratio option is set to always try - * to fill 100% of the block. - */ - private static final double TRY_FILL_BLOCK = 1.0; /** * Instantiates a new Merge block creator. * - * @param coinbase the coinbase - * @param targetGasLimitSupplier the target gas limit supplier + * @param miningParameters the mining parameters * @param extraDataCalculator the extra data calculator * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule - * @param minTransactionGasPrice the min transaction gas price - * @param miningBeneficiary the mining beneficiary * @param parentHeader the parent header */ public MergeBlockCreator( - final Address coinbase, - final Supplier> targetGasLimitSupplier, + final MiningParameters miningParameters, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Address miningBeneficiary, final BlockHeader parentHeader, final Optional
depositContractAddress) { super( - miningBeneficiary, - __ -> miningBeneficiary, - targetGasLimitSupplier, + miningParameters, + __ -> miningParameters.getCoinbase().orElseThrow(), extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - TRY_FILL_BLOCK, parentHeader, depositContractAddress); } 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 d7e2856941f..9a5d26f1c63 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 @@ -56,8 +56,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import com.google.common.annotations.VisibleForTesting; @@ -69,18 +67,20 @@ /** The Merge coordinator. */ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListener { private static final Logger LOG = LoggerFactory.getLogger(MergeCoordinator.class); + /** + * On PoS you do not need to compete with other nodes for block production, since you have an + * allocated slot for that, so in this case make sense to always try to fill the block, if there + * are enough pending transactions, until the remaining gas is less than the minimum needed for + * the smaller transaction. So for PoS the min-block-occupancy-ratio option is set to always try + * to fill 100% of the block. + */ + private static final double TRY_FILL_BLOCK = 1.0; - /** The Target gas limit. */ - protected final AtomicLong targetGasLimit; + private static final long DEFAULT_TARGET_GAS_LIMIT = 30000000L; /** The Mining parameters. */ protected final MiningParameters miningParameters; /** The Merge block creator factory. */ protected final MergeBlockCreatorFactory mergeBlockCreatorFactory; - /** The Extra data. */ - protected final AtomicReference extraData = - new AtomicReference<>(Bytes.fromHexString("0x")); - /** The Latest descends from terminal. */ - protected final AtomicReference latestDescendsFromTerminal = new AtomicReference<>(); /** The Merge context. */ protected final MergeContext mergeContext; /** The Protocol context. */ @@ -118,28 +118,30 @@ public MergeCoordinator( this.protocolSchedule = protocolSchedule; this.blockBuilderExecutor = blockBuilderExecutor; this.mergeContext = protocolContext.getConsensusContext(MergeContext.class); - this.miningParameters = miningParams; this.backwardSyncContext = backwardSyncContext; - this.targetGasLimit = - miningParameters - .getTargetGasLimit() - // TODO: revisit default target gas limit - .orElse(new AtomicLong(30000000L)); - this.extraData.set(miningParams.getExtraData()); + + if (miningParams.getCoinbase().isEmpty()) { + miningParams.setCoinbase(Address.ZERO); + } + if (miningParams.getTargetGasLimit().isEmpty()) { + miningParams.setTargetGasLimit(DEFAULT_TARGET_GAS_LIMIT); + } + miningParams.setMinBlockOccupancyRatio(TRY_FILL_BLOCK); + + this.miningParameters = miningParams; this.mergeBlockCreatorFactory = - (parentHeader, address) -> - new MergeBlockCreator( - address.or(miningParameters::getCoinbase).orElse(Address.ZERO), - () -> Optional.of(targetGasLimit.longValue()), - parent -> extraData.get(), - transactionPool, - protocolContext, - protocolSchedule, - this.miningParameters.getMinTransactionGasPrice(), - address.or(miningParameters::getCoinbase).orElse(Address.ZERO), - parentHeader, - depositContractAddress); + (parentHeader, address) -> { + address.ifPresent(miningParams::setCoinbase); + return new MergeBlockCreator( + miningParameters, + parent -> miningParameters.getExtraData(), + transactionPool, + protocolContext, + protocolSchedule, + parentHeader, + depositContractAddress); + }; this.backwardSyncContext.subscribeBadChainListener(this); } @@ -166,13 +168,12 @@ public MergeCoordinator( this.protocolSchedule = protocolSchedule; this.blockBuilderExecutor = blockBuilderExecutor; this.mergeContext = protocolContext.getConsensusContext(MergeContext.class); - this.miningParameters = miningParams; this.backwardSyncContext = backwardSyncContext; - this.targetGasLimit = - miningParameters - .getTargetGasLimit() - // TODO: revisit default target gas limit - .orElse(new AtomicLong(30000000L)); + if (miningParams.getTargetGasLimit().isEmpty()) { + miningParams.setTargetGasLimit(DEFAULT_TARGET_GAS_LIMIT); + } + miningParams.setMinBlockOccupancyRatio(TRY_FILL_BLOCK); + this.miningParameters = miningParams; this.mergeBlockCreatorFactory = mergeBlockCreatorFactory; @@ -210,7 +211,7 @@ public Wei getMinTransactionGasPrice() { @Override public void setExtraData(final Bytes extraData) { - this.extraData.set(extraData); + this.miningParameters.setExtraData(extraData); } @Override @@ -234,7 +235,7 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti @Override public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { - this.targetGasLimit.set(newTargetGasLimit); + this.miningParameters.setTargetGasLimit(newTargetGasLimit); } else { throw new IllegalArgumentException("Specified target gas limit is invalid"); } @@ -363,11 +364,12 @@ private void tryToBuildBetterBlock( LOG.debug( "Block creation started for payload id {}, remaining time is {}ms", payloadIdentifier, - miningParameters.getPosBlockCreationMaxTime()); + miningParameters.getUnstable().getPosBlockCreationMaxTime()); blockBuilderExecutor .buildProposal(() -> retryBlockCreationUntilUseful(payloadIdentifier, blockCreator)) - .orTimeout(miningParameters.getPosBlockCreationMaxTime(), TimeUnit.MILLISECONDS) + .orTimeout( + miningParameters.getUnstable().getPosBlockCreationMaxTime(), TimeUnit.MILLISECONDS) .whenComplete( (unused, throwable) -> { if (throwable != null) { @@ -393,7 +395,9 @@ private Void retryBlockCreationUntilUseful( final long lastDuration = System.currentTimeMillis() - lastStartAt; final long waitBeforeRepetition = Math.max( - 100, miningParameters.getPosBlockCreationRepetitionMinDuration() - lastDuration); + 100, + miningParameters.getUnstable().getPosBlockCreationRepetitionMinDuration() + - lastDuration); LOG.debug("Waiting {}ms before repeating block creation", waitBeforeRepetition); Thread.sleep(waitBeforeRepetition); } catch (final CancellationException | InterruptedException ce) { @@ -594,7 +598,8 @@ && isDescendantOf(newHead, blockchain.getChainHeadHeader())) { Optional parentOfNewHead = blockchain.getBlockHeader(newHead.getParentHash()); if (parentOfNewHead.isPresent() - && parentOfNewHead.get().getTimestamp() >= newHead.getTimestamp()) { + && Long.compareUnsigned(newHead.getTimestamp(), parentOfNewHead.get().getTimestamp()) + <= 0) { return ForkchoiceResult.withFailure( INVALID, "new head timestamp not greater than parent", latestValid); } 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 bc7e424133d..7c54b9260f9 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 @@ -25,7 +25,6 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doCallRealMethod; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -57,6 +56,9 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.Unstable; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -98,7 +100,6 @@ import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; @@ -132,11 +133,13 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper { @Mock ProposalBuilderExecutor proposalBuilderExecutor; private final Address coinbase = genesisAllocations(getPosGenesisConfigFile()).findFirst().get(); - @Spy MiningParameters miningParameters = - new MiningParameters.Builder() - .coinbase(coinbase) - .posBlockCreationRepetitionMinDuration(REPETITION_MIN_DURATION) + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().coinbase(coinbase).build()) + .unstable( + Unstable.builder() + .posBlockCreationRepetitionMinDuration(REPETITION_MIN_DURATION) + .build()) .build(); private MergeCoordinator coordinator; @@ -278,14 +281,11 @@ public void exceptionDuringBuildingBlockShouldNotBeInvalid() MergeBlockCreator beingSpiedOn = spy( new MergeBlockCreator( - address.or(miningParameters::getCoinbase).orElse(Address.ZERO), - () -> Optional.of(30000000L), + miningParameters, parent -> Bytes.EMPTY, transactionPool, protocolContext, protocolSchedule, - this.miningParameters.getMinTransactionGasPrice(), - address.or(miningParameters::getCoinbase).orElse(Address.ZERO), parentHeader, Optional.empty())); @@ -548,7 +548,11 @@ public void shouldRetryBlockCreationOnRecoverableError() @Test public void shouldStopRetryBlockCreationIfTimeExpired() throws InterruptedException { final AtomicLong retries = new AtomicLong(0); - doReturn(100L).when(miningParameters).getPosBlockCreationMaxTime(); + miningParameters = + ImmutableMiningParameters.builder() + .from(miningParameters) + .unstable(Unstable.builder().posBlockCreationMaxTime(100).build()) + .build(); doAnswer( invocation -> { retries.incrementAndGet(); @@ -738,7 +742,10 @@ public void shouldCancelPreviousBlockCreationJobIfCalledAgainWithNewPayloadId() public void shouldUseExtraDataFromMiningParameters() { final Bytes extraData = Bytes.fromHexString("0x1234"); - miningParameters = new MiningParameters.Builder().extraData(extraData).build(); + miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().extraData(extraData).build()) + .build(); this.coordinator = new MergeCoordinator( diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java index d5dbd139c6c..cd96d9cbdbb 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java @@ -33,7 +33,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; -import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardSyncContext; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; @@ -93,7 +94,9 @@ public void setUp() { mockProtocolSchedule, CompletableFuture::runAsync, mockTransactionPool, - new MiningParameters.Builder().coinbase(coinbase).build(), + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().coinbase(coinbase).build()) + .build(), mock(BackwardSyncContext.class), Optional.empty()); mergeContext.setIsPostMerge(genesisState.getBlock().getHeader().getDifficulty()); diff --git a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java index ac824df6c0f..2b0386d9066 100644 --- a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java +++ b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java @@ -90,6 +90,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.core.Util; @@ -365,11 +367,14 @@ private static ControllerAndState createControllerAndFinalState( final List qbftForks) { final MiningParameters miningParams = - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(Bytes.wrap("Qbft Int tests".getBytes(UTF_8))) - .miningEnabled(true) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .extraData(Bytes.wrap("Qbft Int tests".getBytes(UTF_8))) + .coinbase(AddressHelpers.ofValue(1)) + .build()) .build(); final StubGenesisConfigOptions genesisConfigOptions = new StubGenesisConfigOptions(); diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java index c2007ededf7..2f993c4d1bb 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java @@ -83,7 +83,8 @@ public Bytes createExtraData(final int round, final BlockHeader parentHeader) { // vote and validators will come from contract instead of block final BftExtraData extraData = new BftExtraData( - ConsensusHelpers.zeroLeftPad(vanityData, BftExtraDataCodec.EXTRA_VANITY_LENGTH), + ConsensusHelpers.zeroLeftPad( + miningParameters.getExtraData(), BftExtraDataCodec.EXTRA_VANITY_LENGTH), Collections.emptyList(), Optional.empty(), round, diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java index fa2e8158530..d7b63bc215c 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java @@ -30,6 +30,8 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; @@ -46,9 +48,14 @@ public class QbftBlockCreatorFactoryTest { @BeforeEach @SuppressWarnings("unchecked") - public void setUp() throws Exception { - final MiningParameters miningParams = mock(MiningParameters.class); - when(miningParams.getExtraData()).thenReturn(Bytes.wrap("Qbft tests".getBytes(UTF_8))); + public void setUp() { + final MiningParameters miningParams = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(Bytes.wrap("Qbft tests".getBytes(UTF_8))) + .build()) + .build(); final MutableQbftConfigOptions qbftConfigOptions = new MutableQbftConfigOptions(JsonQbftConfigOptions.DEFAULT); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java index 518d5b8c364..fd6ca9a1313 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java @@ -30,6 +30,7 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; @@ -128,6 +129,7 @@ public Map methods() { final P2PNetwork peerDiscovery = mock(P2PNetwork.class); final EthPeers ethPeers = mock(EthPeers.class); final TransactionPool transactionPool = mock(TransactionPool.class); + final MiningParameters miningParameters = mock(MiningParameters.class); final PoWMiningCoordinator miningCoordinator = mock(PoWMiningCoordinator.class); final ObservableMetricsSystem metricsSystem = new NoOpMetricsSystem(); final Optional accountWhitelistController = @@ -169,6 +171,7 @@ public Map methods() { context, filterManager, transactionPool, + miningParameters, miningCoordinator, metricsSystem, new HashSet<>(), diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java index 555146ca7cb..116c2d75181 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java @@ -119,7 +119,7 @@ public void setUp() { protocolContext, batchAddedListener, ethContext, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + MiningParameters.newDefault(), new TransactionPoolMetrics(metricsSystem), TransactionPoolConfiguration.DEFAULT, null); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java index 873956d34b1..70025eeef07 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java @@ -119,7 +119,7 @@ public void setUp() { protocolContext, batchAddedListener, ethContext, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + MiningParameters.newDefault(), new TransactionPoolMetrics(metricsSystem), TransactionPoolConfiguration.DEFAULT, null); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/ApiConfiguration.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/ApiConfiguration.java index f8b52054d57..6652682fc4f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/ApiConfiguration.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/ApiConfiguration.java @@ -16,6 +16,8 @@ package org.hyperledger.besu.ethereum.api; +import java.util.function.LongSupplier; + import org.immutables.value.Value; @Value.Immutable @@ -33,8 +35,8 @@ public double getGasPricePercentile() { } @Value.Default - public long getGasPriceMin() { - return 1_000_000_000L; // 1 GWei + public LongSupplier getGasPriceMinSupplier() { + return () -> 1_000_000_000L; // 1 GWei } @Value.Default diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index fe7e432081b..78e3f078f7d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -153,6 +153,8 @@ public enum RpcMethod { MINER_SET_ETHERBASE("miner_setEtherbase"), MINER_START("miner_start"), MINER_STOP("miner_stop"), + MINER_GET_MIN_PRIORITY_FEE("miner_getMinPriorityFee"), + MINER_SET_MIN_PRIORITY_FEE("miner_setMinPriorityFee"), NET_ENODE("net_enode"), NET_LISTENING("net_listening"), NET_PEER_COUNT("net_peerCount"), 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 6f65dc5bd3d..b5c38c1e682 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 @@ -140,7 +140,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) .map(WithdrawalParameter::toWithdrawal) .collect(toList()))); Optional maybeError = - isPayloadAttributesValid(requestId, payloadAttributes, withdrawals); + isPayloadAttributesValid(requestId, payloadAttributes); if (maybeError.isPresent()) { LOG.atWarn() .setMessage("RpcError {}: {}") @@ -229,9 +229,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) } protected abstract Optional isPayloadAttributesValid( - final Object requestId, - final EnginePayloadAttributesParameter payloadAttributes, - final Optional> maybeWithdrawals); + final Object requestId, final EnginePayloadAttributesParameter payloadAttribute); protected Optional isPayloadAttributeRelevantToNewHead( final Object requestId, 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 c8263450e72..a5b8acfc056 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 @@ -267,7 +267,8 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) } if (maybeParentHeader.isPresent() - && (blockParam.getTimestamp() <= maybeParentHeader.get().getTimestamp())) { + && (Long.compareUnsigned(maybeParentHeader.get().getTimestamp(), blockParam.getTimestamp()) + >= 0)) { return respondWithInvalid( reqId, blockParam, diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1.java index 24d63fbd434..6aa5f0964b2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV1.java @@ -20,10 +20,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadAttributesParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import java.util.List; import java.util.Optional; import io.vertx.core.Vertx; @@ -41,9 +39,7 @@ public EngineForkchoiceUpdatedV1( @Override protected Optional isPayloadAttributesValid( - final Object requestId, - final EnginePayloadAttributesParameter payloadAttributes, - final Optional> maybeWithdrawals) { + final Object requestId, final EnginePayloadAttributesParameter payloadAttributes) { return Optional.empty(); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java index c4daa688d47..b6406a3e662 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java @@ -20,10 +20,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadAttributesParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import java.util.List; import java.util.Optional; import io.vertx.core.Vertx; @@ -52,9 +50,7 @@ public String getName() { @Override protected Optional isPayloadAttributesValid( - final Object requestId, - final EnginePayloadAttributesParameter payloadAttributes, - final Optional> maybeWithdrawals) { + final Object requestId, final EnginePayloadAttributesParameter payloadAttributes) { if (payloadAttributes.getTimestamp() >= cancunTimestamp) { if (payloadAttributes.getParentBeaconBlockRoot() == null || payloadAttributes.getParentBeaconBlockRoot().isEmpty()) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java index 5b33f653fb3..c070d220854 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java @@ -21,12 +21,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadAttributesParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; -import java.util.List; import java.util.Optional; import io.vertx.core.Vertx; @@ -91,9 +89,7 @@ protected ValidationResult validateForkSupported(final long blockT @Override protected Optional isPayloadAttributesValid( - final Object requestId, - final EnginePayloadAttributesParameter payloadAttributes, - final Optional> maybeWithdrawals) { + final Object requestId, final EnginePayloadAttributesParameter payloadAttributes) { if (payloadAttributes.getParentBeaconBlockRoot() == null) { LOG.error( "Parent beacon block root hash not present in payload attributes after cancun hardfork"); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java index c7d8a10a4a1..dff7174b49d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java @@ -71,7 +71,8 @@ protected ValidationResult validateParameters( @Override protected ValidationResult validateForkSupported(final long blockTimestamp) { if (protocolSchedule.isPresent()) { - if (cancun.isPresent() && blockTimestamp >= cancun.get().milestone()) { + if (cancun.isPresent() + && Long.compareUnsigned(blockTimestamp, cancun.get().milestone()) >= 0) { return ValidationResult.valid(); } else { return ValidationResult.invalid( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerGetMinPriorityFee.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerGetMinPriorityFee.java new file mode 100644 index 00000000000..f473fede16f --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerGetMinPriorityFee.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.api.jsonrpc.internal.methods.miner; + +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +public class MinerGetMinPriorityFee implements JsonRpcMethod { + private final MiningParameters miningParameters; + + public MinerGetMinPriorityFee(final MiningParameters miningParameters) { + this.miningParameters = miningParameters; + } + + @Override + public String getName() { + return RpcMethod.MINER_GET_MIN_PRIORITY_FEE.getMethodName(); + } + + @Override + public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { + return new JsonRpcSuccessResponse( + requestContext.getRequest().getId(), miningParameters.getMinPriorityFeePerGas().getValue()); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetMinPriorityFee.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetMinPriorityFee.java new file mode 100644 index 00000000000..ddc19cfe1de --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetMinPriorityFee.java @@ -0,0 +1,53 @@ +/* + * 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.api.jsonrpc.internal.methods.miner; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MinerSetMinPriorityFee implements JsonRpcMethod { + private static final Logger LOG = LoggerFactory.getLogger(MinerSetMinPriorityFee.class); + + private final MiningParameters miningParameters; + + public MinerSetMinPriorityFee(final MiningParameters miningParameters) { + this.miningParameters = miningParameters; + } + + @Override + public String getName() { + return RpcMethod.MINER_SET_MIN_PRIORITY_FEE.getMethodName(); + } + + @Override + public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { + try { + final Wei minPriorityFeePerGas = Wei.of(requestContext.getRequiredParameter(0, Long.class)); + miningParameters.setMinPriorityFeePerGas(minPriorityFeePerGas); + LOG.debug("min priority fee per gas changed to {}", minPriorityFeePerGas); + return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), true); + } catch (final IllegalArgumentException invalidJsonRpcParameters) { + return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), false); + } + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/UnsignedLongParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/UnsignedLongParameter.java index 039592d28c2..2e9ae8087ec 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/UnsignedLongParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/UnsignedLongParameter.java @@ -17,25 +17,28 @@ import static com.google.common.base.Preconditions.checkArgument; import com.fasterxml.jackson.annotation.JsonCreator; +import org.checkerframework.checker.signedness.qual.Unsigned; public class UnsignedLongParameter { - private final long value; + @Unsigned private final long value; @JsonCreator public UnsignedLongParameter(final String value) { checkArgument(value != null); - this.value = Long.decode(value); - checkArgument(this.value >= 0); + if (value.startsWith("0x")) { + this.value = Long.parseUnsignedLong(value.substring(2), 16); + } else { + this.value = Long.parseUnsignedLong(value, 16); + } } @JsonCreator - public UnsignedLongParameter(final long value) { + public UnsignedLongParameter(final @Unsigned long value) { this.value = value; - checkArgument(this.value >= 0); } - public long getValue() { + public @Unsigned long getValue() { return value; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java index 5effa4dd5da..c8a7ccb7529 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; @@ -62,6 +63,7 @@ public Map methods( final ProtocolContext protocolContext, final FilterManager filterManager, final TransactionPool transactionPool, + final MiningParameters miningParameters, final MiningCoordinator miningCoordinator, final ObservableMetricsSystem metricsSystem, final Set supportedCapabilities, @@ -126,7 +128,7 @@ public Map methods( jsonRpcConfiguration, webSocketConfiguration, metricsConfiguration), - new MinerJsonRpcMethods(miningCoordinator), + new MinerJsonRpcMethods(miningParameters, miningCoordinator), new PermJsonRpcMethods(accountsAllowlistController, nodeAllowlistController), new PrivJsonRpcMethods( blockchainQueries, diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/MinerJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/MinerJsonRpcMethods.java index 35d6502ad3f..1742fe1e552 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/MinerJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/MinerJsonRpcMethods.java @@ -17,19 +17,25 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerChangeTargetGasLimit; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerGetMinPriorityFee; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetCoinbase; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetEtherbase; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetMinPriorityFee; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerStart; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerStop; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import java.util.Map; public class MinerJsonRpcMethods extends ApiGroupJsonRpcMethods { private final MiningCoordinator miningCoordinator; + private final MiningParameters miningParameters; - public MinerJsonRpcMethods(final MiningCoordinator miningCoordinator) { + public MinerJsonRpcMethods( + final MiningParameters miningParameters, final MiningCoordinator miningCoordinator) { + this.miningParameters = miningParameters; this.miningCoordinator = miningCoordinator; } @@ -46,6 +52,8 @@ protected Map create() { new MinerStop(miningCoordinator), minerSetCoinbase, new MinerSetEtherbase(minerSetCoinbase), - new MinerChangeTargetGasLimit(miningCoordinator)); + new MinerChangeTargetGasLimit(miningCoordinator), + new MinerGetMinPriorityFee(miningParameters), + new MinerSetMinPriorityFee(miningParameters)); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index 04bfdd9727a..eede84fb82b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -969,7 +969,7 @@ public Optional gasPrice() { ? Optional.empty() : Optional.of( Math.max( - apiConfig.getGasPriceMin(), + apiConfig.getGasPriceMinSupplier().getAsLong(), Math.min( apiConfig.getGasPriceMax(), gasCollection[ diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java index bba69967d52..9a03f782e5b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java @@ -118,7 +118,7 @@ public void setupTest() throws Exception { context.getWorldStateArchive(), Optional.empty(), Optional.empty(), - ImmutableApiConfiguration.builder().gasPriceMin(0).build()); + ImmutableApiConfiguration.builder().gasPriceMinSupplier(() -> 0).build()); final Set supportedCapabilities = new HashSet<>(); supportedCapabilities.add(EthProtocol.ETH62); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java index d998f54c7e4..b0fc14e63bc 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.core.Transaction; @@ -133,6 +134,7 @@ protected Map getRpcMethods( final Synchronizer synchronizerMock = mock(Synchronizer.class); final P2PNetwork peerDiscoveryMock = mock(P2PNetwork.class); final TransactionPool transactionPoolMock = mock(TransactionPool.class); + final MiningParameters miningParameters = mock(MiningParameters.class); final PoWMiningCoordinator miningCoordinatorMock = mock(PoWMiningCoordinator.class); when(transactionPoolMock.addTransactionViaApi(any(Transaction.class))) .thenReturn(ValidationResult.valid()); @@ -173,6 +175,7 @@ protected Map getRpcMethods( protocolContext, filterManager, transactionPoolMock, + miningParameters, miningCoordinatorMock, new NoOpMetricsSystem(), supportedCapabilities, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java index 961970615fb..208c3d5779b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -110,6 +111,7 @@ public void initServerAndClient() throws Exception { mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), + mock(MiningParameters.class), mock(PoWMiningCoordinator.class), new NoOpMetricsSystem(), supportedCapabilities, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java index 481aedd8ad7..d86bcbd81c0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -139,6 +140,7 @@ public static void initServerAndClient() throws Exception { mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), + mock(MiningParameters.class), mock(PoWMiningCoordinator.class), new NoOpMetricsSystem(), supportedCapabilities, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java index 52b942b7238..fcbb2116c9a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.core.Synchronizer; @@ -212,6 +213,7 @@ private JsonRpcHttpService createJsonRpcHttpServiceWithRpcApis(final JsonRpcConf mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), + mock(MiningParameters.class), mock(PoWMiningCoordinator.class), new NoOpMetricsSystem(), supportedCapabilities, @@ -321,6 +323,7 @@ private JsonRpcHttpService createJsonRpcHttpService( mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), + mock(MiningParameters.class), mock(PoWMiningCoordinator.class), new NoOpMetricsSystem(), supportedCapabilities, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java index 94ec09b2367..8299cf70aa1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.ChainHead; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -118,6 +119,7 @@ public static void initServerAndClient() throws Exception { mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), + mock(MiningParameters.class), mock(PoWMiningCoordinator.class), new NoOpMetricsSystem(), supportedCapabilities, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java index 75612fa1fb8..2cefd7633e8 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.api.tls.SelfSignedP12Certificate; import org.hyperledger.besu.ethereum.api.tls.TlsConfiguration; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -123,6 +124,7 @@ public void initServer() throws Exception { mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), + mock(MiningParameters.class), mock(PoWMiningCoordinator.class), new NoOpMetricsSystem(), supportedCapabilities, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java index 6e1ade32850..c6e4a933ea0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.api.tls.SelfSignedP12Certificate; import org.hyperledger.besu.ethereum.api.tls.TlsConfiguration; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -112,6 +113,7 @@ public void beforeEach() { mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), + mock(MiningParameters.class), mock(PoWMiningCoordinator.class), new NoOpMetricsSystem(), supportedCapabilities, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java index 853412376c7..3fffd3561f0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.api.tls.SelfSignedP12Certificate; import org.hyperledger.besu.ethereum.api.tls.TlsConfiguration; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -113,6 +114,7 @@ public void initServer() throws Exception { mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), + mock(MiningParameters.class), mock(PoWMiningCoordinator.class), new NoOpMetricsSystem(), supportedCapabilities, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java index eef2b4422e8..27462501010 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java @@ -67,7 +67,7 @@ public void setUp() { null, Optional.empty(), Optional.empty(), - ImmutableApiConfiguration.builder().gasPriceMin(100).build()), + ImmutableApiConfiguration.builder().gasPriceMinSupplier(() -> 100).build()), miningCoordinator); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerGetMinPriorityFeeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerGetMinPriorityFeeTest.java new file mode 100644 index 00000000000..2f0bc33e313 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerGetMinPriorityFeeTest.java @@ -0,0 +1,54 @@ +/* + * 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.api.jsonrpc.internal.methods.miner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class MinerGetMinPriorityFeeTest { + MiningParameters miningParameters = mock(MiningParameters.class); + private MinerGetMinPriorityFee method; + + @BeforeEach + public void setUp() { + method = new MinerGetMinPriorityFee(miningParameters); + } + + @Test + public void shouldReturnMinPriorityFee() { + Wei minPriorityFee = Wei.of(70); + final JsonRpcRequestContext request = + new JsonRpcRequestContext(new JsonRpcRequest("2.0", method.getName(), new Object[] {})); + + when(miningParameters.getMinPriorityFeePerGas()).thenReturn(minPriorityFee); + + final JsonRpcResponse expected = + new JsonRpcSuccessResponse(request.getRequest().getId(), minPriorityFee.getValue()); + + final JsonRpcResponse actual = method.response(request); + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetMinPriorityFeeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetMinPriorityFeeTest.java new file mode 100644 index 00000000000..e90e171c15a --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerSetMinPriorityFeeTest.java @@ -0,0 +1,67 @@ +/* + * 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.api.jsonrpc.internal.methods.miner; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class MinerSetMinPriorityFeeTest { + MiningParameters miningParameters = MiningParameters.newDefault(); + private MinerSetMinPriorityFee method; + + @BeforeEach + public void setUp() { + method = new MinerSetMinPriorityFee(miningParameters); + } + + @Test + public void shouldReturnFalseWhenParameterIsInvalid() { + final long newMinPriorityFee = -1; + final var request = request(newMinPriorityFee); + + method.response(request); + final JsonRpcResponse expected = + new JsonRpcSuccessResponse(request.getRequest().getId(), false); + + final JsonRpcResponse actual = method.response(request); + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + } + + @Test + public void shouldChangeMinPriorityFee() { + final long newMinPriorityFee = 10; + final var request = request(newMinPriorityFee); + method.response(request); + final JsonRpcResponse expected = new JsonRpcSuccessResponse(request.getRequest().getId(), true); + + final JsonRpcResponse actual = method.response(request); + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + assertThat(miningParameters.getMinPriorityFeePerGas()).isEqualTo(Wei.of(newMinPriorityFee)); + } + + private JsonRpcRequestContext request(final long longParam) { + return new JsonRpcRequestContext( + new JsonRpcRequest("2.0", method.getName(), new Object[] {String.valueOf(longParam)})); + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java index 622dd3c1197..072c493d696 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java @@ -41,6 +41,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -174,6 +175,7 @@ public void before() throws URISyntaxException { mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), + mock(MiningParameters.class), mock(PoWMiningCoordinator.class), new NoOpMetricsSystem(), supportedCapabilities, 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 3fa80f1dd0a..a8bb17e93cd 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 @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.Deposit; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; @@ -61,7 +62,6 @@ import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; @@ -79,43 +79,33 @@ public interface ExtraDataCalculator { private static final Logger LOG = LoggerFactory.getLogger(AbstractBlockCreator.class); - protected final Address coinbase; private final MiningBeneficiaryCalculator miningBeneficiaryCalculator; - protected final Supplier> targetGasLimitSupplier; - private final ExtraDataCalculator extraDataCalculator; private final TransactionPool transactionPool; + protected final MiningParameters miningParameters; protected final ProtocolContext protocolContext; protected final ProtocolSchedule protocolSchedule; protected final BlockHeaderFunctions blockHeaderFunctions; - private final Wei minTransactionGasPrice; - private final Double minBlockOccupancyRatio; protected final BlockHeader parentHeader; private final Optional
depositContractAddress; private final AtomicBoolean isCancelled = new AtomicBoolean(false); protected AbstractBlockCreator( - final Address coinbase, + final MiningParameters miningParameters, final MiningBeneficiaryCalculator miningBeneficiaryCalculator, - final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader, final Optional
depositContractAddress) { - this.coinbase = coinbase; + this.miningParameters = miningParameters; this.miningBeneficiaryCalculator = miningBeneficiaryCalculator; - this.targetGasLimitSupplier = targetGasLimitSupplier; this.extraDataCalculator = extraDataCalculator; this.transactionPool = transactionPool; this.protocolContext = protocolContext; this.protocolSchedule = protocolSchedule; - this.minTransactionGasPrice = minTransactionGasPrice; - this.minBlockOccupancyRatio = minBlockOccupancyRatio; this.parentHeader = parentHeader; this.depositContractAddress = depositContractAddress; blockHeaderFunctions = ScheduleBasedBlockHeaderFunctions.create(protocolSchedule); @@ -341,14 +331,13 @@ private TransactionSelectionResults selectTransactions( final BlockTransactionSelector selector = new BlockTransactionSelector( + miningParameters, transactionProcessor, protocolContext.getBlockchain(), disposableWorldState, transactionPool, processableBlockHeader, transactionReceiptFactory, - minTransactionGasPrice, - minBlockOccupancyRatio, isCancelled::get, miningBeneficiary, blobGasPrice, @@ -395,7 +384,7 @@ private ProcessableBlockHeader createPendingBlockHeader( .getGasLimitCalculator() .nextGasLimit( parentHeader.getGasLimit(), - targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()), + miningParameters.getTargetGasLimit().orElse(parentHeader.getGasLimit()), newBlockNumber); final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); @@ -419,7 +408,7 @@ private ProcessableBlockHeader createPendingBlockHeader( final Bytes32 parentBeaconBlockRoot = maybeParentBeaconBlockRoot.orElse(null); return BlockHeaderBuilder.create() .parentHash(parentHeader.getHash()) - .coinbase(coinbase) + .coinbase(miningParameters.getCoinbase().orElseThrow()) .difficulty(Difficulty.of(difficulty)) .number(newBlockNumber) .gasLimit(gasLimit) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java index 3434c6f1b26..1432afb34a7 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java @@ -32,7 +32,6 @@ import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; import org.apache.tuweni.bytes.Bytes; import org.slf4j.Logger; @@ -47,12 +46,7 @@ public abstract class AbstractMinerExecutor targetGasLimit; - + protected final MiningParameters miningParameters; private final AtomicBoolean stopped = new AtomicBoolean(false); protected AbstractMinerExecutor( @@ -64,11 +58,8 @@ protected AbstractMinerExecutor( this.protocolContext = protocolContext; this.protocolSchedule = protocolSchedule; this.transactionPool = transactionPool; - this.extraData = miningParams.getExtraData(); - this.minTransactionGasPrice = miningParams.getMinTransactionGasPrice(); this.blockScheduler = blockScheduler; - this.minBlockOccupancyRatio = miningParams.getMinBlockOccupancyRatio(); - this.targetGasLimit = miningParams.getTargetGasLimit(); + this.miningParameters = miningParams; } public Optional startAsyncMining( @@ -103,24 +94,21 @@ public abstract M createMiner( final BlockHeader parentHeader); public void setExtraData(final Bytes extraData) { - this.extraData = extraData.copy(); + miningParameters.setExtraData(extraData.copy()); } public void setMinTransactionGasPrice(final Wei minTransactionGasPrice) { - this.minTransactionGasPrice = minTransactionGasPrice; + miningParameters.setMinTransactionGasPrice(minTransactionGasPrice); } public Wei getMinTransactionGasPrice() { - return minTransactionGasPrice; + return miningParameters.getMinTransactionGasPrice(); } public abstract Optional
getCoinbase(); public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { - this.targetGasLimit.ifPresentOrElse( - existing -> existing.set(newTargetGasLimit), - () -> this.targetGasLimit = Optional.of(new AtomicLong(newTargetGasLimit))); } else { throw new UnsupportedOperationException("Specified target gas limit is invalid"); } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java index 46eb9d5c5ff..66c57379ccb 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java @@ -14,11 +14,10 @@ */ package org.hyperledger.besu.ethereum.blockcreation; -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.EthHash; @@ -31,7 +30,6 @@ import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; -import java.util.function.Supplier; import org.apache.tuweni.units.bigints.UInt256; @@ -40,26 +38,20 @@ public class PoWBlockCreator extends AbstractBlockCreator { private final PoWSolver nonceSolver; public PoWBlockCreator( - final Address coinbase, - final Supplier> targetGasLimitSupplier, + final MiningParameters miningParameters, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final PoWSolver nonceSolver, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader) { super( - coinbase, - __ -> coinbase, - targetGasLimitSupplier, + miningParameters, + __ -> miningParameters.getCoinbase().orElseThrow(), extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, Optional.empty()); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java index 49f7e702c23..cd44318e960 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java @@ -28,17 +28,12 @@ import org.hyperledger.besu.util.Subscribers; import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; public class PoWMinerExecutor extends AbstractMinerExecutor { - protected volatile Optional
coinbase; protected boolean stratumMiningEnabled; - protected final Iterable nonceGenerator; protected final EpochCalculator epochCalculator; - protected final long powJobTimeToLive; - protected final int maxOmmerDepth; public PoWMinerExecutor( final ProtocolContext protocolContext, @@ -46,15 +41,12 @@ public PoWMinerExecutor( final TransactionPool transactionPool, final MiningParameters miningParams, final AbstractBlockScheduler blockScheduler, - final EpochCalculator epochCalculator, - final long powJobTimeToLive, - final int maxOmmerDepth) { + final EpochCalculator epochCalculator) { super(protocolContext, protocolSchedule, transactionPool, miningParams, blockScheduler); - this.coinbase = miningParams.getCoinbase(); - this.nonceGenerator = miningParams.getNonceGenerator().orElse(new RandomNonceGenerator()); + if (miningParams.getNonceGenerator().isEmpty()) { + miningParams.setNonceGenerator(new RandomNonceGenerator()); + } this.epochCalculator = epochCalculator; - this.powJobTimeToLive = powJobTimeToLive; - this.maxOmmerDepth = maxOmmerDepth; } @Override @@ -62,7 +54,7 @@ public Optional startAsyncMining( final Subscribers observers, final Subscribers ethHashObservers, final BlockHeader parentHeader) { - if (coinbase.isEmpty()) { + if (miningParameters.getCoinbase().isEmpty()) { throw new CoinbaseNotSetException("Unable to start mining without a coinbase."); } return super.startAsyncMining(observers, ethHashObservers, parentHeader); @@ -79,25 +71,20 @@ public PoWBlockMiner createMiner( protocolSchedule.getForNextBlockHeader(parentHeader, 0); final PoWSolver solver = new PoWSolver( - nonceGenerator, + miningParameters, nextBlockProtocolSpec.getPoWHasher().get(), stratumMiningEnabled, ethHashObservers, - epochCalculator, - powJobTimeToLive, - maxOmmerDepth); + epochCalculator); final Function blockCreator = (header) -> new PoWBlockCreator( - coinbase.orElse(Address.ZERO), - () -> targetGasLimit.map(AtomicLong::longValue), - parent -> extraData, + miningParameters, + parent -> miningParameters.getExtraData(), transactionPool, protocolContext, protocolSchedule, solver, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader); return new PoWBlockMiner( @@ -108,7 +95,7 @@ public void setCoinbase(final Address coinbase) { if (coinbase == null) { throw new IllegalArgumentException("Coinbase cannot be unset."); } else { - this.coinbase = Optional.of(Address.wrap(coinbase.copy())); + miningParameters.setCoinbase(Address.wrap(coinbase.copy())); } } @@ -118,7 +105,7 @@ void setStratumMiningEnabled(final boolean stratumMiningEnabled) { @Override public Optional
getCoinbase() { - return coinbase; + return miningParameters.getCoinbase(); } public EpochCalculator getEpochCalculator() { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockSelectionContext.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockSelectionContext.java index 0292f0bf67c..8204b3d9e43 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockSelectionContext.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockSelectionContext.java @@ -17,16 +17,16 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.gascalculator.GasCalculator; public record BlockSelectionContext( + MiningParameters miningParameters, GasCalculator gasCalculator, GasLimitCalculator gasLimitCalculator, - Wei minTransactionGasPrice, - Double minBlockOccupancyRatio, ProcessableBlockHeader processableBlockHeader, FeeMarket feeMarket, Wei blobGasPrice, diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java index 03c6ef28951..2c4382234dc 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.PriceTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.ProcessingResultTransactionSelector; import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; @@ -75,7 +76,6 @@ */ public class BlockTransactionSelector { private static final Logger LOG = LoggerFactory.getLogger(BlockTransactionSelector.class); - private final Supplier isCancelled; private final MainnetTransactionProcessor transactionProcessor; private final Blockchain blockchain; @@ -89,14 +89,13 @@ public class BlockTransactionSelector { private final OperationTracer pluginOperationTracer; public BlockTransactionSelector( + final MiningParameters miningParameters, final MainnetTransactionProcessor transactionProcessor, final Blockchain blockchain, final MutableWorldState worldState, final TransactionPool transactionPool, final ProcessableBlockHeader processableBlockHeader, final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final Supplier isCancelled, final Address miningBeneficiary, final Wei blobGasPrice, @@ -111,10 +110,9 @@ public BlockTransactionSelector( this.isCancelled = isCancelled; this.blockSelectionContext = new BlockSelectionContext( + miningParameters, gasCalculator, gasLimitCalculator, - minTransactionGasPrice, - minBlockOccupancyRatio, processableBlockHeader, feeMarket, blobGasPrice, diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java index 5d60ef8fc62..96f357546f3 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java @@ -118,13 +118,13 @@ private boolean blockOccupancyAboveThreshold( LOG.trace( "Min block occupancy ratio {}, gas used {}, available {}, remaining {}, used/available {}", - context.minBlockOccupancyRatio(), + context.miningParameters().getMinBlockOccupancyRatio(), gasUsed, gasAvailable, gasRemaining, occupancyRatio); - return occupancyRatio >= context.minBlockOccupancyRatio(); + return occupancyRatio >= context.miningParameters().getMinBlockOccupancyRatio(); } /** diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java index 9828650b41b..dee4316245c 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java @@ -86,11 +86,15 @@ private boolean transactionCurrentPriceBelowMin(final PendingTransaction pending .feeMarket() .getTransactionPriceCalculator() .price(transaction, context.processableBlockHeader().getBaseFee()); - if (context.minTransactionGasPrice().compareTo(currentMinTransactionGasPriceInBlock) > 0) { + if (context + .miningParameters() + .getMinTransactionGasPrice() + .compareTo(currentMinTransactionGasPriceInBlock) + > 0) { LOG.trace( "Current gas fee of {} is lower than configured minimum {}, skipping", pendingTransaction, - context.minTransactionGasPrice()); + context.miningParameters().getMinTransactionGasPrice()); return true; } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java index b5ad06d8248..413f9bb9ce6 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java @@ -49,6 +49,8 @@ import org.hyperledger.besu.ethereum.core.Deposit; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; @@ -81,7 +83,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Supplier; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; @@ -385,16 +386,24 @@ private AbstractBlockCreator createBlockCreator( null); transactionPool.setEnabled(); + final MiningParameters miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(Bytes.fromHexString("deadbeef")) + .minTransactionGasPrice(Wei.ONE) + .minBlockOccupancyRatio(0d) + .coinbase(Address.ZERO) + .build()) + .build(); + return new TestBlockCreator( - Address.ZERO, + miningParameters, __ -> Address.ZERO, - () -> Optional.of(30_000_000L), __ -> Bytes.fromHexString("deadbeef"), transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), - Wei.of(1L), - 0d, blockchain.getChainHeadHeader(), depositContractAddress); } @@ -402,27 +411,21 @@ private AbstractBlockCreator createBlockCreator( static class TestBlockCreator extends AbstractBlockCreator { protected TestBlockCreator( - final Address coinbase, + final MiningParameters miningParameters, final MiningBeneficiaryCalculator miningBeneficiaryCalculator, - final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader, final Optional
depositContractAddress) { super( - coinbase, + miningParameters, miningBeneficiaryCalculator, - targetGasLimitSupplier, extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, depositContractAddress); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index 863d164df43..1ddcd264ea0 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -46,6 +46,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; @@ -111,12 +113,12 @@ public abstract class AbstractBlockTransactionSelectorTest { protected TransactionPool transactionPool; protected MutableWorldState worldState; protected ProtocolSchedule protocolSchedule; + protected MiningParameters miningParameters; @Mock(answer = Answers.RETURNS_DEEP_STUBS) protected ProtocolContext protocolContext; @Mock protected MainnetTransactionProcessor transactionProcessor; - @Mock protected MiningParameters miningParameters; @Mock(answer = Answers.RETURNS_DEEP_STUBS) protected EthContext ethContext; @@ -148,7 +150,10 @@ public void setup() { when(protocolContext.getWorldStateArchive().getMutable(any(), anyBoolean())) .thenReturn(Optional.of(worldState)); when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); - when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ONE); + miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().minTransactionGasPrice(Wei.ONE).build()) + .build(); transactionPool = createTransactionPool(); } @@ -584,10 +589,8 @@ public TransactionSelectionResult evaluateTransactionPostProcessing( createBlockSelectorWithTxSelPlugin( transactionProcessor, blockHeader, - Wei.ZERO, miningBeneficiary, Wei.ZERO, - MIN_OCCUPANCY_80_PERCENT, transactionSelectorFactory); transactionPool.addRemoteTransactions( @@ -648,10 +651,8 @@ public TransactionSelectionResult evaluateTransactionPostProcessing( createBlockSelectorWithTxSelPlugin( transactionProcessor, blockHeader, - Wei.ZERO, miningBeneficiary, Wei.ZERO, - MIN_OCCUPANCY_80_PERCENT, transactionSelectorFactory); transactionPool.addRemoteTransactions(List.of(selected, notSelected, selected3)); @@ -682,10 +683,8 @@ public void transactionSelectionPluginShouldBeNotifiedWhenTransactionSelectionCo createBlockSelectorWithTxSelPlugin( transactionProcessor, createBlock(300_000), - Wei.ZERO, AddressHelpers.ofValue(1), Wei.ZERO, - MIN_OCCUPANCY_80_PERCENT, transactionSelectorFactory) .buildTransactionListForBlock(); @@ -747,14 +746,15 @@ protected BlockTransactionSelector createBlockSelector( final double minBlockOccupancyRatio) { final BlockTransactionSelector selector = new BlockTransactionSelector( + miningParameters + .setMinTransactionGasPrice(minGasPrice) + .setMinBlockOccupancyRatio(minBlockOccupancyRatio), transactionProcessor, blockchain, worldState, transactionPool, blockHeader, this::createReceipt, - minGasPrice, - minBlockOccupancyRatio, this::isCancelled, miningBeneficiary, blobGasPrice, @@ -769,21 +769,18 @@ protected BlockTransactionSelector createBlockSelector( protected BlockTransactionSelector createBlockSelectorWithTxSelPlugin( final MainnetTransactionProcessor transactionProcessor, final ProcessableBlockHeader blockHeader, - final Wei minGasPrice, final Address miningBeneficiary, final Wei blobGasPrice, - final double minBlockOccupancyRatio, final PluginTransactionSelectorFactory transactionSelectorFactory) { final BlockTransactionSelector selector = new BlockTransactionSelector( + miningParameters, transactionProcessor, blockchain, worldState, transactionPool, blockHeader, this::createReceipt, - minGasPrice, - minBlockOccupancyRatio, this::isCancelled, miningBeneficiary, blobGasPrice, diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java index 818210f88a4..80c0a3d4426 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java @@ -31,6 +31,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.PrivacyParameters; @@ -58,7 +60,6 @@ import java.io.IOException; import java.math.BigInteger; import java.util.Collections; -import java.util.Optional; import java.util.function.Function; import com.google.common.collect.Lists; @@ -94,29 +95,26 @@ void createMainnetBlock1() throws IOException { .createProtocolSchedule()) .build(); + final MiningParameters miningParameters = createMiningParameters(); + final PoWSolver solver = new PoWSolver( - Lists.newArrayList(BLOCK_1_NONCE), + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( - BLOCK_1_COINBASE, - Optional::empty, + miningParameters, parent -> BLOCK_1_EXTRA_DATA, transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, - Wei.ZERO, - 0.8, executionContextTestFixture.getBlockchain().getChainHeadHeader()); // A Hashrate should not exist in the block creator prior to creating a block @@ -150,29 +148,26 @@ void createMainnetBlock1_fixedDifficulty1() { .createProtocolSchedule()) .build(); + final MiningParameters miningParameters = createMiningParameters(); + final PoWSolver solver = new PoWSolver( - Lists.newArrayList(BLOCK_1_NONCE), + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( - BLOCK_1_COINBASE, - Optional::empty, + miningParameters, parent -> BLOCK_1_EXTRA_DATA, transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, - Wei.ZERO, - 0.8, executionContextTestFixture.getBlockchain().getChainHeadHeader()); assertThat(blockCreator.createBlock(BLOCK_1_TIMESTAMP)).isNotNull(); @@ -197,29 +192,26 @@ void rewardBeneficiary_zeroReward_skipZeroRewardsFalse() { final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder().protocolSchedule(protocolSchedule).build(); + final MiningParameters miningParameters = createMiningParameters(); + final PoWSolver solver = new PoWSolver( - Lists.newArrayList(BLOCK_1_NONCE), + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( - BLOCK_1_COINBASE, - () -> Optional.of(10_000_000L), + miningParameters, parent -> BLOCK_1_EXTRA_DATA, transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, - Wei.ZERO, - 0.8, executionContextTestFixture.getBlockchain().getChainHeadHeader()); final MutableWorldState mutableWorldState = @@ -266,29 +258,26 @@ void rewardBeneficiary_zeroReward_skipZeroRewardsTrue() { final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder().protocolSchedule(protocolSchedule).build(); + final MiningParameters miningParameters = createMiningParameters(); + final PoWSolver solver = new PoWSolver( - Lists.newArrayList(BLOCK_1_NONCE), + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( - BLOCK_1_COINBASE, - () -> Optional.of(10_000_000L), + miningParameters, parent -> BLOCK_1_EXTRA_DATA, transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, - Wei.ZERO, - 0.8, executionContextTestFixture.getBlockchain().getChainHeadHeader()); final MutableWorldState mutableWorldState = @@ -347,4 +336,16 @@ private TransactionPool createTransactionPool( return transactionPool; } + + private MiningParameters createMiningParameters() { + return ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .nonceGenerator(Lists.newArrayList(BLOCK_1_NONCE)) + .extraData(BLOCK_1_EXTRA_DATA) + .minTransactionGasPrice(Wei.ONE) + .coinbase(BLOCK_1_COINBASE) + .build()) + .build(); + } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java index b3ab4ff0688..b074e2146a8 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; @@ -48,8 +47,7 @@ public class PoWMinerExecutorTest { @Test public void startingMiningWithoutCoinbaseThrowsException() { - final MiningParameters miningParameters = - new MiningParameters.Builder().coinbase(null).minTransactionGasPrice(Wei.of(1000)).build(); + final MiningParameters miningParameters = MiningParameters.newDefault(); final TransactionPool transactionPool = createTransactionPool(miningParameters); @@ -60,9 +58,7 @@ public void startingMiningWithoutCoinbaseThrowsException() { transactionPool, miningParameters, new DefaultBlockScheduler(1, 10, TestClock.fixed()), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); assertThatExceptionOfType(CoinbaseNotSetException.class) .isThrownBy(() -> executor.startAsyncMining(Subscribers.create(), Subscribers.none(), null)) @@ -71,7 +67,7 @@ public void startingMiningWithoutCoinbaseThrowsException() { @Test public void settingCoinbaseToNullThrowsException() { - final MiningParameters miningParameters = new MiningParameters.Builder().build(); + final MiningParameters miningParameters = MiningParameters.newDefault(); final TransactionPool transactionPool = createTransactionPool(miningParameters); @@ -82,9 +78,7 @@ public void settingCoinbaseToNullThrowsException() { transactionPool, miningParameters, new DefaultBlockScheduler(1, 10, TestClock.fixed()), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> executor.setCoinbase(null)) diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java index b60b1f2cd43..6efd63fbaed 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java @@ -15,8 +15,8 @@ package org.hyperledger.besu.ethereum.blockcreation; import static org.assertj.core.api.Assertions.assertThat; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_LIMIT; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_TTL; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_REMOTE_SEALERS_LIMIT; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_REMOTE_SEALERS_TTL; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; 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 299b826369c..bcb7f9f65fe 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 @@ -62,6 +62,7 @@ public class BonsaiWorldStateProvider implements WorldStateArchive { private final Blockchain blockchain; + private final CachedWorldStorageManager cachedWorldStorageManager; private final TrieLogManager trieLogManager; private final BonsaiWorldState persistedState; private final BonsaiWorldStateKeyValueStorage worldStateStorage; @@ -91,15 +92,12 @@ public BonsaiWorldStateProvider( final ObservableMetricsSystem metricsSystem, final BesuContext pluginContext) { + this.cachedWorldStorageManager = + new CachedWorldStorageManager(this, worldStateStorage, metricsSystem); // TODO: de-dup constructors this.trieLogManager = - new CachedWorldStorageManager( - this, - blockchain, - worldStateStorage, - metricsSystem, - maxLayersToLoad.orElse(RETAINED_LAYERS), - pluginContext); + new TrieLogManager( + blockchain, worldStateStorage, maxLayersToLoad.orElse(RETAINED_LAYERS), pluginContext); this.blockchain = blockchain; this.worldStateStorage = worldStateStorage; this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; @@ -108,16 +106,18 @@ public BonsaiWorldStateProvider( .getBlockHeader(persistedState.getWorldStateBlockHash()) .ifPresent( blockHeader -> - this.trieLogManager.addCachedLayer( + this.cachedWorldStorageManager.addCachedLayer( blockHeader, persistedState.getWorldStateRootHash(), persistedState)); } @VisibleForTesting BonsaiWorldStateProvider( + final CachedWorldStorageManager cachedWorldStorageManager, final TrieLogManager trieLogManager, final BonsaiWorldStateKeyValueStorage worldStateStorage, final Blockchain blockchain, final CachedMerkleTrieLoader cachedMerkleTrieLoader) { + this.cachedWorldStorageManager = cachedWorldStorageManager; this.trieLogManager = trieLogManager; this.blockchain = blockchain; this.worldStateStorage = worldStateStorage; @@ -127,13 +127,13 @@ public BonsaiWorldStateProvider( .getBlockHeader(persistedState.getWorldStateBlockHash()) .ifPresent( blockHeader -> - this.trieLogManager.addCachedLayer( + this.cachedWorldStorageManager.addCachedLayer( blockHeader, persistedState.getWorldStateRootHash(), persistedState)); } @Override public Optional get(final Hash rootHash, final Hash blockHash) { - return trieLogManager + return cachedWorldStorageManager .getWorldState(blockHash) .or( () -> { @@ -148,7 +148,7 @@ public Optional get(final Hash rootHash, final Hash blockHash) { @Override public boolean isWorldStateAvailable(final Hash rootHash, final Hash blockHash) { - return trieLogManager.containWorldStateStorage(blockHash) + return cachedWorldStorageManager.containWorldStateStorage(blockHash) || persistedState.blockHash().equals(blockHash) || worldStateStorage.isWorldStateAvailable(rootHash, blockHash); } @@ -167,10 +167,10 @@ public Optional getMutable( trieLogManager.getMaxLayersToLoad()); return Optional.empty(); } - return trieLogManager + return cachedWorldStorageManager .getWorldState(blockHeader.getHash()) - .or(() -> trieLogManager.getNearestWorldState(blockHeader)) - .or(() -> trieLogManager.getHeadWorldState(blockchain::getBlockHeader)) + .or(() -> cachedWorldStorageManager.getNearestWorldState(blockHeader)) + .or(() -> cachedWorldStorageManager.getHeadWorldState(blockchain::getBlockHeader)) .flatMap( bonsaiWorldState -> rollMutableStateToBlockHash(bonsaiWorldState, blockHeader.getHash())) @@ -354,11 +354,15 @@ public TrieLogManager getTrieLogManager() { return trieLogManager; } + public CachedWorldStorageManager getCachedWorldStorageManager() { + return cachedWorldStorageManager; + } + @Override public void resetArchiveStateTo(final BlockHeader blockHeader) { persistedState.resetWorldStateTo(blockHeader); - this.trieLogManager.reset(); - this.trieLogManager.addCachedLayer( + this.cachedWorldStorageManager.reset(); + this.cachedWorldStorageManager.addCachedLayer( blockHeader, persistedState.getWorldStateRootHash(), persistedState); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedWorldStorageManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedWorldStorageManager.java index d0f1be97d89..f2434bbf912 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedWorldStorageManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/cache/CachedWorldStorageManager.java @@ -20,17 +20,9 @@ import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateLayerStorage; -import org.hyperledger.besu.ethereum.bonsai.trielog.AbstractTrieLogManager; -import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogFactoryImpl; import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldState; -import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.metrics.ObservableMetricsSystem; -import org.hyperledger.besu.plugin.BesuContext; -import org.hyperledger.besu.plugin.services.TrieLogService; -import org.hyperledger.besu.plugin.services.trielogs.TrieLog; -import org.hyperledger.besu.plugin.services.trielogs.TrieLogFactory; -import org.hyperledger.besu.plugin.services.trielogs.TrieLogProvider; import java.util.ArrayList; import java.util.Comparator; @@ -39,52 +31,39 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import java.util.stream.LongStream; -import java.util.stream.Stream; -import com.google.common.annotations.VisibleForTesting; import org.apache.tuweni.bytes.Bytes32; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class CachedWorldStorageManager extends AbstractTrieLogManager - implements BonsaiStorageSubscriber { +public class CachedWorldStorageManager implements BonsaiStorageSubscriber { + public static final long RETAINED_LAYERS = 512; // at least 256 + typical rollbacks private static final Logger LOG = LoggerFactory.getLogger(CachedWorldStorageManager.class); private final BonsaiWorldStateProvider archive; private final ObservableMetricsSystem metricsSystem; - CachedWorldStorageManager( + private final BonsaiWorldStateKeyValueStorage rootWorldStateStorage; + private final Map cachedWorldStatesByHash; + + private CachedWorldStorageManager( final BonsaiWorldStateProvider archive, - final Blockchain blockchain, final BonsaiWorldStateKeyValueStorage worldStateStorage, - final long maxLayersToLoad, final Map cachedWorldStatesByHash, - final BesuContext pluginContext, final ObservableMetricsSystem metricsSystem) { - super(blockchain, worldStateStorage, maxLayersToLoad, cachedWorldStatesByHash, pluginContext); worldStateStorage.subscribe(this); + this.rootWorldStateStorage = worldStateStorage; + this.cachedWorldStatesByHash = cachedWorldStatesByHash; this.archive = archive; this.metricsSystem = metricsSystem; } public CachedWorldStorageManager( final BonsaiWorldStateProvider archive, - final Blockchain blockchain, final BonsaiWorldStateKeyValueStorage worldStateStorage, - final ObservableMetricsSystem metricsSystem, - final long maxLayersToLoad, - final BesuContext pluginContext) { - this( - archive, - blockchain, - worldStateStorage, - maxLayersToLoad, - new ConcurrentHashMap<>(), - pluginContext, - metricsSystem); + final ObservableMetricsSystem metricsSystem) { + this(archive, worldStateStorage, new ConcurrentHashMap<>(), metricsSystem); } - @Override public synchronized void addCachedLayer( final BlockHeader blockHeader, final Hash worldStateRootHash, @@ -132,7 +111,20 @@ public synchronized void addCachedLayer( scrubCachedLayers(blockHeader.getNumber()); } - @Override + private synchronized void scrubCachedLayers(final long newMaxHeight) { + if (cachedWorldStatesByHash.size() > RETAINED_LAYERS) { + final long waterline = newMaxHeight - RETAINED_LAYERS; + cachedWorldStatesByHash.values().stream() + .filter(layer -> layer.getBlockNumber() < waterline) + .toList() + .forEach( + layer -> { + cachedWorldStatesByHash.remove(layer.getBlockHash()); + layer.close(); + }); + } + } + public Optional getWorldState(final Hash blockHash) { if (cachedWorldStatesByHash.containsKey(blockHash)) { // return a new worldstate using worldstate storage and an isolated copy of the updater @@ -150,7 +142,6 @@ public Optional getWorldState(final Hash blockHash) { return Optional.empty(); } - @Override public Optional getNearestWorldState(final BlockHeader blockHeader) { LOG.atDebug() .setMessage("getting nearest worldstate for {}") @@ -183,7 +174,6 @@ public Optional getNearestWorldState(final BlockHeader blockHe archive, new BonsaiWorldStateLayerStorage(storage))); } - @Override public Optional getHeadWorldState( final Function> hashBlockHeaderFunction) { @@ -203,7 +193,10 @@ public Optional getHeadWorldState( }); } - @Override + public boolean containWorldStateStorage(final Hash blockHash) { + return cachedWorldStatesByHash.containsKey(blockHash); + } + public void reset() { this.cachedWorldStatesByHash.clear(); } @@ -227,76 +220,4 @@ public void onClearTrieLog() { public void onCloseStorage() { this.cachedWorldStatesByHash.clear(); } - - @VisibleForTesting - @Override - protected TrieLogFactory setupTrieLogFactory(final BesuContext pluginContext) { - // if we have a TrieLogService from pluginContext, use it. - var trieLogServicez = - Optional.ofNullable(pluginContext) - .flatMap(context -> context.getService(TrieLogService.class)); - - if (trieLogServicez.isPresent()) { - var trieLogService = trieLogServicez.get(); - // push the TrieLogProvider into the TrieLogService - trieLogService.configureTrieLogProvider(getTrieLogProvider()); - - // configure plugin observers: - trieLogService.getObservers().forEach(trieLogObservers::subscribe); - - // return the TrieLogFactory implementation from the TrieLogService - return trieLogService.getTrieLogFactory(); - } else { - // Otherwise default to TrieLogFactoryImpl - return new TrieLogFactoryImpl(); - } - } - - @VisibleForTesting - TrieLogProvider getTrieLogProvider() { - return new TrieLogProvider() { - @Override - public Optional getTrieLogLayer(final Hash blockHash) { - return CachedWorldStorageManager.this.getTrieLogLayer(blockHash); - } - - @Override - public Optional getTrieLogLayer(final long blockNumber) { - return CachedWorldStorageManager.this - .blockchain - .getBlockHeader(blockNumber) - .map(BlockHeader::getHash) - .flatMap(CachedWorldStorageManager.this::getTrieLogLayer); - } - - @Override - public List getTrieLogsByRange( - final long fromBlockNumber, final long toBlockNumber) { - return rangeAsStream(fromBlockNumber, toBlockNumber) - .map(blockchain::getBlockHeader) - .map( - headerOpt -> - headerOpt.flatMap( - header -> - CachedWorldStorageManager.this - .getTrieLogLayer(header.getBlockHash()) - .map( - layer -> - new TrieLogRangeTuple( - header.getBlockHash(), header.getNumber(), layer)))) - .filter(Optional::isPresent) - .map(Optional::get) - .toList(); - } - - Stream rangeAsStream(final long fromBlockNumber, final long toBlockNumber) { - if (Math.abs(toBlockNumber - fromBlockNumber) > LOG_RANGE_LIMIT) { - throw new IllegalArgumentException("Requested Range too large"); - } - long left = Math.min(fromBlockNumber, toBlockNumber); - long right = Math.max(fromBlockNumber, toBlockNumber); - return LongStream.range(left, right).boxed(); - } - }; - } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/trielog/AbstractTrieLogManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/trielog/AbstractTrieLogManager.java deleted file mode 100644 index 90aff386e83..00000000000 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/trielog/AbstractTrieLogManager.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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.trielog; - -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.bonsai.cache.CachedBonsaiWorldView; -import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.BonsaiUpdater; -import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldState; -import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; -import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.plugin.BesuContext; -import org.hyperledger.besu.plugin.services.trielogs.TrieLog; -import org.hyperledger.besu.plugin.services.trielogs.TrieLogEvent.TrieLogObserver; -import org.hyperledger.besu.plugin.services.trielogs.TrieLogFactory; -import org.hyperledger.besu.util.Subscribers; - -import java.util.Map; -import java.util.Optional; - -import com.google.common.annotations.VisibleForTesting; -import org.apache.tuweni.bytes.Bytes32; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class AbstractTrieLogManager implements TrieLogManager { - private static final Logger LOG = LoggerFactory.getLogger(AbstractTrieLogManager.class); - public static final long RETAINED_LAYERS = 512; // at least 256 + typical rollbacks - public static final long LOG_RANGE_LIMIT = 1000; // restrict trielog range queries to 1k logs - protected final Blockchain blockchain; - protected final BonsaiWorldStateKeyValueStorage rootWorldStateStorage; - - protected final Map cachedWorldStatesByHash; - protected final long maxLayersToLoad; - protected final Subscribers trieLogObservers = Subscribers.create(); - - protected final TrieLogFactory trieLogFactory; - - protected AbstractTrieLogManager( - final Blockchain blockchain, - final BonsaiWorldStateKeyValueStorage worldStateStorage, - final long maxLayersToLoad, - final Map cachedWorldStatesByHash, - final BesuContext pluginContext) { - this.blockchain = blockchain; - this.rootWorldStateStorage = worldStateStorage; - this.cachedWorldStatesByHash = cachedWorldStatesByHash; - this.maxLayersToLoad = maxLayersToLoad; - this.trieLogFactory = setupTrieLogFactory(pluginContext); - } - - protected abstract TrieLogFactory setupTrieLogFactory(final BesuContext pluginContext); - - @Override - public synchronized void saveTrieLog( - final BonsaiWorldStateUpdateAccumulator localUpdater, - final Hash forWorldStateRootHash, - final BlockHeader forBlockHeader, - final BonsaiWorldState forWorldState) { - // do not overwrite a trielog layer that already exists in the database. - // if it's only in memory we need to save it - // for example, in case of reorg we don't replace a trielog layer - if (rootWorldStateStorage.getTrieLog(forBlockHeader.getHash()).isEmpty()) { - final BonsaiUpdater stateUpdater = forWorldState.getWorldStateStorage().updater(); - boolean success = false; - try { - final TrieLog trieLog = prepareTrieLog(forBlockHeader, localUpdater); - persistTrieLog(forBlockHeader, forWorldStateRootHash, trieLog, stateUpdater); - - // notify trie log added observers, synchronously - trieLogObservers.forEach(o -> o.onTrieLogAdded(new TrieLogAddedEvent(trieLog))); - - success = true; - } finally { - if (success) { - stateUpdater.commit(); - } else { - stateUpdater.rollback(); - } - } - } - } - - @VisibleForTesting - TrieLog prepareTrieLog( - final BlockHeader blockHeader, final BonsaiWorldStateUpdateAccumulator localUpdater) { - LOG.atDebug() - .setMessage("Adding layered world state for {}") - .addArgument(blockHeader::toLogString) - .log(); - final TrieLog trieLog = trieLogFactory.create(localUpdater, blockHeader); - trieLog.freeze(); - return trieLog; - } - - public synchronized void scrubCachedLayers(final long newMaxHeight) { - if (cachedWorldStatesByHash.size() > RETAINED_LAYERS) { - final long waterline = newMaxHeight - RETAINED_LAYERS; - cachedWorldStatesByHash.values().stream() - .filter(layer -> layer.getBlockNumber() < waterline) - .toList() - .forEach( - layer -> { - cachedWorldStatesByHash.remove(layer.getBlockHash()); - layer.close(); - }); - } - } - - private void persistTrieLog( - final BlockHeader blockHeader, - final Hash worldStateRootHash, - final TrieLog trieLog, - final BonsaiUpdater stateUpdater) { - LOG.atDebug() - .setMessage("Persisting trie log for block hash {} and world state root {}") - .addArgument(blockHeader::toLogString) - .addArgument(worldStateRootHash::toHexString) - .log(); - - stateUpdater - .getTrieLogStorageTransaction() - .put(blockHeader.getHash().toArrayUnsafe(), trieLogFactory.serialize(trieLog)); - } - - @Override - public boolean containWorldStateStorage(final Hash blockHash) { - return cachedWorldStatesByHash.containsKey(blockHash); - } - - @Override - public long getMaxLayersToLoad() { - return maxLayersToLoad; - } - - @Override - public Optional getTrieLogLayer(final Hash blockHash) { - return rootWorldStateStorage.getTrieLog(blockHash).map(trieLogFactory::deserialize); - } - - @Override - public synchronized long subscribe(final TrieLogObserver sub) { - return trieLogObservers.subscribe(sub); - } - - @Override - public synchronized void unsubscribe(final long id) { - trieLogObservers.unsubscribe(id); - } -} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManager.java index 5da83180a1c..cabd5a2d300 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManager.java @@ -16,42 +16,188 @@ package org.hyperledger.besu.ethereum.bonsai.trielog; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; +import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.plugin.BesuContext; +import org.hyperledger.besu.plugin.services.TrieLogService; 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.plugin.services.trielogs.TrieLogProvider; +import org.hyperledger.besu.util.Subscribers; +import java.util.List; import java.util.Optional; -import java.util.function.Function; +import java.util.stream.LongStream; +import java.util.stream.Stream; -public interface TrieLogManager { +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; - void saveTrieLog( +public class TrieLogManager { + private static final Logger LOG = LoggerFactory.getLogger(TrieLogManager.class); + public static final long LOG_RANGE_LIMIT = 1000; // restrict trielog range queries to 1k logs + protected final Blockchain blockchain; + protected final BonsaiWorldStateKeyValueStorage rootWorldStateStorage; + + protected final long maxLayersToLoad; + protected final Subscribers trieLogObservers = Subscribers.create(); + + protected final TrieLogFactory trieLogFactory; + + public TrieLogManager( + final Blockchain blockchain, + final BonsaiWorldStateKeyValueStorage worldStateStorage, + final long maxLayersToLoad, + final BesuContext pluginContext) { + this.blockchain = blockchain; + this.rootWorldStateStorage = worldStateStorage; + this.maxLayersToLoad = maxLayersToLoad; + this.trieLogFactory = setupTrieLogFactory(pluginContext); + } + + public synchronized void saveTrieLog( final BonsaiWorldStateUpdateAccumulator localUpdater, final Hash forWorldStateRootHash, final BlockHeader forBlockHeader, - final BonsaiWorldState forWorldState); + final BonsaiWorldState forWorldState) { + // do not overwrite a trielog layer that already exists in the database. + // if it's only in memory we need to save it + // for example, in case of reorg we don't replace a trielog layer + if (rootWorldStateStorage.getTrieLog(forBlockHeader.getHash()).isEmpty()) { + final BonsaiWorldStateKeyValueStorage.BonsaiUpdater stateUpdater = + forWorldState.getWorldStateStorage().updater(); + boolean success = false; + try { + final TrieLog trieLog = prepareTrieLog(forBlockHeader, localUpdater); + persistTrieLog(forBlockHeader, forWorldStateRootHash, trieLog, stateUpdater); + + // notify trie log added observers, synchronously + trieLogObservers.forEach(o -> o.onTrieLogAdded(new TrieLogAddedEvent(trieLog))); + + success = true; + } finally { + if (success) { + stateUpdater.commit(); + } else { + stateUpdater.rollback(); + } + } + } + } + + private TrieLog prepareTrieLog( + final BlockHeader blockHeader, final BonsaiWorldStateUpdateAccumulator localUpdater) { + LOG.atDebug() + .setMessage("Adding layered world state for {}") + .addArgument(blockHeader::toLogString) + .log(); + final TrieLog trieLog = trieLogFactory.create(localUpdater, blockHeader); + trieLog.freeze(); + return trieLog; + } + + private void persistTrieLog( + final BlockHeader blockHeader, + final Hash worldStateRootHash, + final TrieLog trieLog, + final BonsaiWorldStateKeyValueStorage.BonsaiUpdater stateUpdater) { + LOG.atDebug() + .setMessage("Persisting trie log for block hash {} and world state root {}") + .addArgument(blockHeader::toLogString) + .addArgument(worldStateRootHash::toHexString) + .log(); + + stateUpdater + .getTrieLogStorageTransaction() + .put(blockHeader.getHash().toArrayUnsafe(), trieLogFactory.serialize(trieLog)); + } + + public long getMaxLayersToLoad() { + return maxLayersToLoad; + } + + public Optional getTrieLogLayer(final Hash blockHash) { + return rootWorldStateStorage.getTrieLog(blockHash).map(trieLogFactory::deserialize); + } - void addCachedLayer( - BlockHeader blockHeader, Hash worldStateRootHash, BonsaiWorldState forWorldState); + public synchronized long subscribe(final TrieLogEvent.TrieLogObserver sub) { + return trieLogObservers.subscribe(sub); + } - boolean containWorldStateStorage(final Hash blockHash); + public synchronized void unsubscribe(final long id) { + trieLogObservers.unsubscribe(id); + } - Optional getWorldState(final Hash blockHash); + private TrieLogFactory setupTrieLogFactory(final BesuContext pluginContext) { + // if we have a TrieLogService from pluginContext, use it. + var trieLogServicez = + Optional.ofNullable(pluginContext) + .flatMap(context -> context.getService(TrieLogService.class)); - Optional getNearestWorldState(final BlockHeader blockHeader); + if (trieLogServicez.isPresent()) { + var trieLogService = trieLogServicez.get(); + // push the TrieLogProvider into the TrieLogService + trieLogService.configureTrieLogProvider(getTrieLogProvider()); - Optional getHeadWorldState( - final Function> hashBlockHeaderFunction); + // configure plugin observers: + trieLogService.getObservers().forEach(trieLogObservers::subscribe); - long getMaxLayersToLoad(); + // return the TrieLogFactory implementation from the TrieLogService + return trieLogService.getTrieLogFactory(); + } else { + // Otherwise default to TrieLogFactoryImpl + return new TrieLogFactoryImpl(); + } + } - void reset(); + private TrieLogProvider getTrieLogProvider() { + return new TrieLogProvider() { + @Override + public Optional getTrieLogLayer(final Hash blockHash) { + return TrieLogManager.this.getTrieLogLayer(blockHash); + } - Optional getTrieLogLayer(final Hash blockHash); + @Override + public Optional getTrieLogLayer(final long blockNumber) { + return TrieLogManager.this + .blockchain + .getBlockHeader(blockNumber) + .map(BlockHeader::getHash) + .flatMap(TrieLogManager.this::getTrieLogLayer); + } - long subscribe(final TrieLogEvent.TrieLogObserver sub); + @Override + public List getTrieLogsByRange( + final long fromBlockNumber, final long toBlockNumber) { + return rangeAsStream(fromBlockNumber, toBlockNumber) + .map(blockchain::getBlockHeader) + .map( + headerOpt -> + headerOpt.flatMap( + header -> + TrieLogManager.this + .getTrieLogLayer(header.getBlockHash()) + .map( + layer -> + new TrieLogRangeTuple( + header.getBlockHash(), header.getNumber(), layer)))) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + } - void unsubscribe(final long id); + Stream rangeAsStream(final long fromBlockNumber, final long toBlockNumber) { + if (Math.abs(toBlockNumber - fromBlockNumber) > LOG_RANGE_LIMIT) { + throw new IllegalArgumentException("Requested Range too large"); + } + long left = Math.min(fromBlockNumber, toBlockNumber); + long right = Math.max(fromBlockNumber, toBlockNumber); + return LongStream.range(left, right).boxed(); + } + }; + } } 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 ed81c90f439..d4c4c223a24 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 @@ -28,6 +28,7 @@ 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.cache.CachedWorldStorageManager; 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; @@ -69,6 +70,7 @@ public class BonsaiWorldState protected BonsaiWorldStateKeyValueStorage worldStateStorage; protected final CachedMerkleTrieLoader cachedMerkleTrieLoader; + protected final CachedWorldStorageManager cachedWorldStorageManager; protected final TrieLogManager trieLogManager; private BonsaiWorldStateUpdateAccumulator accumulator; @@ -79,12 +81,17 @@ public class BonsaiWorldState public BonsaiWorldState( final BonsaiWorldStateProvider archive, final BonsaiWorldStateKeyValueStorage worldStateStorage) { - this(worldStateStorage, archive.getCachedMerkleTrieLoader(), archive.getTrieLogManager()); + this( + worldStateStorage, + archive.getCachedMerkleTrieLoader(), + archive.getCachedWorldStorageManager(), + archive.getTrieLogManager()); } protected BonsaiWorldState( final BonsaiWorldStateKeyValueStorage worldStateStorage, final CachedMerkleTrieLoader cachedMerkleTrieLoader, + final CachedWorldStorageManager cachedWorldStorageManager, final TrieLogManager trieLogManager) { this.worldStateStorage = worldStateStorage; this.worldStateRootHash = @@ -101,6 +108,7 @@ protected BonsaiWorldState( (addr, value) -> cachedMerkleTrieLoader.preLoadStorageSlot(getWorldStateStorage(), addr, value)); this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; + this.cachedWorldStorageManager = cachedWorldStorageManager; this.trieLogManager = trieLogManager; } @@ -396,7 +404,7 @@ public void persist(final BlockHeader blockHeader) { trieLogManager.saveTrieLog(localCopy, newWorldStateRootHash, blockHeader, this); // not save a frozen state in the cache if (!isFrozen) { - trieLogManager.addCachedLayer(blockHeader, newWorldStateRootHash, this); + cachedWorldStorageManager.addCachedLayer(blockHeader, newWorldStateRootHash, this); } }; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java index e218bf1d25b..fc38b663ea9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java @@ -238,7 +238,6 @@ private void validateProcessableBlockHeader() { checkState(this.difficulty != null, "Missing block difficulty"); checkState(this.number > -1L, "Missing block number"); checkState(this.gasLimit > -1L, "Missing gas limit"); - checkState(this.timestamp > -1L, "Missing timestamp"); } private void validateSealableBlockHeader() { @@ -360,7 +359,6 @@ public BlockHeaderBuilder gasUsed(final long gasUsed) { } public BlockHeaderBuilder timestamp(final long timestamp) { - checkArgument(timestamp >= 0); this.timestamp = timestamp; return this; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java index e90efaba5b9..2f273f265ea 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java @@ -20,385 +20,283 @@ import java.time.Duration; import java.util.Objects; import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; +import java.util.OptionalLong; import org.apache.tuweni.bytes.Bytes; +import org.immutables.value.Value; + +@Value.Immutable +@Value.Enclosing +public abstract class MiningParameters { + public static final MiningParameters MINING_DISABLED = + ImmutableMiningParameters.builder() + .mutableInitValues( + ImmutableMiningParameters.MutableInitValues.builder().isMiningEnabled(false).build()) + .build(); + + public static final MiningParameters newDefault() { + return ImmutableMiningParameters.builder().build(); + } -public class MiningParameters { - - public static final int DEFAULT_REMOTE_SEALERS_LIMIT = 1000; - - public static final long DEFAULT_REMOTE_SEALERS_TTL = Duration.ofMinutes(10).toMinutes(); - - public static final long DEFAULT_POW_JOB_TTL = Duration.ofMinutes(5).toMillis(); - - public static final int DEFAULT_MAX_OMMERS_DEPTH = 8; - - public static final long DEFAULT_POS_BLOCK_CREATION_MAX_TIME = Duration.ofSeconds(12).toMillis(); - - public static final long DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION = - Duration.ofMillis(500).toMillis(); - - private final Optional
coinbase; - private final Optional targetGasLimit; - private final Wei minTransactionGasPrice; - private final Bytes extraData; - private final boolean miningEnabled; - private final boolean stratumMiningEnabled; - private final String stratumNetworkInterface; - private final int stratumPort; - private final String stratumExtranonce; - private final Optional> maybeNonceGenerator; - private final Double minBlockOccupancyRatio; - private final int remoteSealersLimit; - private final long remoteSealersTimeToLive; - private final long powJobTimeToLive; - private final int maxOmmerDepth; - private final long posBlockCreationMaxTime; - private final long posBlockCreationRepetitionMinDuration; - - private MiningParameters( - final Address coinbase, - final Long targetGasLimit, - final Wei minTransactionGasPrice, - final Bytes extraData, - final boolean miningEnabled, - final boolean stratumMiningEnabled, - final String stratumNetworkInterface, - final int stratumPort, - final String stratumExtranonce, - final Optional> maybeNonceGenerator, - final Double minBlockOccupancyRatio, - final int remoteSealersLimit, - final long remoteSealersTimeToLive, - final long powJobTimeToLive, - final int maxOmmerDepth, - final long posBlockCreationMaxTime, - final long posBlockCreationRepetitionMinDuration) { - this.coinbase = Optional.ofNullable(coinbase); - this.targetGasLimit = Optional.ofNullable(targetGasLimit).map(AtomicLong::new); - this.minTransactionGasPrice = minTransactionGasPrice; - this.extraData = extraData; - this.miningEnabled = miningEnabled; - this.stratumMiningEnabled = stratumMiningEnabled; - this.stratumNetworkInterface = stratumNetworkInterface; - this.stratumPort = stratumPort; - this.stratumExtranonce = stratumExtranonce; - this.maybeNonceGenerator = maybeNonceGenerator; - this.minBlockOccupancyRatio = minBlockOccupancyRatio; - this.remoteSealersLimit = remoteSealersLimit; - this.remoteSealersTimeToLive = remoteSealersTimeToLive; - this.powJobTimeToLive = powJobTimeToLive; - this.maxOmmerDepth = maxOmmerDepth; - this.posBlockCreationMaxTime = posBlockCreationMaxTime; - this.posBlockCreationRepetitionMinDuration = posBlockCreationRepetitionMinDuration; + public boolean isMiningEnabled() { + return getMutableRuntimeValues().miningEnabled; } - public Optional
getCoinbase() { - return coinbase; + public MiningParameters setMiningEnabled(final boolean miningEnabled) { + getMutableRuntimeValues().miningEnabled = miningEnabled; + return this; + } + + public Bytes getExtraData() { + return getMutableRuntimeValues().extraData; } - public Optional getTargetGasLimit() { - return targetGasLimit; + public MiningParameters setExtraData(final Bytes extraData) { + getMutableRuntimeValues().extraData = extraData; + return this; } public Wei getMinTransactionGasPrice() { - return minTransactionGasPrice; + return getMutableRuntimeValues().minTransactionGasPrice; } - public Bytes getExtraData() { - return extraData; + public MiningParameters setMinTransactionGasPrice(final Wei minTransactionGasPrice) { + getMutableRuntimeValues().minTransactionGasPrice = minTransactionGasPrice; + return this; } - public boolean isMiningEnabled() { - return miningEnabled; + public Wei getMinPriorityFeePerGas() { + return getMutableRuntimeValues().minPriorityFeePerGas; } - public boolean isStratumMiningEnabled() { - return stratumMiningEnabled; + public MiningParameters setMinPriorityFeePerGas(final Wei minPriorityFeePerGas) { + getMutableRuntimeValues().minPriorityFeePerGas = minPriorityFeePerGas; + return this; } - public String getStratumNetworkInterface() { - return stratumNetworkInterface; + public Optional
getCoinbase() { + return getMutableRuntimeValues().coinbase; } - public int getStratumPort() { - return stratumPort; + public MiningParameters setCoinbase(final Address coinbase) { + getMutableRuntimeValues().coinbase = Optional.of(coinbase); + return this; } - public String getStratumExtranonce() { - return stratumExtranonce; + public OptionalLong getTargetGasLimit() { + return getMutableRuntimeValues().targetGasLimit; } - public Optional> getNonceGenerator() { - return maybeNonceGenerator; + public MiningParameters setTargetGasLimit(final long targetGasLimit) { + getMutableRuntimeValues().targetGasLimit = OptionalLong.of(targetGasLimit); + return this; } - public Double getMinBlockOccupancyRatio() { - return minBlockOccupancyRatio; + public double getMinBlockOccupancyRatio() { + return getMutableRuntimeValues().minBlockOccupancyRatio; } - public int getRemoteSealersLimit() { - return remoteSealersLimit; + public MiningParameters setMinBlockOccupancyRatio(final double minBlockOccupancyRatio) { + getMutableRuntimeValues().minBlockOccupancyRatio = minBlockOccupancyRatio; + return this; } - public long getRemoteSealersTimeToLive() { - return remoteSealersTimeToLive; + public Optional> getNonceGenerator() { + return getMutableRuntimeValues().nonceGenerator; } - public long getPowJobTimeToLive() { - return powJobTimeToLive; + public MiningParameters setNonceGenerator(final Iterable nonceGenerator) { + getMutableRuntimeValues().nonceGenerator = Optional.of(nonceGenerator); + return this; } - public int getMaxOmmerDepth() { - return maxOmmerDepth; + @Value.Default + public boolean isStratumMiningEnabled() { + return false; } - public long getPosBlockCreationMaxTime() { - return posBlockCreationMaxTime; + @Value.Default + public String getStratumNetworkInterface() { + return "0.0.0.0"; } - public long getPosBlockCreationRepetitionMinDuration() { - return posBlockCreationRepetitionMinDuration; + @Value.Default + public int getStratumPort() { + return 8008; } - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MiningParameters that = (MiningParameters) o; - return stratumPort == that.stratumPort - && Objects.equals(coinbase, that.coinbase) - && Objects.equals(targetGasLimit, that.targetGasLimit) - && Objects.equals(minTransactionGasPrice, that.minTransactionGasPrice) - && Objects.equals(extraData, that.extraData) - && miningEnabled == that.miningEnabled - && stratumMiningEnabled == that.stratumMiningEnabled - && Objects.equals(stratumNetworkInterface, that.stratumNetworkInterface) - && Objects.equals(stratumExtranonce, that.stratumExtranonce) - && Objects.equals(minBlockOccupancyRatio, that.minBlockOccupancyRatio) - && remoteSealersTimeToLive == that.remoteSealersTimeToLive - && remoteSealersLimit == that.remoteSealersLimit - && powJobTimeToLive == that.powJobTimeToLive - && posBlockCreationMaxTime == that.posBlockCreationMaxTime - && posBlockCreationRepetitionMinDuration == that.posBlockCreationRepetitionMinDuration; + @Value.Default + protected MutableRuntimeValues getMutableRuntimeValues() { + return new MutableRuntimeValues(getMutableInitValues()); } - @Override - public int hashCode() { - return Objects.hash( - coinbase, - targetGasLimit, - minTransactionGasPrice, - extraData, - miningEnabled, - stratumMiningEnabled, - stratumNetworkInterface, - stratumPort, - stratumExtranonce, - minBlockOccupancyRatio, - remoteSealersLimit, - remoteSealersTimeToLive, - powJobTimeToLive, - posBlockCreationMaxTime, - posBlockCreationRepetitionMinDuration); + @Value.Default + public Unstable getUnstable() { + return Unstable.DEFAULT; } - @Override - public String toString() { - return "MiningParameters{" - + "coinbase=" - + coinbase - + ", targetGasLimit=" - + targetGasLimit.map(Object::toString).orElse("null") - + ", minTransactionGasPrice=" - + minTransactionGasPrice - + ", extraData=" - + extraData - + ", miningEnabled=" - + miningEnabled - + ", stratumMiningEnabled=" - + stratumMiningEnabled - + ", stratumNetworkInterface='" - + stratumNetworkInterface - + '\'' - + ", stratumPort=" - + stratumPort - + ", stratumExtranonce='" - + stratumExtranonce - + '\'' - + ", maybeNonceGenerator=" - + maybeNonceGenerator - + ", minBlockOccupancyRatio=" - + minBlockOccupancyRatio - + ", remoteSealersLimit=" - + remoteSealersLimit - + ", remoteSealersTimeToLive=" - + remoteSealersTimeToLive - + ", powJobTimeToLive=" - + powJobTimeToLive - + ", posBlockCreationMaxTime=" - + posBlockCreationMaxTime - + ", posBlockCreationRepetitionMinDuration=" - + posBlockCreationRepetitionMinDuration - + '}'; + @Value.Default + public MutableInitValues getMutableInitValues() { + return MutableInitValues.DEFAULT; } - public static class Builder { - - private Address coinbase = null; - private Long targetGasLimit = null; - private Wei minTransactionGasPrice = Wei.ZERO; - private Bytes extraData = Bytes.EMPTY; - private boolean miningEnabled = false; - private boolean stratumMiningEnabled = false; - private String stratumNetworkInterface = "0.0.0.0"; - private int stratumPort = 8008; - private String stratumExtranonce = "080c"; - private Iterable maybeNonceGenerator; - private Double minBlockOccupancyRatio = 0.8; - private int remoteSealersLimit = DEFAULT_REMOTE_SEALERS_LIMIT; - private long remoteSealersTimeToLive = DEFAULT_REMOTE_SEALERS_TTL; - private long powJobTimeToLive = DEFAULT_POW_JOB_TTL; - private int maxOmmerDepth = DEFAULT_MAX_OMMERS_DEPTH; - private long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME; - - private long posBlockCreationRepetitionMinDuration = - DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; - - public Builder() { - // zero arg - } + @Value.Immutable + public interface MutableInitValues { + Bytes DEFAULT_EXTRA_DATA = Bytes.EMPTY; + Wei DEFAULT_MIN_TRANSACTION_GAS_PRICE = Wei.of(1000); + Wei DEFAULT_MIN_PRIORITY_FEE_PER_GAS = Wei.ZERO; + double DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO = 0.8; - public Builder(final MiningParameters existing) { - existing.getCoinbase().ifPresent(cb -> this.coinbase = cb); - existing - .getTargetGasLimit() - .map(AtomicLong::longValue) - .ifPresent(gasLimit -> this.targetGasLimit = gasLimit); - this.minTransactionGasPrice = existing.getMinTransactionGasPrice(); - this.extraData = existing.getExtraData(); - this.miningEnabled = existing.isMiningEnabled(); - this.stratumMiningEnabled = existing.isStratumMiningEnabled(); - this.stratumNetworkInterface = existing.getStratumNetworkInterface(); - this.stratumPort = existing.getStratumPort(); - this.stratumExtranonce = existing.getStratumExtranonce(); - existing.getNonceGenerator().ifPresent(ng -> this.maybeNonceGenerator = ng); - this.minBlockOccupancyRatio = existing.getMinBlockOccupancyRatio(); - this.remoteSealersLimit = existing.getRemoteSealersLimit(); - this.remoteSealersTimeToLive = existing.getRemoteSealersTimeToLive(); - this.powJobTimeToLive = existing.getPowJobTimeToLive(); - this.maxOmmerDepth = existing.getMaxOmmerDepth(); - this.posBlockCreationMaxTime = existing.getPosBlockCreationMaxTime(); - this.posBlockCreationRepetitionMinDuration = - existing.getPosBlockCreationRepetitionMinDuration(); - } + MutableInitValues DEFAULT = ImmutableMiningParameters.MutableInitValues.builder().build(); - public Builder coinbase(final Address address) { - this.coinbase = address; - return this; + @Value.Default + default boolean isMiningEnabled() { + return false; } - public Builder targetGasLimit(final Long targetGasLimit) { - this.targetGasLimit = targetGasLimit; - return this; + @Value.Default + default Bytes getExtraData() { + return DEFAULT_EXTRA_DATA; } - public Builder minTransactionGasPrice(final Wei minTransactionGasPrice) { - this.minTransactionGasPrice = minTransactionGasPrice; - return this; + @Value.Default + default Wei getMinTransactionGasPrice() { + return DEFAULT_MIN_TRANSACTION_GAS_PRICE; } - public Builder extraData(final Bytes extraData) { - this.extraData = extraData; - return this; + @Value.Default + default Wei getMinPriorityFeePerGas() { + return DEFAULT_MIN_PRIORITY_FEE_PER_GAS; } - public Builder miningEnabled(final boolean miningEnabled) { - this.miningEnabled = miningEnabled; - return this; + @Value.Default + default double getMinBlockOccupancyRatio() { + return DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; } - public Builder stratumMiningEnabled(final boolean stratumMiningEnabled) { - this.stratumMiningEnabled = stratumMiningEnabled; - return this; - } + Optional
getCoinbase(); - public Builder stratumNetworkInterface(final String stratumNetworkInterface) { - this.stratumNetworkInterface = stratumNetworkInterface; - return this; - } + OptionalLong getTargetGasLimit(); - public Builder stratumPort(final int stratumPort) { - this.stratumPort = stratumPort; - return this; + Optional> nonceGenerator(); + } + + static class MutableRuntimeValues { + private volatile boolean miningEnabled; + private volatile Bytes extraData; + private volatile Wei minTransactionGasPrice; + private volatile Wei minPriorityFeePerGas; + private volatile double minBlockOccupancyRatio; + private volatile Optional
coinbase; + private volatile OptionalLong targetGasLimit; + private volatile Optional> nonceGenerator; + + private MutableRuntimeValues(final MutableInitValues initValues) { + miningEnabled = initValues.isMiningEnabled(); + extraData = initValues.getExtraData(); + minTransactionGasPrice = initValues.getMinTransactionGasPrice(); + minPriorityFeePerGas = initValues.getMinPriorityFeePerGas(); + minBlockOccupancyRatio = initValues.getMinBlockOccupancyRatio(); + coinbase = initValues.getCoinbase(); + targetGasLimit = initValues.getTargetGasLimit(); + nonceGenerator = initValues.nonceGenerator(); } - public Builder stratumExtranonce(final String stratumExtranonce) { - this.stratumExtranonce = stratumExtranonce; - return this; + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final MutableRuntimeValues that = (MutableRuntimeValues) o; + return miningEnabled == that.miningEnabled + && Double.compare(minBlockOccupancyRatio, that.minBlockOccupancyRatio) == 0 + && Objects.equals(extraData, that.extraData) + && Objects.equals(minTransactionGasPrice, that.minTransactionGasPrice) + && Objects.equals(coinbase, that.coinbase) + && Objects.equals(minPriorityFeePerGas, that.minPriorityFeePerGas) + && Objects.equals(targetGasLimit, that.targetGasLimit) + && Objects.equals(nonceGenerator, that.nonceGenerator); } - public Builder maybeNonceGenerator(final Iterable maybeNonceGenerator) { - this.maybeNonceGenerator = maybeNonceGenerator; - return this; + @Override + public int hashCode() { + return Objects.hash( + miningEnabled, + extraData, + minTransactionGasPrice, + minPriorityFeePerGas, + minBlockOccupancyRatio, + coinbase, + targetGasLimit, + nonceGenerator); } - public Builder minBlockOccupancyRatio(final Double minBlockOccupancyRatio) { - this.minBlockOccupancyRatio = minBlockOccupancyRatio; - return this; + @Override + public String toString() { + return "UpdatableRuntimeValues{" + + "miningEnabled=" + + miningEnabled + + ", extraData=" + + extraData + + ", minTransactionGasPrice=" + + minTransactionGasPrice + + ", minPriorityFeePerGas=" + + minPriorityFeePerGas + + ", minBlockOccupancyRatio=" + + minBlockOccupancyRatio + + ", coinbase=" + + coinbase + + ", targetGasLimit=" + + targetGasLimit + + ", nonceGenerator=" + + nonceGenerator + + '}'; } + } + + @Value.Immutable + public interface Unstable { + int DEFAULT_REMOTE_SEALERS_LIMIT = 1000; + long DEFAULT_REMOTE_SEALERS_TTL = Duration.ofMinutes(10).toMinutes(); + long DEFAULT_POW_JOB_TTL = Duration.ofMinutes(5).toMillis(); + int DEFAULT_MAX_OMMERS_DEPTH = 8; + long DEFAULT_POS_BLOCK_CREATION_MAX_TIME = Duration.ofSeconds(12).toMillis(); + long DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION = Duration.ofMillis(500).toMillis(); + + MiningParameters.Unstable DEFAULT = ImmutableMiningParameters.Unstable.builder().build(); - public Builder remoteSealersLimit(final int remoteSealersLimit) { - this.remoteSealersLimit = remoteSealersLimit; - return this; + @Value.Default + default int getRemoteSealersLimit() { + return DEFAULT_REMOTE_SEALERS_LIMIT; } - public Builder remoteSealersTimeToLive(final long remoteSealersTimeToLive) { - this.remoteSealersTimeToLive = remoteSealersTimeToLive; - return this; + @Value.Default + default long getRemoteSealersTimeToLive() { + return DEFAULT_REMOTE_SEALERS_TTL; } - public Builder powJobTimeToLive(final long powJobTimeToLive) { - this.powJobTimeToLive = powJobTimeToLive; - return this; + @Value.Default + default long getPowJobTimeToLive() { + return DEFAULT_POW_JOB_TTL; } - public Builder maxOmmerDepth(final int maxOmmerDepth) { - this.maxOmmerDepth = maxOmmerDepth; - return this; + @Value.Default + default int getMaxOmmerDepth() { + return DEFAULT_MAX_OMMERS_DEPTH; } - public Builder posBlockCreationMaxTime(final long posBlockCreationMaxTime) { - this.posBlockCreationMaxTime = posBlockCreationMaxTime; - return this; + @Value.Default + default long getPosBlockCreationMaxTime() { + return DEFAULT_POS_BLOCK_CREATION_MAX_TIME; } - public Builder posBlockCreationRepetitionMinDuration( - final long posBlockCreationRepetitionMinDuration) { - this.posBlockCreationRepetitionMinDuration = posBlockCreationRepetitionMinDuration; - return this; + @Value.Default + default long getPosBlockCreationRepetitionMinDuration() { + return DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; } - public MiningParameters build() { - return new MiningParameters( - coinbase, - targetGasLimit, - minTransactionGasPrice, - extraData, - miningEnabled, - stratumMiningEnabled, - stratumNetworkInterface, - stratumPort, - stratumExtranonce, - Optional.ofNullable(maybeNonceGenerator), - minBlockOccupancyRatio, - remoteSealersLimit, - remoteSealersTimeToLive, - powJobTimeToLive, - maxOmmerDepth, - posBlockCreationMaxTime, - posBlockCreationRepetitionMinDuration); + @Value.Default + default String getStratumExtranonce() { + return "080c"; } } } 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 02f757483df..e477bf6f75e 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 @@ -640,8 +640,6 @@ static ProtocolSpecBuilder cancunDefinition( final EvmConfiguration evmConfiguration) { final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); - final int contractSizeLimit = - configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); final BaseFeeMarket cancunFeeMarket = genesisConfigOptions.isZeroBaseFee() @@ -668,17 +666,6 @@ static ProtocolSpecBuilder cancunDefinition( (gasCalculator, jdCacheConfig) -> MainnetEVMs.cancun( gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration)) - // change contract call creator to accept EOF code - .contractCreationProcessorBuilder( - (gasCalculator, evm) -> - new ContractCreationProcessor( - gasCalculator, - evm, - true, - List.of( - MaxCodeSizeRule.of(contractSizeLimit), EOFValidationCodeRule.of(1, false)), - 1, - SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) // use Cancun fee market .transactionProcessorBuilder( (gasCalculator, @@ -723,7 +710,8 @@ static ProtocolSpecBuilder futureEipsDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration) { - + final int contractSizeLimit = + configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); return cancunDefinition( chainId, configContractSizeLimit, @@ -731,10 +719,23 @@ static ProtocolSpecBuilder futureEipsDefinition( enableRevertReason, genesisConfigOptions, evmConfiguration) + // Use Future EIP configured EVM .evmBuilder( (gasCalculator, jdCacheConfig) -> MainnetEVMs.futureEips( gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration)) + // change contract call creator to accept EOF code + .contractCreationProcessorBuilder( + (gasCalculator, evm) -> + new ContractCreationProcessor( + gasCalculator, + evm, + true, + List.of( + MaxCodeSizeRule.of(contractSizeLimit), EOFValidationCodeRule.of(1, false)), + 1, + SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) + // use future configured precompiled contracts .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::futureEips) .name("FutureEips"); } 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 cdeec19b117..35909c0c62e 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 @@ -19,6 +19,7 @@ import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION; import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION_HASH; +import org.hyperledger.besu.collections.trie.BytesTrieSet; import org.hyperledger.besu.datatypes.AccessListEntry; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; @@ -43,7 +44,6 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.util.Deque; -import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; @@ -318,7 +318,7 @@ public TransactionProcessingResult processTransaction( final List accessListEntries = transaction.getAccessList().orElse(List.of()); // we need to keep a separate hash set of addresses in case they specify no storage. // No-storage is a common pattern, especially for Externally Owned Accounts - final Set
addressList = new HashSet<>(); + final Set
addressList = new BytesTrieSet<>(Address.SIZE); final Multimap storageList = HashMultimap.create(); int accessListStorageCount = 0; for (final var entry : accessListEntries) { @@ -500,7 +500,8 @@ public TransactionProcessingResult processTransaction( LOG.error("Critical Exception Processing Transaction", re); return TransactionProcessingResult.invalid( ValidationResult.invalid( - TransactionInvalidReason.INTERNAL_ERROR, "Internal Error in Besu - " + re)); + TransactionInvalidReason.INTERNAL_ERROR, + "Internal Error in Besu - " + re + "\n" + printableStackTraceFromThrowable(re))); } } @@ -525,4 +526,14 @@ protected long refunded( final long refundAllowance = Math.min(maxRefundAllowance, gasRefund); return gasRemaining + refundAllowance; } + + private String printableStackTraceFromThrowable(final RuntimeException re) { + final StringBuilder builder = new StringBuilder(); + + for (final StackTraceElement stackTraceElement : re.getStackTrace()) { + builder.append("\tat ").append(stackTraceElement.toString()).append("\n"); + } + + return builder.toString(); + } } 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 80eb7a19e9f..3715263fd2b 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 @@ -15,9 +15,11 @@ package org.hyperledger.besu.ethereum.mainnet; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; @@ -25,8 +27,8 @@ public interface ParentBeaconBlockRootHelper { // Modulus to use for the timestamp to store the root - public static final long HISTORY_BUFFER_LENGTH = 8191; - public static final Address BEACON_ROOTS_ADDRESS = + long HISTORY_BUFFER_LENGTH = 8191; + Address BEACON_ROOTS_ADDRESS = Address.fromHexString("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02"); static void storeParentBeaconBlockRoot( @@ -34,14 +36,19 @@ static void storeParentBeaconBlockRoot( /* see EIP-4788: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4788.md */ - final long timestampReduced = timestamp % HISTORY_BUFFER_LENGTH; + // If code is not deployed don't do anything + final MutableAccount account = worldUpdater.getOrCreate(BEACON_ROOTS_ADDRESS); + if (Hash.EMPTY.equals(account.getCodeHash())) { + return; + } + + final long timestampReduced = Long.remainderUnsigned(timestamp, HISTORY_BUFFER_LENGTH); final long timestampExtended = timestampReduced + HISTORY_BUFFER_LENGTH; final UInt256 timestampIndex = UInt256.valueOf(timestampReduced); final UInt256 rootIndex = UInt256.valueOf(timestampExtended); - final MutableAccount account = worldUpdater.getOrCreate(BEACON_ROOTS_ADDRESS); - account.setStorageValue(timestampIndex, UInt256.valueOf(timestamp)); + account.setStorageValue(timestampIndex, UInt256.fromBytes(Bytes.ofUnsignedLong(timestamp))); account.setStorageValue(rootIndex, UInt256.fromBytes(root)); worldUpdater.commit(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PoWSolver.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PoWSolver.java index 3248f304100..3161490478e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PoWSolver.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PoWSolver.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.mainnet; import org.hyperledger.besu.ethereum.chain.PoWObserver; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.util.Subscribers; import java.util.Optional; @@ -31,9 +32,9 @@ public class PoWSolver { - private final int maxOmmerDepth; private static final Logger LOG = LoggerFactory.getLogger(PoWSolver.class); - private final long powJobTimeToLive; + + private final MiningParameters miningParameters; public static class PoWSolverJob { @@ -76,7 +77,6 @@ PoWSolution getSolution() throws InterruptedException, ExecutionException { private final long NO_MINING_CONDUCTED = -1; - private final Iterable nonceGenerator; private final PoWHasher poWHasher; private volatile long hashesPerSecond = NO_MINING_CONDUCTED; private final Boolean stratumMiningEnabled; @@ -86,28 +86,26 @@ PoWSolution getSolution() throws InterruptedException, ExecutionException { private final ExpiringMap currentJobs = new ExpiringMap<>(); public PoWSolver( - final Iterable nonceGenerator, + final MiningParameters miningParameters, final PoWHasher poWHasher, final Boolean stratumMiningEnabled, final Subscribers ethHashObservers, - final EpochCalculator epochCalculator, - final long powJobTimeToLive, - final int maxOmmerDepth) { - this.nonceGenerator = nonceGenerator; + final EpochCalculator epochCalculator) { + this.miningParameters = miningParameters; this.poWHasher = poWHasher; this.stratumMiningEnabled = stratumMiningEnabled; this.ethHashObservers = ethHashObservers; ethHashObservers.forEach(observer -> observer.setSubmitWorkCallback(this::submitSolution)); this.epochCalculator = epochCalculator; - this.powJobTimeToLive = powJobTimeToLive; - this.maxOmmerDepth = maxOmmerDepth; } public PoWSolution solveFor(final PoWSolverJob job) throws InterruptedException, ExecutionException { currentJob = Optional.of(job); currentJobs.put( - job.getInputs().getPrePowHash(), job, System.currentTimeMillis() + powJobTimeToLive); + job.getInputs().getPrePowHash(), + job, + System.currentTimeMillis() + miningParameters.getUnstable().getPowJobTimeToLive()); if (stratumMiningEnabled) { LOG.debug( "solving with stratum miner for {} observers", ethHashObservers.getSubscriberCount()); @@ -123,7 +121,7 @@ private void findValidNonce() { final Stopwatch operationTimer = Stopwatch.createStarted(); final PoWSolverJob job = currentJob.get(); long hashesExecuted = 0; - for (final Long n : nonceGenerator) { + for (final Long n : miningParameters.getNonceGenerator().get()) { if (job.isDone()) { return; @@ -183,7 +181,7 @@ public boolean submitSolution(final PoWSolution solution) { solution.getPowHash(), ommerCandidate.getInputs().getBlockNumber(), distanceToHead); - if (distanceToHead <= maxOmmerDepth) { + if (distanceToHead <= miningParameters.getUnstable().getMaxOmmerDepth()) { jobToTestWith = ommerCandidate; } else { LOG.debug("Discarded ommer solution as too far from head {}", distanceToHead); @@ -213,6 +211,6 @@ public boolean submitSolution(final PoWSolution solution) { } public Iterable getNonceGenerator() { - return nonceGenerator; + return miningParameters.getNonceGenerator().get(); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java index 012bb469c6a..d03a3fe90ef 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java @@ -62,7 +62,7 @@ private TimestampProtocolSpec(final long timestamp, final ProtocolSpec protocolS @Override public boolean isOnOrAfterMilestoneBoundary(final ProcessableBlockHeader header) { - return header.getTimestamp() >= timestamp; + return Long.compareUnsigned(header.getTimestamp(), timestamp) >= 0; } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/IncrementalTimestampRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/IncrementalTimestampRule.java index bc29e0db9f2..72b5161a775 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/IncrementalTimestampRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/IncrementalTimestampRule.java @@ -28,6 +28,6 @@ public boolean validate( final long blockTimestamp = header.getTimestamp(); final long parentTimestamp = parent.getTimestamp(); - return blockTimestamp > parentTimestamp; + return Long.compareUnsigned(blockTimestamp, parentTimestamp) > 0; } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java index da12289afa8..a6441f970fb 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java @@ -41,6 +41,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; @@ -77,7 +79,6 @@ import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Collectors; import org.apache.tuweni.bytes.Bytes; @@ -205,26 +206,20 @@ public int getDatabaseVersion() { static class TestBlockCreator extends AbstractBlockCreator { private TestBlockCreator( - final Address coinbase, + final MiningParameters miningParameters, final MiningBeneficiaryCalculator miningBeneficiaryCalculator, - final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader) { super( - coinbase, + miningParameters, miningBeneficiaryCalculator, - targetGasLimitSupplier, extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, Optional.empty()); } @@ -234,16 +229,26 @@ static TestBlockCreator forHeader( final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final TransactionPool transactionPool) { + + final MiningParameters miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(Bytes.fromHexString("deadbeef")) + .targetGasLimit(30_000_000L) + .minTransactionGasPrice(Wei.ONE) + .minBlockOccupancyRatio(0d) + .coinbase(Address.ZERO) + .build()) + .build(); + return new TestBlockCreator( - Address.ZERO, + miningParameters, __ -> Address.ZERO, - () -> Optional.of(30_000_000L), __ -> Bytes.fromHexString("deadbeef"), transactionPool, protocolContext, protocolSchedule, - Wei.of(1L), - 0d, parentHeader); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotIsolationTests.java index ed4b4549674..03407d2868f 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotIsolationTests.java @@ -61,8 +61,11 @@ public void testIsolatedFromHead_behindHead() { assertThat(res.isSuccessful()).isTrue(); assertThat(res2.isSuccessful()).isTrue(); - assertThat(archive.getTrieLogManager().containWorldStateStorage(firstBlock.getHash())).isTrue(); - assertThat(archive.getTrieLogManager().containWorldStateStorage(secondBlock.getHash())) + assertThat( + archive.getCachedWorldStorageManager().containWorldStateStorage(firstBlock.getHash())) + .isTrue(); + assertThat( + archive.getCachedWorldStorageManager().containWorldStateStorage(secondBlock.getHash())) .isTrue(); assertThat(archive.getMutable().get(testAddress)).isNotNull(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java index b492b67ffdb..0721522ffb1 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoader; +import org.hyperledger.besu.ethereum.bonsai.cache.CachedWorldStorageManager; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogFactoryImpl; import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogLayer; @@ -74,6 +75,7 @@ public class BonsaiWorldStateArchiveTest { @Mock SegmentedKeyValueStorageTransaction segmentedKeyValueStorageTransaction; BonsaiWorldStateProvider bonsaiWorldStateArchive; + @Mock CachedWorldStorageManager cachedWorldStorageManager; @Mock TrieLogManager trieLogManager; @BeforeEach @@ -100,6 +102,7 @@ public void testGetMutableReturnPersistedStateWhenNeeded() { .thenReturn(Optional.of(chainHead.getHash().toArrayUnsafe())); bonsaiWorldStateArchive = new BonsaiWorldStateProvider( + cachedWorldStorageManager, trieLogManager, new BonsaiWorldStateKeyValueStorage(storageProvider, new NoOpMetricsSystem()), blockchain, @@ -123,7 +126,7 @@ public void testGetMutableReturnEmptyWhenLoadMoreThanLimitLayersBack() { final BlockHeader chainHead = blockBuilder.number(512).buildHeader(); when(blockchain.getChainHeadHeader()).thenReturn(chainHead); assertThat(bonsaiWorldStateArchive.getMutable(blockHeader, false)).isEmpty(); - verify(trieLogManager, Mockito.never()).getWorldState(any(Hash.class)); + verify(cachedWorldStorageManager, Mockito.never()).getWorldState(any(Hash.class)); } @Test @@ -131,6 +134,7 @@ public void testGetMutableWhenLoadLessThanLimitLayersBack() { bonsaiWorldStateArchive = new BonsaiWorldStateProvider( + cachedWorldStorageManager, trieLogManager, new BonsaiWorldStateKeyValueStorage(storageProvider, new NoOpMetricsSystem()), blockchain, @@ -142,7 +146,7 @@ public void testGetMutableWhenLoadLessThanLimitLayersBack() { when(mockWorldState.freeze()).thenReturn(mockWorldState); when(trieLogManager.getMaxLayersToLoad()).thenReturn(Long.valueOf(512)); - when(trieLogManager.getWorldState(blockHeader.getHash())) + when(cachedWorldStorageManager.getWorldState(blockHeader.getHash())) .thenReturn(Optional.of(mockWorldState)); when(blockchain.getChainHeadHeader()).thenReturn(chainHead); assertThat(bonsaiWorldStateArchive.getMutable(blockHeader, false)) @@ -162,6 +166,7 @@ public void testGetMutableWithStorageInconsistencyRollbackTheState() { bonsaiWorldStateArchive = spy( new BonsaiWorldStateProvider( + cachedWorldStorageManager, trieLogManager, worldStateStorage, blockchain, @@ -186,6 +191,7 @@ public void testGetMutableWithStorageConsistencyNotRollbackTheState() { bonsaiWorldStateArchive = spy( new BonsaiWorldStateProvider( + cachedWorldStorageManager, trieLogManager, worldStateStorage, blockchain, @@ -222,6 +228,7 @@ public void testGetMutableWithStorageConsistencyToRollbackAndRollForwardTheState bonsaiWorldStateArchive = spy( new BonsaiWorldStateProvider( + cachedWorldStorageManager, trieLogManager, worldStateStorage, blockchain, @@ -261,6 +268,7 @@ public void testGetMutableWithRollbackNotOverrideTrieLogLayer() { bonsaiWorldStateArchive = spy( new BonsaiWorldStateProvider( + cachedWorldStorageManager, trieLogManager, new BonsaiWorldStateKeyValueStorage(storageProvider, new NoOpMetricsSystem()), blockchain, diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManagerTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManagerTests.java index 35ce1b77c06..0c911d33556 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManagerTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManagerTests.java @@ -19,15 +19,12 @@ import static org.mockito.Mockito.spy; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateProvider; -import org.hyperledger.besu.ethereum.bonsai.cache.CachedWorldStorageManager; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.concurrent.atomic.AtomicBoolean; @@ -48,7 +45,6 @@ public class TrieLogManagerTests { @Mock BonsaiWorldStateKeyValueStorage bonsaiWorldStateKeyValueStorage; @Mock BonsaiWorldState worldState; - @Mock BonsaiWorldStateProvider archive; @Mock Blockchain blockchain; BonsaiWorldStateUpdateAccumulator bonsaiUpdater = spy(new BonsaiWorldStateUpdateAccumulator(worldState, (__, ___) -> {}, (__, ___) -> {})); @@ -57,14 +53,7 @@ public class TrieLogManagerTests { @BeforeEach public void setup() { - trieLogManager = - new CachedWorldStorageManager( - archive, - blockchain, - bonsaiWorldStateKeyValueStorage, - new NoOpMetricsSystem(), - 512, - null); + trieLogManager = new TrieLogManager(blockchain, bonsaiWorldStateKeyValueStorage, 512, null); } @Test diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java index 92cdce6eb0e..91553afed33 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java @@ -21,6 +21,9 @@ import static org.mockito.Mockito.mock; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.util.Subscribers; import java.util.Arrays; @@ -48,13 +51,11 @@ public void emptyHashRateAndWorkDefinitionIsReportedPriorToSolverStarting() { final List noncesToTry = Arrays.asList(1L, 1L, 1L, 1L, 1L, 1L, 0L); final PoWSolver solver = new PoWSolver( - noncesToTry, + createMiningParameters(noncesToTry, 1000, 8), PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); assertThat(solver.hashesPerSecond()).isEqualTo(Optional.empty()); assertThat(solver.getWorkDefinition()).isEqualTo(Optional.empty()); @@ -83,13 +84,11 @@ public void hashRateIsProducedSuccessfully() throws InterruptedException, Execut final PoWSolver solver = new PoWSolver( - noncesToTry, + createMiningParameters(noncesToTry, 1000, 8), hasher, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final Stopwatch operationTimer = Stopwatch.createStarted(); final PoWSolverInputs inputs = new PoWSolverInputs(UInt256.ONE, Bytes.EMPTY, 5); @@ -150,13 +149,15 @@ public void ifInvokedTwiceProducesCorrectAnswerForSecondInvocation() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 1000, + 8), PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); PoWSolution soln = solver.solveFor(PoWSolver.PoWSolverJob.createFromInputs(firstInputs)); assertThat(soln.getMixHash()).isEqualTo(expectedFirstOutput.getMixHash()); @@ -210,13 +211,15 @@ public void canAcceptSolutionsSerially() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 1000, + 8), PoWHasher.ETHASH_LIGHT, true, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); CompletableFuture soln1 = new CompletableFuture<>(); CompletableFuture soln2 = new CompletableFuture<>(); @@ -291,13 +294,15 @@ public void canAcceptSolutionsForMultipleJobs() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 10000, + 8), PoWHasher.ETHASH_LIGHT, true, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 10000, - 8); + new EpochCalculator.DefaultEpochCalculator()); CompletableFuture soln1 = new CompletableFuture<>(); CompletableFuture soln2 = new CompletableFuture<>(); @@ -382,13 +387,15 @@ public void canAcceptAtMostOneSolution() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 1000, + 8), PoWHasher.ETHASH_LIGHT, true, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); CompletableFuture soln1 = new CompletableFuture<>(); CompletableFuture soln2 = new CompletableFuture<>(); @@ -475,13 +482,15 @@ public void rejectsSolutionsForOldBlocks() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 1000, + 8), PoWHasher.ETHASH_LIGHT, true, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); CompletableFuture soln1 = new CompletableFuture<>(); CompletableFuture soln2 = new CompletableFuture<>(); @@ -520,4 +529,16 @@ public void rejectsSolutionsForOldBlocks() assertThat(result2.getMixHash()).isEqualTo(expectedSecondOutput.getMixHash()); powThread1.interrupt(); } + + private MiningParameters createMiningParameters( + final List nonceToTry, final int powJobTimeToLive, final int maxOmmerDepth) { + return ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().nonceGenerator(nonceToTry).build()) + .unstable( + ImmutableMiningParameters.Unstable.builder() + .maxOmmerDepth(maxOmmerDepth) + .powJobTimeToLive(powJobTimeToLive) + .build()) + .build(); + } } diff --git a/ethereum/eth/build.gradle b/ethereum/eth/build.gradle index a40b49afffb..1919efdd4f2 100644 --- a/ethereum/eth/build.gradle +++ b/ethereum/eth/build.gradle @@ -58,6 +58,7 @@ dependencies { implementation 'io.tmio:tuweni-bytes' implementation 'io.tmio:tuweni-units' implementation 'io.tmio:tuweni-rlp' + implementation 'org.rocksdb:rocksdbjni' annotationProcessor "org.immutables:value" implementation "org.immutables:value-annotations" diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTask.java index ca3c90af5f1..06151ba68c8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTask.java @@ -27,8 +27,10 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,12 +40,12 @@ public class GetPooledTransactionsFromPeerTask extends AbstractPeerRequestTask hashes; + private final Set hashes; private GetPooledTransactionsFromPeerTask( final EthContext ethContext, final List hashes, final MetricsSystem metricsSystem) { super(ethContext, EthPV65.GET_POOLED_TRANSACTIONS, metricsSystem); - this.hashes = List.copyOf(hashes); + this.hashes = new HashSet<>(hashes); } public static GetPooledTransactionsFromPeerTask forHashes( @@ -51,7 +53,7 @@ public static GetPooledTransactionsFromPeerTask forHashes( return new GetPooledTransactionsFromPeerTask(ethContext, hashes, metricsSystem); } - public List getTransactionHashes() { + public Set getTransactionHashes() { return hashes; } @@ -60,7 +62,7 @@ protected PendingPeerRequest sendRequest() { return sendRequestToPeer( peer -> { LOG.debug("Requesting {} transaction pool entries from peer {}.", hashes.size(), peer); - return peer.getPooledTransactions(hashes); + return peer.getPooledTransactions(new ArrayList<>(hashes)); }, 0); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/StorageExceptionManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/StorageExceptionManager.java new file mode 100644 index 00000000000..97d1506cf3e --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/StorageExceptionManager.java @@ -0,0 +1,64 @@ +/* + * Copyright ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.sync; + +import org.hyperledger.besu.plugin.services.exception.StorageException; + +import java.util.EnumSet; +import java.util.Optional; + +import org.rocksdb.RocksDBException; +import org.rocksdb.Status; + +public final class StorageExceptionManager { + + private static final EnumSet RETRYABLE_STATUS_CODES = + EnumSet.of(Status.Code.TimedOut, Status.Code.TryAgain, Status.Code.Busy); + + private static final long ERROR_THRESHOLD = 1000; + + private static long retryableErrorCounter; + /** + * Determines if an operation can be retried based on the error received. This method checks if + * the cause of the StorageException is a RocksDBException. If it is, it retrieves the status code + * of the RocksDBException and checks if it is contained in the list of retryable {@link + * StorageExceptionManager.RETRYABLE_STATUS_CODES} status codes. + * + * @param e the StorageException to check + * @return true if the operation can be retried, false otherwise + */ + public static boolean canRetryOnError(final StorageException e) { + return Optional.of(e.getCause()) + .filter(z -> z instanceof RocksDBException) + .map(RocksDBException.class::cast) + .map(RocksDBException::getStatus) + .map(Status::getCode) + .map(RETRYABLE_STATUS_CODES::contains) + .map( + result -> { + retryableErrorCounter++; + return result; + }) + .orElse(false); + } + + public static long getRetryableErrorCounter() { + return retryableErrorCounter; + } + + public static boolean errorCountAtThreshold() { + return retryableErrorCounter % ERROR_THRESHOLD == 1; + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java index 94592b98d81..1ab202ee6ce 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java @@ -14,15 +14,26 @@ */ package org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.canRetryOnError; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.errorCountAtThreshold; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.getRetryableErrorCounter; + import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldDownloadState; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.services.tasks.Task; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class PersistDataStep { + + private static final Logger LOG = LoggerFactory.getLogger(PersistDataStep.class); + private final WorldStateStorage worldStateStorage; public PersistDataStep(final WorldStateStorage worldStateStorage) { @@ -33,24 +44,40 @@ public List> persist( final List> tasks, final BlockHeader blockHeader, final WorldDownloadState downloadState) { - final Updater updater = worldStateStorage.updater(); - tasks.stream() - .map( - task -> { - enqueueChildren(task, downloadState); - return task; - }) - .map(Task::getData) - .filter(request -> request.getData() != null) - .forEach( - request -> { - if (isRootState(blockHeader, request)) { - downloadState.setRootNodeData(request.getData()); - } else { - request.persist(updater); - } - }); - updater.commit(); + try { + final Updater updater = worldStateStorage.updater(); + tasks.stream() + .map( + task -> { + enqueueChildren(task, downloadState); + return task; + }) + .map(Task::getData) + .filter(request -> request.getData() != null) + .forEach( + request -> { + if (isRootState(blockHeader, request)) { + downloadState.setRootNodeData(request.getData()); + } else { + request.persist(updater); + } + }); + updater.commit(); + } catch (StorageException storageException) { + if (canRetryOnError(storageException)) { + // We reset the task by setting it to null. This way, it is considered as failed by the + // pipeline, and it will attempt to execute it again later. + if (errorCountAtThreshold()) { + LOG.info( + "Encountered {} retryable RocksDB errors, latest error message {}", + getRetryableErrorCounter(), + storageException.getMessage()); + } + tasks.forEach(nodeDataRequestTask -> nodeDataRequestTask.getData().setData(null)); + } else { + throw storageException; + } + } return tasks; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java index 5264eac2b50..c24dbf6037d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java @@ -14,11 +14,16 @@ */ package org.hyperledger.besu.ethereum.eth.sync.snapsync; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.canRetryOnError; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.errorCountAtThreshold; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.getRetryableErrorCounter; + import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.TrieNodeHealingRequest; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.services.pipeline.Pipe; import org.hyperledger.besu.services.tasks.Task; @@ -27,9 +32,12 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class LoadLocalDataStep { + private static final Logger LOG = LoggerFactory.getLogger(LoadLocalDataStep.class); private final WorldStateStorage worldStateStorage; private final SnapWorldDownloadState downloadState; private final SnapSyncProcessState snapSyncState; @@ -58,19 +66,35 @@ public Stream> loadLocalDataTrieNode( final Task task, final Pipe> completedTasks) { final TrieNodeHealingRequest request = (TrieNodeHealingRequest) task.getData(); // check if node is already stored in the worldstate - if (snapSyncState.hasPivotBlockHeader()) { - Optional existingData = request.getExistingData(downloadState, worldStateStorage); - if (existingData.isPresent()) { - existingNodeCounter.inc(); - request.setData(existingData.get()); - request.setRequiresPersisting(false); - final WorldStateStorage.Updater updater = worldStateStorage.updater(); - request.persist( - worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); - updater.commit(); - downloadState.enqueueRequests(request.getRootStorageRequests(worldStateStorage)); - completedTasks.put(task); - return Stream.empty(); + try { + if (snapSyncState.hasPivotBlockHeader()) { + Optional existingData = request.getExistingData(downloadState, worldStateStorage); + if (existingData.isPresent()) { + existingNodeCounter.inc(); + request.setData(existingData.get()); + request.setRequiresPersisting(false); + final WorldStateStorage.Updater updater = worldStateStorage.updater(); + request.persist( + worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); + updater.commit(); + downloadState.enqueueRequests(request.getRootStorageRequests(worldStateStorage)); + completedTasks.put(task); + return Stream.empty(); + } + } + } catch (StorageException storageException) { + if (canRetryOnError(storageException)) { + // We reset the task by setting it to null. This way, it is considered as failed by the + // pipeline, and it will attempt to execute it again later. + if (errorCountAtThreshold()) { + LOG.info( + "Encountered {} retryable RocksDB errors, latest error message {}", + getRetryableErrorCounter(), + storageException.getMessage()); + } + task.getData().clear(); + } else { + throw storageException; } } return Stream.of(task); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java index 6a39f648716..df3696ccdf7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java @@ -14,16 +14,25 @@ */ package org.hyperledger.besu.ethereum.eth.sync.snapsync; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.canRetryOnError; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.errorCountAtThreshold; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.getRetryableErrorCounter; + import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.TrieNodeHealingRequest; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.services.tasks.Task; import java.util.List; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class PersistDataStep { + private static final Logger LOG = LoggerFactory.getLogger(PersistDataStep.class); private final SnapSyncProcessState snapSyncState; private final WorldStateStorage worldStateStorage; @@ -43,41 +52,58 @@ public PersistDataStep( } public List> persist(final List> tasks) { - final WorldStateStorage.Updater updater = worldStateStorage.updater(); - for (Task task : tasks) { - if (task.getData().isResponseReceived()) { - // enqueue child requests - final Stream childRequests = - task.getData().getChildRequests(downloadState, worldStateStorage, snapSyncState); - if (!(task.getData() instanceof TrieNodeHealingRequest)) { - enqueueChildren(childRequests); - } else { - if (!task.getData().isExpired(snapSyncState)) { + try { + final WorldStateStorage.Updater updater = worldStateStorage.updater(); + for (Task task : tasks) { + if (task.getData().isResponseReceived()) { + // enqueue child requests + final Stream childRequests = + task.getData().getChildRequests(downloadState, worldStateStorage, snapSyncState); + if (!(task.getData() instanceof TrieNodeHealingRequest)) { enqueueChildren(childRequests); } else { - continue; + if (!task.getData().isExpired(snapSyncState)) { + enqueueChildren(childRequests); + } else { + continue; + } } - } - // persist nodes - final int persistedNodes = - task.getData() - .persist( - worldStateStorage, - updater, - downloadState, - snapSyncState, - snapSyncConfiguration); - if (persistedNodes > 0) { - if (task.getData() instanceof TrieNodeHealingRequest) { - downloadState.getMetricsManager().notifyTrieNodesHealed(persistedNodes); - } else { - downloadState.getMetricsManager().notifyNodesGenerated(persistedNodes); + // persist nodes + final int persistedNodes = + task.getData() + .persist( + worldStateStorage, + updater, + downloadState, + snapSyncState, + snapSyncConfiguration); + if (persistedNodes > 0) { + if (task.getData() instanceof TrieNodeHealingRequest) { + downloadState.getMetricsManager().notifyTrieNodesHealed(persistedNodes); + } else { + downloadState.getMetricsManager().notifyNodesGenerated(persistedNodes); + } } } } + updater.commit(); + } catch (StorageException storageException) { + if (canRetryOnError(storageException)) { + // We reset the task by setting it to null. This way, it is considered as failed by the + // pipeline, and it will attempt to execute it again later. not display all the retryable + // issues + if (errorCountAtThreshold()) { + LOG.info( + "Encountered {} retryable RocksDB errors, latest error message {}", + getRetryableErrorCounter(), + storageException.getMessage()); + } + tasks.forEach(task -> task.getData().clear()); + } else { + throw storageException; + } } - updater.commit(); return tasks; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloadProcess.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloadProcess.java index c8afc582b72..c19ae6facc7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloadProcess.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloadProcess.java @@ -231,6 +231,22 @@ public SnapWorldStateDownloadProcess build() { "step", "action"); + /* + The logic and intercommunication of different pipelines can be summarized as follows: + + 1. Account Data Pipeline (fetchAccountDataPipeline): This process starts with downloading the leaves of the account tree in ranges, with multiple ranges being processed simultaneously. + If the downloaded accounts are smart contracts, tasks are created in the storage pipeline to download the storage tree of the smart contract, and in the code download pipeline for the smart contract. + + 2. Storage Data Pipeline (fetchStorageDataPipeline): Running parallel to the account data pipeline, this pipeline downloads the storage of smart contracts. + If all slots cannot be downloaded at once, tasks are created in the fetchLargeStorageDataPipeline to download the storage by range, allowing parallelization of large account downloads. + + 3. Code Data Pipeline (fetchCodePipeline): This pipeline, running concurrently with the account and storage data pipelines, is responsible for downloading the code of the smart contracts. + + 4. Large Storage Data Pipeline (fetchLargeStorageDataPipeline): This pipeline is used when the storage data for a smart contract is too large to be downloaded at once. + It enables the storage data to be downloaded in ranges, similar to the account data. + + 5. Healing Phase: Initiated after all other pipelines have completed their tasks, this phase ensures the integrity and completeness of the downloaded data. + */ final Pipeline> completionPipeline = PipelineBuilder.>createPipeline( "requestDataAvailable", bufferCapacity, outputCounter, true, "node_data_request") diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java index fd6acde3754..01f17eb79b4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java @@ -51,8 +51,8 @@ public class StackTrie { private final AtomicInteger nbSegments; private final int maxSegments; private final Bytes32 startKeyHash; - private final Map elements; - private final AtomicLong elementsCount; + private Map elements; + private AtomicLong elementsCount; public StackTrie(final Hash rootHash, final Bytes32 startKeyHash) { this(rootHash, 1, 1, startKeyHash); @@ -78,6 +78,12 @@ public void addElement( taskIdentifier, ImmutableTaskElement.builder().proofs(proofs).keys(keys).build()); } + public void removeElement(final Bytes32 taskIdentifier) { + if (this.elements.containsKey(taskIdentifier)) { + this.elementsCount.addAndGet(-this.elements.remove(taskIdentifier).keys().size()); + } + } + public TaskElement getElement(final Bytes32 taskIdentifier) { return this.elements.get(taskIdentifier); } @@ -142,6 +148,11 @@ public void maybeStoreNode(final Bytes location, final Node node) { } } + public void clear() { + this.elements = new LinkedHashMap<>(); + this.elementsCount = new AtomicLong(); + } + public boolean addSegment() { if (nbSegments.get() > maxSegments) { return false; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java index a1a6bc63da4..06181fd09f1 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java @@ -216,6 +216,12 @@ public TreeMap getAccounts() { return stackTrie.getElement(startKeyHash).keys(); } + @Override + public void clear() { + stackTrie.clear(); + isProofValid = Optional.of(false); + } + public Bytes serialize() { return RLP.encode( out -> { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java index 96673d6f874..5db5ec0211e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java @@ -88,6 +88,11 @@ public Bytes32 getAccountHash() { return accountHash; } + @Override + public void clear() { + setCode(Bytes.EMPTY); + } + public Bytes32 getCodeHash() { return codeHash; } 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 c18d063d74d..14839f0ad6f 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 @@ -205,6 +205,12 @@ public Bytes32 getEndKeyHash() { return endKeyHash; } + @Override + public void clear() { + this.isProofValid = Optional.of(false); + this.stackTrie.removeElement(startKeyHash); + } + @VisibleForTesting public void setProofValid(final boolean isProofValid) { this.isProofValid = Optional.of(isProofValid); 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 c04066141d8..ef7191a0167 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 @@ -123,6 +123,11 @@ public boolean isResponseReceived() { return !data.isEmpty() && Hash.hash(data).equals(getNodeHash()); } + @Override + public void clear() { + setData(Bytes.EMPTY); + } + @Override public boolean isExpired(final SnapSyncProcessState snapSyncState) { return snapSyncState.isExpired(this); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index 60574c92152..8884eefdd6e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -27,7 +27,6 @@ import org.hyperledger.besu.consensus.merge.ForkchoiceEvent; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -1116,7 +1115,7 @@ public void transactionMessagesGoToTheCorrectExecutor() { TestClock.system(ZoneId.systemDefault()), metricsSystem, new SyncState(blockchain, ethManager.ethContext().getEthPeers()), - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + MiningParameters.newDefault(), TransactionPoolConfiguration.DEFAULT, null) .setEnabled(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java index dc410937341..88f5457a121 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java @@ -22,7 +22,6 @@ import org.hyperledger.besu.crypto.SECPPublicKey; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; @@ -136,7 +135,7 @@ public void setupTest() { TestClock.system(ZoneId.systemDefault()), metricsSystem, syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ONE).build(), + MiningParameters.newDefault(), TransactionPoolConfiguration.DEFAULT, null); transactionPool.setEnabled(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java index f50237515e4..4c7d521a16b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java @@ -43,7 +43,7 @@ protected List generateDataToBeRequested() { Transaction tx = new TransactionTestFixture() .nonce(genesisAccountNonce + i) - .gasPrice(Wei.ONE) + .gasPrice(Wei.of(2000)) .gasLimit(100000) .chainId(Optional.empty()) .createTransaction(genesisAccountKeyPair); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java index d9c98f3a92b..ee3b6da2425 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java @@ -132,7 +132,10 @@ public abstract class AbstractTransactionPoolTest { protected TransactionValidatorFactory transactionValidatorFactory; @Mock protected PendingTransactionAddedListener listener; - @Mock protected MiningParameters miningParameters; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + protected MiningParameters miningParameters; + @Mock protected TransactionsMessageSender transactionsMessageSender; @Mock protected NewPooledTransactionHashesMessageSender newPooledTransactionHashesMessageSender; @Mock protected ProtocolSpec protocolSpec; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java index 6d3eb668f8f..90f77a783f3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java @@ -26,7 +26,6 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.GenesisState; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -163,7 +162,7 @@ public boolean isMessagePermitted(final EnodeURL destinationEnode, final int cod TestClock.system(ZoneId.systemDefault()), metricsSystem, syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + MiningParameters.newDefault(), TransactionPoolConfiguration.DEFAULT, null); 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 3da9bb9c66d..e902c2c1dd8 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 @@ -27,7 +27,6 @@ import org.hyperledger.besu.config.StubGenesisConfigOptions; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -241,7 +240,7 @@ private void setupInitialSyncPhase(final boolean hasInitialSyncPhase) { TestClock.fixed(), new TransactionPoolMetrics(new NoOpMetricsSystem()), syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ONE).build(), + MiningParameters.newDefault(), ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(1) .pendingTxRetentionPeriod(1) @@ -350,7 +349,7 @@ private TransactionPool createTransactionPool( TestClock.fixed(), new NoOpMetricsSystem(), syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ONE).build(), + MiningParameters.newDefault(), ImmutableTransactionPoolConfiguration.builder() .txPoolImplementation(implementation) .txPoolMaxSize(1) 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 a2d966f0675..f45797f9643 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 @@ -100,6 +100,11 @@ public class StateTestSubCommand implements Runnable { description = "Limit execution to one value variable.") private Integer valueIndex = null; + @Option( + names = {"--fork-index"}, + description = "Limit execution to one fork.") + private String forkIndex = null; + @ParentCommand private final EvmToolCommand parentCommand; // picocli does it magically @@ -197,6 +202,9 @@ private void traceTestSpecs(final String test, final ListBesu reference-test style test cases should supply a stateroot to verify to prevent bonsai - * regressions. + * For reference tests world state root validation is handled in the harness, this stubs out the + * behavior to always pass. * * @param calculatedStateRoot state root calculated during bonsai persist step. * @param header supplied reference test block header. */ @Override protected void verifyWorldStateRoot(final Hash calculatedStateRoot, final BlockHeader header) { - if (!disableRootHashVerification) { - super.verifyWorldStateRoot(calculatedStateRoot, header); - } + // The test harness validates the root hash, no need to validate in-line for reference test } @JsonCreator @@ -109,9 +105,16 @@ public static BonsaiReferenceTestWorldState create( new InMemoryKeyValueStorageProvider(), metricsSystem), preImageProxy); + final NoOpCachedWorldStorageManager noOpCachedWorldStorageManager = + new NoOpCachedWorldStorageManager(); + final BonsaiReferenceTestWorldState worldState = new BonsaiReferenceTestWorldState( - worldStateStorage, cachedMerkleTrieLoader, trieLogManager, preImageProxy); + worldStateStorage, + cachedMerkleTrieLoader, + noOpCachedWorldStorageManager, + trieLogManager, + preImageProxy); final WorldUpdater updater = worldState.updater(); for (final Map.Entry entry : accounts.entrySet()) { @@ -127,30 +130,23 @@ public Stream streamAccounts(final Bytes32 startKeyHash, fina return this.refTestStorage.streamAccounts(this, startKeyHash, limit); } - public void disableRootHashVerification() { - disableRootHashVerification = true; - } - - static class NoOpTrieLogManager implements TrieLogManager { - private final Subscribers trieLogObservers = Subscribers.create(); - private final TrieLogFactory trieLogFactory = new TrieLogFactoryImpl(); + static class NoOpCachedWorldStorageManager extends CachedWorldStorageManager { - @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))); + public NoOpCachedWorldStorageManager() { + super( + null, + new BonsaiWorldStateKeyValueStorage( + new InMemoryKeyValueStorageProvider(), new NoOpMetricsSystem()), + new NoOpMetricsSystem()); } @Override public void addCachedLayer( final BlockHeader blockHeader, final Hash worldStateRootHash, - final BonsaiWorldState forWorldState) {} + final BonsaiWorldState forWorldState) { + // reference tests do not cache layers + } @Override public boolean containWorldStateStorage(final Hash blockHash) { @@ -174,15 +170,36 @@ public Optional getHeadWorldState( } @Override - public long getMaxLayersToLoad() { - return 0; + public void reset() { + // reference test world states are not re-used + } + } + + static class NoOpTrieLogManager extends TrieLogManager { + + public NoOpTrieLogManager() { + super(null, null, 0, null); } + @SuppressWarnings("UnsynchronizedOverridesSynchronized") @Override - public void reset() {} + 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 long getMaxLayersToLoad() { + return 0; + } @Override - public Optional getTrieLogLayer(final Hash blockHash) { + public Optional getTrieLogLayer(final Hash blockHash) { return Optional.empty(); } diff --git a/ethereum/referencetests/src/reference-test/external-resources b/ethereum/referencetests/src/reference-test/external-resources index 661356317ac..02c1859633a 160000 --- a/ethereum/referencetests/src/reference-test/external-resources +++ b/ethereum/referencetests/src/reference-test/external-resources @@ -1 +1 @@ -Subproject commit 661356317ac6df52208d54187e692472a25a01f8 +Subproject commit 02c1859633abbdf776956136931ea247485c9f90 diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java index 9d6f7982d8d..af6405fb0ff 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java @@ -82,13 +82,6 @@ public class BlockchainReferenceTestTools { // Perfectly valid test pre-merge. params.ignore("UncleFromSideChain_(Merge|Shanghai|Cancun|Prague|Osaka|Bogota)"); - // Reference Tests are old. Max blob count is 6. - params.ignore("blobhashListBounds5"); - params.ignore("blockWithAllTransactionTypes"); - - // EIP-4788 is still in flux and the current fill is not against the final address - params.ignore("\\[Cancun\\]"); - // EOF tests are written against an older version of the spec params.ignore("/stEOF/"); } 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 83388fe2526..af6181dab00 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,10 +21,8 @@ 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; @@ -35,10 +33,8 @@ 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; import org.hyperledger.besu.evm.log.Log; -import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.testutil.JsonTestParameters; @@ -109,9 +105,6 @@ private static ProtocolSpec protocolSpec(final String name) { params.ignore("CALLBlake2f_MaxRounds.*"); params.ignore("loopMul-.*"); - // Reference Tests are old. Max blob count is 6. - params.ignore("blobhashListBounds5"); - // EOF tests are written against an older version of the spec params.ignore("/stEOF/"); } 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 4d29bfd213e..bed7652c6d7 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 @@ -24,7 +24,6 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.blockcreation.IncrementingNonceGenerator; import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; import org.hyperledger.besu.ethereum.chain.GenesisState; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -32,6 +31,9 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.Unstable; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; @@ -99,7 +101,7 @@ public class RetestethContext { private HeaderValidationMode headerValidationMode; private BlockReplay blockReplay; private RetestethClock retestethClock; - + private MiningParameters miningParameters; private TransactionPool transactionPool; private EthScheduler ethScheduler; private PoWSolver poWSolver; @@ -180,25 +182,33 @@ private boolean buildContext( ? HeaderValidationMode.LIGHT : HeaderValidationMode.FULL; - final Iterable nonceGenerator = new IncrementingNonceGenerator(0); + miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .coinbase(coinbase) + .extraData(extraData) + .targetGasLimit(blockchain.getChainHeadHeader().getGasLimit()) + .minBlockOccupancyRatio(0.0) + .minTransactionGasPrice(Wei.ZERO) + .build()) + .unstable(Unstable.builder().powJobTimeToLive(1000).maxOmmerDepth(8).build()) + .build(); + miningParameters.setMinTransactionGasPrice(Wei.ZERO); poWSolver = ("NoProof".equals(sealengine) || "NoReward".equals(sealEngine)) ? new PoWSolver( - nonceGenerator, + miningParameters, NO_WORK_HASHER, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8) + new EpochCalculator.DefaultEpochCalculator()) : new PoWSolver( - nonceGenerator, + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); blockReplay = new BlockReplay(protocolSchedule, blockchainQueries.getBlockchain()); @@ -239,7 +249,7 @@ private boolean buildContext( retestethClock, metricsSystem, syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + miningParameters, transactionPoolConfiguration, null); @@ -307,12 +317,8 @@ public TransactionPool getTransactionPool() { return transactionPool; } - public Address getCoinbase() { - return coinbase; - } - - public Bytes getExtraData() { - return extraData; + public MiningParameters getMiningParameters() { + return miningParameters; } public MutableBlockchain getBlockchain() { diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java index f802ee73e4b..6c3fddae1c7 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.retesteth.methods; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; @@ -24,14 +23,13 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.mainnet.BlockImportResult; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.retesteth.RetestethClock; import org.hyperledger.besu.ethereum.retesteth.RetestethContext; -import java.util.Optional; - public class TestMineBlocks implements JsonRpcMethod { private final RetestethContext context; @@ -62,17 +60,15 @@ private boolean mineNewBlock() { final ProtocolContext protocolContext = context.getProtocolContext(); final MutableBlockchain blockchain = context.getBlockchain(); final HeaderValidationMode headerValidationMode = context.getHeaderValidationMode(); + final MiningParameters miningParameters = context.getMiningParameters(); final PoWBlockCreator blockCreator = new PoWBlockCreator( - context.getCoinbase(), - () -> Optional.of(blockchain.getChainHeadHeader().getGasLimit()), - header -> context.getExtraData(), + miningParameters, + header -> miningParameters.getExtraData(), context.getTransactionPool(), protocolContext, protocolSchedule, context.getEthHashSolver(), - Wei.ZERO, - 0.0, blockchain.getChainHeadHeader()); final Block block = blockCreator.createBlock(retesethClock.instant().getEpochSecond()).getBlock(); diff --git a/evm/src/main/java/org/hyperledger/besu/collections/trie/BytesTrieSet.java b/evm/src/main/java/org/hyperledger/besu/collections/trie/BytesTrieSet.java new file mode 100644 index 00000000000..20e2d49af5c --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/collections/trie/BytesTrieSet.java @@ -0,0 +1,312 @@ +/* + * 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.collections.trie; + +import java.util.AbstractSet; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; + +import org.apache.tuweni.bytes.Bytes; + +/** + * A Bytes optimized set that stores values in a trie by byte + * + * @param Type of trie + */ +public class BytesTrieSet extends AbstractSet { + + record Node(byte[] leafArray, E leafObject, Node[] children) { + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof Node node)) return false; + return Arrays.equals(leafArray, node.leafArray) + && Objects.equals(leafObject, node.leafObject) + && Arrays.equals(children, node.children); + } + + @Override + public int hashCode() { + int result = Objects.hash(leafObject); + result = 31 * result + Arrays.hashCode(leafArray); + result = 31 * result + Arrays.hashCode(children); + return result; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Node{"); + sb.append("leaf="); + if (leafObject == null) sb.append("null"); + else { + sb.append('['); + System.out.println(leafObject.toHexString()); + sb.append(']'); + } + sb.append(", children="); + if (children == null) sb.append("null"); + else { + sb.append('['); + for (int i = 0; i < children.length; ++i) { + if (children[i] == null) { + continue; + } + sb.append(i == 0 ? "" : ", ").append(i).append("=").append(children[i]); + } + sb.append(']'); + } + sb.append('}'); + return sb.toString(); + } + } + + Node root; + + int size = 0; + final int byteLength; + + /** + * Create a BytesTrieSet with a fixed length + * + * @param byteLength length in bytes of the stored types + */ + public BytesTrieSet(final int byteLength) { + this.byteLength = byteLength; + } + + static class NodeWalker { + final Node node; + int lastRead; + + NodeWalker(final Node node) { + this.node = node; + this.lastRead = -1; + } + + NodeWalker nextNodeWalker() { + if (node.children == null) { + return null; + } + while (lastRead < 255) { + lastRead++; + Node child = node.children[lastRead]; + if (child != null) { + return new NodeWalker<>(child); + } + } + return null; + } + + E thisNode() { + return node.leafObject; + } + } + + @Override + public Iterator iterator() { + var result = + new Iterator() { + final Deque> stack = new ArrayDeque<>(); + E next; + E last; + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public E next() { + if (next == null) { + throw new NoSuchElementException(); + } + last = next; + advance(); + return last; + } + + @Override + public void remove() { + BytesTrieSet.this.remove(last); + } + + void advance() { + while (!stack.isEmpty()) { + NodeWalker thisStep = stack.peek(); + var nextStep = thisStep.nextNodeWalker(); + if (nextStep == null) { + stack.pop(); + if (thisStep.thisNode() != null) { + next = thisStep.thisNode(); + return; + } + } else { + stack.push(nextStep); + } + } + next = null; + } + }; + if (root != null) { + result.stack.add(new NodeWalker<>(root)); + } + result.advance(); + return result; + } + + @Override + public int size() { + return size; + } + + @Override + public boolean contains(final Object o) { + if (!(o instanceof Bytes bytes)) { + throw new IllegalArgumentException( + "Expected Bytes, got " + (o == null ? "null" : o.getClass().getName())); + } + byte[] array = bytes.toArrayUnsafe(); + if (array.length != byteLength) { + throw new IllegalArgumentException( + "Byte array is size " + array.length + " but set is size " + byteLength); + } + if (root == null) { + return false; + } + int level = 0; + Node current = root; + while (current != null) { + if (current.leafObject != null) { + return Arrays.compare(current.leafArray, array) == 0; + } + current = current.children[array[level] & 0xff]; + level++; + } + return false; + } + + @Override + public boolean remove(final Object o) { + // Two base cases, size==0 and size==1; + if (!(o instanceof Bytes bytes)) { + throw new IllegalArgumentException( + "Expected Bytes, got " + (o == null ? "null" : o.getClass().getName())); + } + byte[] array = bytes.toArrayUnsafe(); + if (array.length != byteLength) { + throw new IllegalArgumentException( + "Byte array is size " + array.length + " but set is size " + byteLength); + } + // Two base cases, size==0 and size==1; + if (root == null) { + // size==0 is easy, empty + return false; + } + if (root.leafObject != null) { + // size==1 just check and possibly remove the root + if (Arrays.compare(array, root.leafArray) == 0) { + root = null; + size--; + return true; + } else { + return false; + } + } + int level = 0; + Node current = root; + do { + int index = array[level] & 0xff; + Node next = current.children[index]; + if (next == null) { + return false; + } + if (next.leafObject != null) { + if (Arrays.compare(array, next.leafArray) == 0) { + // TODO there is no cleanup of empty branches + current.children[index] = null; + size--; + return true; + } else { + return false; + } + } + current = next; + + level++; + } while (true); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public boolean add(final E bytes) { + byte[] array = bytes.toArrayUnsafe(); + if (array.length != byteLength) { + throw new IllegalArgumentException( + "Byte array is size " + array.length + " but set is size " + byteLength); + } + // Two base cases, size==0 and size==1; + if (root == null) { + // size==0 is easy, just add + root = new Node<>(array, bytes, null); + size++; + return true; + } + if (root.leafObject != null) { + // size==1 first check then if no match make it look like n>1 + if (Arrays.compare(array, root.leafArray) == 0) { + return false; + } + Node oldRoot = root; + root = new Node<>(null, null, new Node[256]); + root.children[oldRoot.leafArray[0] & 0xff] = oldRoot; + } + int level = 0; + Node current = root; + do { + int index = array[level] & 0xff; + Node next = current.children[index]; + if (next == null) { + next = new Node<>(array, bytes, null); + current.children[index] = next; + size++; + return true; + } + if (next.leafObject != null) { + if (Arrays.compare(array, next.leafArray) == 0) { + return false; + } + Node newLeaf = new Node<>(null, null, new Node[256]); + newLeaf.children[next.leafArray[level + 1] & 0xff] = next; + current.children[index] = newLeaf; + next = newLeaf; + } + level++; + + current = next; + + } while (true); + } + + @Override + public void clear() { + root = null; + } +} 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 d046c64778e..9946b6f57a8 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 @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkNotNull; +import org.hyperledger.besu.collections.trie.BytesTrieSet; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.VersionedHash; @@ -41,7 +42,6 @@ import java.math.BigInteger; import java.util.Collection; import java.util.Deque; -import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -80,7 +80,7 @@ public class EVMExecutor { List.of(MaxCodeSizeRule.of(0x6000), PrefixCodeRule.of()); private long initialNonce = 1; private Collection
forceCommitAddresses = List.of(Address.fromHexString("0x03")); - private Set
accessListWarmAddresses = new HashSet<>(); + private Set
accessListWarmAddresses = new BytesTrieSet<>(Address.SIZE); private Multimap accessListWarmStorage = HashMultimap.create(); private MessageCallProcessor messageCallProcessor = null; private ContractCreationProcessor contractCreationProcessor = null; 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 ed711e3f181..64c865dfd41 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 @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkState; import static java.util.Collections.emptySet; +import org.hyperledger.besu.collections.trie.BytesTrieSet; import org.hyperledger.besu.collections.undo.UndoSet; import org.hyperledger.besu.collections.undo.UndoTable; import org.hyperledger.besu.datatypes.Address; @@ -38,7 +39,6 @@ import java.util.ArrayList; import java.util.Deque; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -1707,7 +1707,7 @@ public MessageFrame build() { new TxValues( blockHashLookup, maxStackSize, - UndoSet.of(new HashSet<>()), + UndoSet.of(new BytesTrieSet<>(Address.SIZE)), UndoTable.of(HashBasedTable.create()), originator, gasPrice, @@ -1717,8 +1717,8 @@ public MessageFrame build() { miningBeneficiary, versionedHashes, UndoTable.of(HashBasedTable.create()), - UndoSet.of(new HashSet<>()), - UndoSet.of(new HashSet<>())); + UndoSet.of(new BytesTrieSet<>(Address.SIZE)), + UndoSet.of(new BytesTrieSet<>(Address.SIZE))); updater = worldUpdater; newStatic = isStatic; } else { 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 41cacdbea06..2eb48dd1add 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 @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.evm.worldstate; +import org.hyperledger.besu.collections.trie.BytesTrieSet; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.account.Account; @@ -21,7 +22,6 @@ import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -44,7 +44,8 @@ public abstract class AbstractWorldUpdater> updatedAccounts = new ConcurrentHashMap<>(); /** The Deleted accounts. */ - protected Set
deletedAccounts = Collections.synchronizedSet(new HashSet<>()); + protected Set
deletedAccounts = + Collections.synchronizedSet(new BytesTrieSet<>(Address.SIZE)); /** * Instantiates a new Abstract world updater. diff --git a/evm/src/test/java/org/hyperledger/besu/collections/trie/BytesTrieSetTest.java b/evm/src/test/java/org/hyperledger/besu/collections/trie/BytesTrieSetTest.java new file mode 100644 index 00000000000..dc92cc47d72 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/collections/trie/BytesTrieSetTest.java @@ -0,0 +1,176 @@ +/* + * 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.collections.trie; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Test; + +class BytesTrieSetTest { + + private static final Bytes BYTES_1234 = Bytes.of(1, 2, 3, 4); + private static final Bytes BYTES_4321 = Bytes.of(4, 3, 2, 1); + private static final Bytes BYTES_4567 = Bytes.of(4, 5, 6, 7); + private static final Bytes BYTES_4568 = Bytes.of(4, 5, 6, 8); + private static final Bytes BYTES_4556 = Bytes.of(4, 5, 5, 6); + private static final Bytes BYTES_123 = Bytes.of(1, 2, 3); + + @Test + void testInserts() { + BytesTrieSet trieSet = new BytesTrieSet<>(4); + assertThat(trieSet).isEmpty(); + System.out.println(trieSet); + + assertThat(trieSet.add(BYTES_1234)).isTrue(); + assertThat(trieSet).hasSize(1); + + assertThat(trieSet.add(BYTES_1234)).isFalse(); + assertThat(trieSet).hasSize(1); + + assertThat(trieSet.add(BYTES_4321)).isTrue(); + assertThat(trieSet).hasSize(2); + + assertThat(trieSet.add(BYTES_4567)).isTrue(); + assertThat(trieSet).hasSize(3); + + assertThat(trieSet.add(BYTES_4567)).isFalse(); + assertThat(trieSet).hasSize(3); + + System.out.println(trieSet); + } + + @Test + void testRemoves() { + BytesTrieSet trieSet = new BytesTrieSet<>(4); + + assertThat(trieSet.remove(BYTES_1234)).isFalse(); + + trieSet.add(BYTES_1234); + assertThat(trieSet.remove(BYTES_4321)).isFalse(); + assertThat(trieSet.remove(BYTES_1234)).isTrue(); + assertThat(trieSet).isEmpty(); + + trieSet.add(BYTES_1234); + trieSet.add(BYTES_4321); + assertThat(trieSet.remove(BYTES_4567)).isFalse(); + assertThat(trieSet.remove(BYTES_4568)).isFalse(); + + trieSet.add(BYTES_4567); + trieSet.add(BYTES_4568); + assertThat(trieSet).hasSize(4); + + assertThat(trieSet.remove(BYTES_4556)).isFalse(); + assertThat(trieSet.remove(BYTES_4568)).isTrue(); + assertThat(trieSet.remove(BYTES_4568)).isFalse(); + assertThat(trieSet).hasSize(3); + assertThat(trieSet.remove(BYTES_4567)).isTrue(); + assertThat(trieSet).hasSize(2); + + assertThat(trieSet.remove(BYTES_4321)).isTrue(); + assertThat(trieSet).hasSize(1); + + assertThat(trieSet.remove(BYTES_1234)).isTrue(); + assertThat(trieSet).isEmpty(); + } + + @Test + @SuppressWarnings( + "squid:S5838") // contains and doesNotContains uses iterables, not the contains method + void testContains() { + BytesTrieSet trieSet = new BytesTrieSet<>(4); + + assertThat(trieSet.contains(BYTES_1234)).isFalse(); + + trieSet.add(BYTES_1234); + assertThat(trieSet.contains(BYTES_4321)).isFalse(); + assertThat(trieSet.contains(BYTES_1234)).isTrue(); + assertThat(trieSet).hasSize(1); + + trieSet.add(BYTES_1234); + trieSet.add(BYTES_4321); + assertThat(trieSet.contains(BYTES_4567)).isFalse(); + assertThat(trieSet.contains(BYTES_4568)).isFalse(); + + trieSet.add(BYTES_4567); + trieSet.add(BYTES_4568); + assertThat(trieSet).hasSize(4); + + assertThat(trieSet.contains(BYTES_4556)).isFalse(); + assertThat(trieSet.contains(BYTES_4568)).isTrue(); + trieSet.remove(BYTES_4568); + assertThat(trieSet).hasSize(3); + assertThat(trieSet.contains(BYTES_4567)).isTrue(); + trieSet.remove(BYTES_4567); + assertThat(trieSet).hasSize(2); + assertThat(trieSet.contains(BYTES_4567)).isFalse(); + + assertThat(trieSet.contains(BYTES_4321)).isTrue(); + trieSet.remove(BYTES_4321); + assertThat(trieSet.contains(BYTES_4321)).isFalse(); + assertThat(trieSet).hasSize(1); + + assertThat(trieSet.contains(BYTES_1234)).isTrue(); + trieSet.remove(BYTES_1234); + assertThat(trieSet.contains(BYTES_4321)).isFalse(); + + assertThat(trieSet).isEmpty(); + } + + @Test + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + void checkLengthAdd() { + BytesTrieSet trieSet = new BytesTrieSet<>(4); + assertThatThrownBy(() -> trieSet.add(BYTES_123)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + void checkLengthRemove() { + BytesTrieSet trieSet = new BytesTrieSet<>(4); + assertThatThrownBy(() -> trieSet.remove(BYTES_123)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("4"); + } + + @Test + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + void checkLengthContains() { + BytesTrieSet trieSet = new BytesTrieSet<>(4); + assertThatThrownBy(() -> trieSet.contains(BYTES_123)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("4"); + } + + @Test + @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection", "SuspiciousMethodCalls"}) + void checkWrongClassRemove() { + BytesTrieSet trieSet = new BytesTrieSet<>(4); + assertThatThrownBy(() -> trieSet.remove(this)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Bytes"); + } + + @Test + @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection", "SuspiciousMethodCalls"}) + void checkWrongClassContains() { + BytesTrieSet trieSet = new BytesTrieSet<>(4); + assertThatThrownBy(() -> trieSet.contains(this)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Bytes"); + } +} diff --git a/gradle.properties b/gradle.properties index f277c752a98..e94b9a26b5d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=23.10.1-SNAPSHOT +version=23.10.2-SNAPSHOT org.gradle.welcome=never # Set exports/opens flags required by Google Java Format and ErrorProne plugins. (JEP-396) diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index f79852f2011..8bd7676ee96 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 = 'j6NRklFHlG35Pq/t6t/oJBrT8DbYOyruGq3cJNh4ENw=' + knownHash = 'pSutbB9biIQPQX14VvzzVGqfeT/SivfMh4rqDhPuPOQ=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockTraceResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockTraceResult.java new file mode 100644 index 00000000000..3d66aca55ab --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockTraceResult.java @@ -0,0 +1,88 @@ +/* + * 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.plugin.data; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +public class BlockTraceResult { + final List transactionTraceResults; + + public BlockTraceResult(final List transactionTraceResults) { + this.transactionTraceResults = transactionTraceResults; + } + + public static BlockTraceResult empty() { + return new BlockTraceResult(new ArrayList<>()); + } + + public List transactionTraceResults() { + return transactionTraceResults; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final BlockTraceResult that = (BlockTraceResult) o; + return transactionTraceResults.equals(that.transactionTraceResults()); + } + + @Override + public int hashCode() { + return Objects.hash(transactionTraceResults); + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("BlockTraceResult{transactionTraceResults=["); + + final Iterator iterator = transactionTraceResults.iterator(); + while (iterator.hasNext()) { + builder.append(iterator.next().toString()); + + if (iterator.hasNext()) { + builder.append(","); + } + } + builder.append("]}"); + return builder.toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + List transactionTraceResults = new ArrayList<>(); + + public Builder addTransactionTraceResult(final TransactionTraceResult transactionTraceResult) { + transactionTraceResults.add(transactionTraceResult); + + return this; + } + + public BlockTraceResult build() { + return new BlockTraceResult(transactionTraceResults); + } + } +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionTraceResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionTraceResult.java new file mode 100644 index 00000000000..0136d2503a6 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionTraceResult.java @@ -0,0 +1,92 @@ +/* + * 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.plugin.data; + +import org.hyperledger.besu.datatypes.Hash; + +import java.util.Objects; +import java.util.Optional; + +public class TransactionTraceResult { + public enum Status { + /* the transaction was traced successfully. This might include transactions that have been reverted */ + SUCCESS, + /* there was an internal error while generating the trace */ + ERROR + } + + private final Hash txHash; + private final Status status; + private final String errorMessage; + + private TransactionTraceResult( + final Hash txHash, final Status status, final String errorMessage) { + this.txHash = txHash; + this.status = status; + this.errorMessage = errorMessage; + } + + public static TransactionTraceResult success(final Hash txHash) { + return new TransactionTraceResult(txHash, Status.SUCCESS, null); + } + + public static TransactionTraceResult error(final Hash txHash, final String errorMessage) { + return new TransactionTraceResult(txHash, Status.ERROR, errorMessage); + } + + public Hash getTxHash() { + return txHash; + } + + public Status getStatus() { + return status; + } + + public Optional errorMessage() { + return Optional.ofNullable(errorMessage); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final TransactionTraceResult that = (TransactionTraceResult) o; + return Objects.equals(txHash, that.txHash) + && status == that.status + && Objects.equals(errorMessage, that.errorMessage); + } + + @Override + public int hashCode() { + return Objects.hash(txHash, status, errorMessage); + } + + @Override + public String toString() { + return "TransactionTraceResult{" + + "txHash=" + + txHash + + ", status=" + + status + + ", errorMessage='" + + errorMessage + + '\'' + + '}'; + } +} 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 0b4809544ab..b084d3712c7 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 @@ -17,6 +17,7 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.data.BlockTraceResult; import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; import java.util.function.Consumer; @@ -29,16 +30,18 @@ public interface TraceService extends BesuService { * * @param blockNumber the block number * @param tracer the tracer (OperationTracer) + * @return BlockTraceResult the result of the trace */ - void traceBlock(long blockNumber, BlockAwareOperationTracer tracer); + BlockTraceResult traceBlock(long blockNumber, BlockAwareOperationTracer tracer); /** * Traces a block by hash * * @param hash the block hash * @param tracer the tracer (OperationTracer) + * @return BlockTraceResult the result of the trace */ - void traceBlock(Hash hash, BlockAwareOperationTracer tracer); + BlockTraceResult traceBlock(Hash hash, BlockAwareOperationTracer tracer); /** * Traces range of blocks