Merge branch 'main' into 7311-add-GetReceiptsFromPeerTask

pull/7638/head
Matilda-Clerke 1 month ago committed by GitHub
commit 24d8f999dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 21
      README.md
  2. 1
      acceptance-tests/dsl/build.gradle
  3. 1
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java
  4. 2
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransactionBuilder.java
  5. 1
      acceptance-tests/tests/build.gradle
  6. 3
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java
  7. 1
      besu/build.gradle
  8. 1
      besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java
  9. 1
      besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java
  10. 2
      besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java
  11. 11
      config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java
  12. 1
      enclave/build.gradle
  13. 1
      ethereum/api/build.gradle
  14. 3
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java
  15. 6
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java
  16. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java
  17. 7
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java
  18. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java
  19. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java
  20. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java
  21. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java
  22. 2
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java
  23. 1
      ethereum/core/build.gradle
  24. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java
  25. 14
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java
  26. 20
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java
  27. 17
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java
  28. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java
  29. 8
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java
  30. 12
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java
  31. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java
  32. 3
      ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague.json
  33. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java
  34. 3
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java
  35. 4
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java
  36. 2
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/revert.json
  37. 1
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java
  38. 1
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java
  39. 35
      evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java
  40. 5
      evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java
  41. 0
      gradle/versions.gradle
  42. 2
      platform/build.gradle
  43. 2
      plugin-api/build.gradle
  44. 12
      plugin-api/src/main/java/org/hyperledger/besu/plugin/data/ProcessableBlockHeader.java
  45. 2
      testutil/build.gradle
  46. 290
      testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java
  47. 126
      testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarnessFactory.java

@ -14,15 +14,15 @@ Besu is an Apache 2.0 licensed, MainNet compatible, Ethereum client written in J
* [Besu User Documentation] * [Besu User Documentation]
* [Besu Issues] * [Besu Issues]
* [Besu Wiki](https://wiki.hyperledger.org/display/BESU/Besu) * [Besu Wiki](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/)
* [How to Contribute to Besu](https://wiki.hyperledger.org/display/BESU/How+to+Contribute) * [How to Contribute to Besu](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156850/How+to+Contribute)
* [Besu Roadmap & Planning](https://wiki.hyperledger.org/pages/viewpage.action?pageId=24781786) * [Besu Roadmap & Planning](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154278/Besu+Roadmap+Planning)
## Issues ## Issues
Besu issues are tracked [in the github issues tab][Besu Issues]. Besu issues are tracked [in the github issues tab][Besu Issues].
See our [guidelines](https://wiki.hyperledger.org/display/BESU/Issues) for more details on searching and creating issues. See our [guidelines](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154243/Issues) for more details on searching and creating issues.
If you have any questions, queries or comments, [Besu channel on Discord] is the place to find us. If you have any questions, queries or comments, [Besu channel on Discord] is the place to find us.
@ -34,20 +34,19 @@ To install the Besu binary, follow [these instructions](https://besu.hyperledger
## Besu Developers ## Besu Developers
* [Contributing Guidelines] * [Contributing Guidelines]
* [Coding Conventions](https://wiki.hyperledger.org/display/BESU/Coding+Conventions) * [Coding Conventions](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154259/Coding+Conventions)
* [Command Line Interface (CLI) Style Guide](https://wiki.hyperledger.org/display/BESU/Besu+CLI+Style+Guide) * [Command Line Interface (CLI) Style Guide](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154260/Besu+CLI+Style+Guide)
* [Besu User Documentation] for running and using Besu * [Besu User Documentation] for running and using Besu
### Development ### Development
Instructions for how to get started with developing on the Besu codebase. Please also read the Instructions for how to get started with developing on the Besu codebase. Please also read the
[wiki](https://wiki.hyperledger.org/display/BESU/Pull+Requests) for more details on how to submit a pull request (PR). [wiki](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154251/Pull+Requests) for more details on how to submit a pull request (PR).
* [Checking Out and Building](https://wiki.hyperledger.org/display/BESU/Building+from+source) * [Checking Out and Building](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154264/Building+from+source)
* [Running Developer Builds](https://wiki.hyperledger.org/display/BESU/Building+from+source#running-developer-builds) * [Code Coverage](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154288/Code+coverage)
* [Code Coverage](https://wiki.hyperledger.org/display/BESU/Code+coverage) * [Logging](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154291/Logging) or the [Documentation's Logging section](https://besu.hyperledger.org/public-networks/how-to/monitor/logging)
* [Logging](https://wiki.hyperledger.org/display/BESU/Logging) or the [Documentation's Logging section](https://besu.hyperledger.org/public-networks/how-to/monitor/logging)
## Release Notes ## Release Notes

@ -45,6 +45,5 @@ dependencies {
implementation 'org.web3j:crypto' implementation 'org.web3j:crypto'
implementation 'org.wiremock:wiremock' implementation 'org.wiremock:wiremock'
implementation 'org.testcontainers:testcontainers'
implementation 'org.junit.jupiter:junit-jupiter' implementation 'org.junit.jupiter:junit-jupiter'
} }

@ -58,6 +58,7 @@ public class BlockUtils {
null, null,
null, null,
null, null,
null,
blockHeaderFunctions); blockHeaderFunctions);
} }
} }

@ -14,7 +14,7 @@
*/ */
package org.hyperledger.besu.tests.acceptance.dsl.transaction.account; package org.hyperledger.besu.tests.acceptance.dsl.transaction.account;
import static org.testcontainers.shaded.com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.crypto.SECP256K1; import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithm;

@ -74,7 +74,6 @@ dependencies {
testImplementation 'org.assertj:assertj-core' testImplementation 'org.assertj:assertj-core'
testImplementation 'org.awaitility:awaitility' testImplementation 'org.awaitility:awaitility'
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.testcontainers:testcontainers'
testImplementation 'org.web3j:abi' testImplementation 'org.web3j:abi'
testImplementation 'org.web3j:besu' testImplementation 'org.web3j:besu'
testImplementation 'org.web3j:core' testImplementation 'org.web3j:core'

@ -20,8 +20,11 @@ import java.util.stream.Stream;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
// TODO SLD
@Disabled("TODO SLD - Enable when Prague spec is finalized")
public class ExecutionEnginePragueAcceptanceTest extends AbstractJsonRpcTest { public class ExecutionEnginePragueAcceptanceTest extends AbstractJsonRpcTest {
private static final String GENESIS_FILE = "/jsonrpc/engine/prague/genesis.json"; private static final String GENESIS_FILE = "/jsonrpc/engine/prague/genesis.json";
private static final String TEST_CASE_PATH = "/jsonrpc/engine/prague/test-cases/"; private static final String TEST_CASE_PATH = "/jsonrpc/engine/prague/test-cases/";

@ -104,7 +104,6 @@ dependencies {
testImplementation 'org.awaitility:awaitility' testImplementation 'org.awaitility:awaitility'
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.mockito:mockito-core' testImplementation 'org.mockito:mockito-core'
testImplementation 'org.testcontainers:testcontainers'
testImplementation 'tech.pegasys.discovery:discovery' testImplementation 'tech.pegasys.discovery:discovery'
testImplementation 'com.google.dagger:dagger' testImplementation 'com.google.dagger:dagger'

@ -193,6 +193,7 @@ public abstract class AbstractBftBesuControllerBuilderTest {
null, null,
null, null,
null, null,
null,
getBlockHeaderFunctions()); getBlockHeaderFunctions());
final Block block1 = new Block(header1, BlockBody.empty()); final Block block1 = new Block(header1, BlockBody.empty());

@ -222,6 +222,7 @@ public class CliqueBesuControllerBuilderTest {
null, null,
null, null,
null, null,
null,
new CliqueBlockHeaderFunctions()); new CliqueBlockHeaderFunctions());
final Block block1 = new Block(header1, BlockBody.empty()); final Block block1 = new Block(header1, BlockBody.empty());

@ -219,7 +219,7 @@ public class BesuEventsImplTest {
mock(EthPeer.class), mock(EthPeer.class),
new org.hyperledger.besu.ethereum.core.BlockHeader( new org.hyperledger.besu.ethereum.core.BlockHeader(
null, null, null, null, null, null, null, null, 1, 1, 1, 1, null, null, null, 1, null, null, null, null, null, null, null, null, null, 1, 1, 1, 1, null, null, null, 1, null,
null, null, null, null, null)); null, null, null, null, null, null));
} }
private void clearSyncTarget() { private void clearSyncTarget() {

@ -265,6 +265,17 @@ public class GenesisConfigFile {
"0x0000000000000000000000000000000000000000000000000000000000000000"); "0x0000000000000000000000000000000000000000000000000000000000000000");
} }
/**
* Gets target blob count.
*
* @return the target blob count
*/
public Optional<String> getTargetBlobCount() {
// TODO SLD EIP-7742 not sure if we should use a default value here or enforce any
// "pragueAtGenesis" genesis file (used in devnets) to have this value
return JsonUtil.getValueAsString(genesisRoot, "targetblobcount");
}
/** /**
* Gets coinbase. * Gets coinbase.
* *

@ -24,5 +24,4 @@ dependencies {
integrationTestImplementation 'org.awaitility:awaitility' integrationTestImplementation 'org.awaitility:awaitility'
integrationTestImplementation 'org.junit.jupiter:junit-jupiter-api' integrationTestImplementation 'org.junit.jupiter:junit-jupiter-api'
integrationTestImplementation 'org.mockito:mockito-core' integrationTestImplementation 'org.mockito:mockito-core'
integrationTestImplementation 'org.testcontainers:testcontainers'
} }

@ -121,7 +121,6 @@ dependencies {
integrationTestImplementation 'org.junit.jupiter:junit-jupiter' integrationTestImplementation 'org.junit.jupiter:junit-jupiter'
integrationTestImplementation 'org.mockito:mockito-core' integrationTestImplementation 'org.mockito:mockito-core'
integrationTestImplementation 'org.mockito:mockito-junit-jupiter' integrationTestImplementation 'org.mockito:mockito-junit-jupiter'
integrationTestImplementation 'org.testcontainers:testcontainers'
integrationTestRuntimeOnly 'org.junit.jupiter:junit-jupiter' integrationTestRuntimeOnly 'org.junit.jupiter:junit-jupiter'
} }

@ -38,5 +38,6 @@ public enum JsonRpcResponseKey {
TRANSACTION_ROOT, TRANSACTION_ROOT,
BASEFEE, BASEFEE,
WITHDRAWALS_ROOT, WITHDRAWALS_ROOT,
REQUESTS_HASH REQUESTS_HASH,
TARGET_BLOB_COUNT
} }

@ -63,6 +63,7 @@ import java.util.Optional;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
import org.apache.tuweni.units.bigints.UInt64;
public class JsonRpcResponseUtils { public class JsonRpcResponseUtils {
@ -106,6 +107,10 @@ public class JsonRpcResponseUtils {
values.containsKey(WITHDRAWALS_ROOT) ? hash(values.get(WITHDRAWALS_ROOT)) : null; values.containsKey(WITHDRAWALS_ROOT) ? hash(values.get(WITHDRAWALS_ROOT)) : null;
final Hash requestsHash = final Hash requestsHash =
values.containsKey(REQUESTS_HASH) ? hash(values.get(REQUESTS_HASH)) : null; values.containsKey(REQUESTS_HASH) ? hash(values.get(REQUESTS_HASH)) : null;
final UInt64 targetBlobCount =
values.containsKey(JsonRpcResponseKey.TARGET_BLOB_COUNT)
? UInt64.fromHexString(values.get(JsonRpcResponseKey.TARGET_BLOB_COUNT))
: null;
final List<JsonNode> ommers = new ArrayList<>(); final List<JsonNode> ommers = new ArrayList<>();
final BlockHeader header = final BlockHeader header =
@ -131,6 +136,7 @@ public class JsonRpcResponseUtils {
null, // ToDo 4844: set with the value of excess_blob_gas field null, // ToDo 4844: set with the value of excess_blob_gas field
null, // TODO 4788: set with the value of the parent beacon block root field null, // TODO 4788: set with the value of the parent beacon block root field
requestsHash, requestsHash,
targetBlobCount,
blockHeaderFunctions); blockHeaderFunctions);
return new JsonRpcSuccessResponse( return new JsonRpcSuccessResponse(

@ -279,6 +279,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
: BlobGas.fromHexString(blockParam.getExcessBlobGas()), : BlobGas.fromHexString(blockParam.getExcessBlobGas()),
maybeParentBeaconBlockRoot.orElse(null), maybeParentBeaconBlockRoot.orElse(null),
maybeRequests.map(BodyValidation::requestsHash).orElse(null), maybeRequests.map(BodyValidation::requestsHash).orElse(null),
null, // TODO SLD EIP-7742 wiring in future PR
headerFunctions); headerFunctions);
// ensure the block hash matches the blockParam hash // ensure the block hash matches the blockParam hash

@ -88,6 +88,7 @@ public class BlockResult implements JsonRpcResult {
private final String blobGasUsed; private final String blobGasUsed;
private final String excessBlobGas; private final String excessBlobGas;
private final String parentBeaconBlockRoot; private final String parentBeaconBlockRoot;
private final String targetBlobCount;
public BlockResult( public BlockResult(
final BlockHeader header, final BlockHeader header,
@ -138,6 +139,7 @@ public class BlockResult implements JsonRpcResult {
this.excessBlobGas = header.getExcessBlobGas().map(Quantity::create).orElse(null); this.excessBlobGas = header.getExcessBlobGas().map(Quantity::create).orElse(null);
this.parentBeaconBlockRoot = this.parentBeaconBlockRoot =
header.getParentBeaconBlockRoot().map(Bytes32::toHexString).orElse(null); header.getParentBeaconBlockRoot().map(Bytes32::toHexString).orElse(null);
this.targetBlobCount = header.getTargetBlobCount().map(Quantity::create).orElse(null);
} }
@JsonGetter(value = "number") @JsonGetter(value = "number")
@ -275,4 +277,9 @@ public class BlockResult implements JsonRpcResult {
public String getParentBeaconBlockRoot() { public String getParentBeaconBlockRoot() {
return parentBeaconBlockRoot; return parentBeaconBlockRoot;
} }
@JsonGetter(value = "targetBlobCount")
public String getTargetBlobCount() {
return targetBlobCount;
}
} }

@ -372,6 +372,7 @@ public class EthGasPriceTest {
null, null,
null, null,
null, null,
null,
null), null),
new BlockBody( new BlockBody(
IntStream.range(0, txsNum) IntStream.range(0, txsNum)

@ -207,6 +207,7 @@ public class EthMaxPriorityFeePerGasTest {
null, null,
null, null,
null, null,
null,
null), null),
new BlockBody( new BlockBody(
IntStream.range(0, txsNum) IntStream.range(0, txsNum)

@ -254,6 +254,7 @@ public class EngineExchangeTransitionConfigurationTest {
null, null,
null, null,
null, null,
null,
new BlockHeaderFunctions() { new BlockHeaderFunctions() {
@Override @Override
public Hash hash(final BlockHeader header) { public Hash hash(final BlockHeader header) {

@ -120,6 +120,7 @@ public class BlockchainQueriesLogCacheTest {
null, null,
null, null,
null, null,
null,
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
testHash = fakeHeader.getHash(); testHash = fakeHeader.getHash();
final BlockBody fakeBody = new BlockBody(Collections.emptyList(), Collections.emptyList()); final BlockBody fakeBody = new BlockBody(Collections.emptyList(), Collections.emptyList());

@ -108,6 +108,7 @@ public class TransactionLogBloomCacherTest {
null, null,
null, null,
null, null,
null,
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
testHash = fakeHeader.getHash(); testHash = fakeHeader.getHash();
when(blockchain.getBlockHeader(anyLong())).thenReturn(Optional.of(fakeHeader)); when(blockchain.getBlockHeader(anyLong())).thenReturn(Optional.of(fakeHeader));
@ -283,6 +284,7 @@ public class TransactionLogBloomCacherTest {
null, null,
null, null,
null, null,
null,
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
testHash = fakeHeader.getHash(); testHash = fakeHeader.getHash();
when(blockchain.getBlockHeader(number)).thenReturn(Optional.of(fakeHeader)); when(blockchain.getBlockHeader(number)).thenReturn(Optional.of(fakeHeader));

@ -96,7 +96,6 @@ dependencies {
integrationTestImplementation 'org.assertj:assertj-core' integrationTestImplementation 'org.assertj:assertj-core'
integrationTestImplementation 'org.junit.jupiter:junit-jupiter-api' integrationTestImplementation 'org.junit.jupiter:junit-jupiter-api'
integrationTestImplementation 'org.mockito:mockito-core' integrationTestImplementation 'org.mockito:mockito-core'
integrationTestImplementation 'org.testcontainers:testcontainers'
integrationTestImplementation 'io.tmio:tuweni-bytes' integrationTestImplementation 'io.tmio:tuweni-bytes'
integrationTestRuntimeOnly 'org.junit.jupiter:junit-jupiter' integrationTestRuntimeOnly 'org.junit.jupiter:junit-jupiter'

@ -48,6 +48,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
public final class GenesisState { public final class GenesisState {
@ -218,6 +219,12 @@ public final class GenesisState {
.parentBeaconBlockRoot( .parentBeaconBlockRoot(
(isCancunAtGenesis(genesis) ? parseParentBeaconBlockRoot(genesis) : null)) (isCancunAtGenesis(genesis) ? parseParentBeaconBlockRoot(genesis) : null))
.requestsHash(isPragueAtGenesis(genesis) ? Hash.EMPTY_REQUESTS_HASH : null) .requestsHash(isPragueAtGenesis(genesis) ? Hash.EMPTY_REQUESTS_HASH : null)
.targetBlobCount(
isPragueAtGenesis(genesis)
// TODO SLD EIP-7742 Currently defaulting to null due to dependency on web3j
// BlockHeader in CodeDelegationTransactionAcceptanceTest
? genesis.getTargetBlobCount().map(UInt64::fromHexString).orElse(null)
: null)
.buildBlockHeader(); .buildBlockHeader();
} }

@ -28,6 +28,7 @@ import java.util.function.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
/** A mined Ethereum block header. */ /** A mined Ethereum block header. */
public class BlockHeader extends SealableBlockHeader public class BlockHeader extends SealableBlockHeader
@ -65,6 +66,7 @@ public class BlockHeader extends SealableBlockHeader
final BlobGas excessBlobGas, final BlobGas excessBlobGas,
final Bytes32 parentBeaconBlockRoot, final Bytes32 parentBeaconBlockRoot,
final Hash requestsHash, final Hash requestsHash,
final UInt64 targetBlobCount,
final BlockHeaderFunctions blockHeaderFunctions) { final BlockHeaderFunctions blockHeaderFunctions) {
super( super(
parentHash, parentHash,
@ -86,7 +88,8 @@ public class BlockHeader extends SealableBlockHeader
blobGasUsed, blobGasUsed,
excessBlobGas, excessBlobGas,
parentBeaconBlockRoot, parentBeaconBlockRoot,
requestsHash); requestsHash,
targetBlobCount);
this.nonce = nonce; this.nonce = nonce;
this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this));
this.parsedExtraData = Suppliers.memoize(() -> blockHeaderFunctions.parseExtraData(this)); this.parsedExtraData = Suppliers.memoize(() -> blockHeaderFunctions.parseExtraData(this));
@ -187,6 +190,9 @@ public class BlockHeader extends SealableBlockHeader
if (requestsHash == null) break; if (requestsHash == null) break;
out.writeBytes(requestsHash); out.writeBytes(requestsHash);
if (targetBlobCount == null) break;
out.writeUInt64Scalar(targetBlobCount);
} while (false); } while (false);
out.endList(); out.endList();
} }
@ -219,6 +225,7 @@ public class BlockHeader extends SealableBlockHeader
!input.isEndOfCurrentList() ? BlobGas.of(input.readUInt64Scalar()) : null; !input.isEndOfCurrentList() ? BlobGas.of(input.readUInt64Scalar()) : null;
final Bytes32 parentBeaconBlockRoot = !input.isEndOfCurrentList() ? input.readBytes32() : null; final Bytes32 parentBeaconBlockRoot = !input.isEndOfCurrentList() ? input.readBytes32() : null;
final Hash requestsHash = !input.isEndOfCurrentList() ? Hash.wrap(input.readBytes32()) : null; final Hash requestsHash = !input.isEndOfCurrentList() ? Hash.wrap(input.readBytes32()) : null;
final UInt64 targetBlobCount = !input.isEndOfCurrentList() ? input.readUInt64Scalar() : null;
input.leaveList(); input.leaveList();
return new BlockHeader( return new BlockHeader(
parentHash, parentHash,
@ -242,6 +249,7 @@ public class BlockHeader extends SealableBlockHeader
excessBlobGas, excessBlobGas,
parentBeaconBlockRoot, parentBeaconBlockRoot,
requestsHash, requestsHash,
targetBlobCount,
blockHeaderFunctions); blockHeaderFunctions);
} }
@ -295,6 +303,9 @@ public class BlockHeader extends SealableBlockHeader
if (requestsHash != null) { if (requestsHash != null) {
sb.append("requestsHash=").append(requestsHash); sb.append("requestsHash=").append(requestsHash);
} }
if (targetBlobCount != null) {
sb.append("targetBlobCount=").append(targetBlobCount);
}
return sb.append("}").toString(); return sb.append("}").toString();
} }
@ -329,6 +340,7 @@ public class BlockHeader extends SealableBlockHeader
.getRequestsHash() .getRequestsHash()
.map(h -> Hash.fromHexString(h.toHexString())) .map(h -> Hash.fromHexString(h.toHexString()))
.orElse(null), .orElse(null),
pluginBlockHeader.getTargetBlobCount().orElse(null),
blockHeaderFunctions); blockHeaderFunctions);
} }

@ -30,6 +30,7 @@ import java.util.OptionalLong;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
/** A utility class for building block headers. */ /** A utility class for building block headers. */
public class BlockHeaderBuilder { public class BlockHeaderBuilder {
@ -76,6 +77,7 @@ public class BlockHeaderBuilder {
private Long blobGasUsed = null; private Long blobGasUsed = null;
private BlobGas excessBlobGas = null; private BlobGas excessBlobGas = null;
private Bytes32 parentBeaconBlockRoot = null; private Bytes32 parentBeaconBlockRoot = null;
private UInt64 targetBlobCount = null;
public static BlockHeaderBuilder create() { public static BlockHeaderBuilder create() {
return new BlockHeaderBuilder(); return new BlockHeaderBuilder();
@ -124,7 +126,8 @@ public class BlockHeaderBuilder {
.blobGasUsed(header.getBlobGasUsed().orElse(null)) .blobGasUsed(header.getBlobGasUsed().orElse(null))
.excessBlobGas(header.getExcessBlobGas().orElse(null)) .excessBlobGas(header.getExcessBlobGas().orElse(null))
.parentBeaconBlockRoot(header.getParentBeaconBlockRoot().orElse(null)) .parentBeaconBlockRoot(header.getParentBeaconBlockRoot().orElse(null))
.requestsHash(header.getRequestsHash().orElse(null)); .requestsHash(header.getRequestsHash().orElse(null))
.targetBlobCount(header.getTargetBlobCount().orElse(null));
} }
public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilder) { public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilder) {
@ -149,6 +152,7 @@ public class BlockHeaderBuilder {
.excessBlobGas(fromBuilder.excessBlobGas) .excessBlobGas(fromBuilder.excessBlobGas)
.parentBeaconBlockRoot(fromBuilder.parentBeaconBlockRoot) .parentBeaconBlockRoot(fromBuilder.parentBeaconBlockRoot)
.requestsHash(fromBuilder.requestsHash) .requestsHash(fromBuilder.requestsHash)
.targetBlobCount(fromBuilder.targetBlobCount)
.blockHeaderFunctions(fromBuilder.blockHeaderFunctions); .blockHeaderFunctions(fromBuilder.blockHeaderFunctions);
toBuilder.nonce = fromBuilder.nonce; toBuilder.nonce = fromBuilder.nonce;
return toBuilder; return toBuilder;
@ -179,6 +183,7 @@ public class BlockHeaderBuilder {
excessBlobGas, excessBlobGas,
parentBeaconBlockRoot, parentBeaconBlockRoot,
requestsHash, requestsHash,
targetBlobCount,
blockHeaderFunctions); blockHeaderFunctions);
} }
@ -194,7 +199,8 @@ public class BlockHeaderBuilder {
timestamp, timestamp,
baseFee, baseFee,
mixHashOrPrevRandao, mixHashOrPrevRandao,
parentBeaconBlockRoot); parentBeaconBlockRoot,
targetBlobCount);
} }
public SealableBlockHeader buildSealableBlockHeader() { public SealableBlockHeader buildSealableBlockHeader() {
@ -220,7 +226,8 @@ public class BlockHeaderBuilder {
blobGasUsed, blobGasUsed,
excessBlobGas, excessBlobGas,
parentBeaconBlockRoot, parentBeaconBlockRoot,
requestsHash); requestsHash,
targetBlobCount);
} }
private void validateBlockHeader() { private void validateBlockHeader() {
@ -260,6 +267,7 @@ public class BlockHeaderBuilder {
baseFee(processableBlockHeader.getBaseFee().orElse(null)); baseFee(processableBlockHeader.getBaseFee().orElse(null));
processableBlockHeader.getPrevRandao().ifPresent(this::prevRandao); processableBlockHeader.getPrevRandao().ifPresent(this::prevRandao);
processableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot); processableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot);
processableBlockHeader.getTargetBlobCount().ifPresent(this::targetBlobCount);
return this; return this;
} }
@ -285,6 +293,7 @@ public class BlockHeaderBuilder {
sealableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas); sealableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas);
sealableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot); sealableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot);
requestsHash(sealableBlockHeader.getRequestsHash().orElse(null)); requestsHash(sealableBlockHeader.getRequestsHash().orElse(null));
sealableBlockHeader.getTargetBlobCount().ifPresent(this::targetBlobCount);
return this; return this;
} }
@ -418,4 +427,9 @@ public class BlockHeaderBuilder {
this.parentBeaconBlockRoot = parentBeaconBlockRoot; this.parentBeaconBlockRoot = parentBeaconBlockRoot;
return this; return this;
} }
public BlockHeaderBuilder targetBlobCount(final UInt64 targetBlobCount) {
this.targetBlobCount = targetBlobCount;
return this;
}
} }

@ -23,6 +23,7 @@ import java.util.Optional;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
/** A block header capable of being processed. */ /** A block header capable of being processed. */
public class ProcessableBlockHeader public class ProcessableBlockHeader
@ -46,6 +47,8 @@ public class ProcessableBlockHeader
protected final Bytes32 mixHashOrPrevRandao; protected final Bytes32 mixHashOrPrevRandao;
// parentBeaconBlockRoot is included for Cancun // parentBeaconBlockRoot is included for Cancun
protected final Bytes32 parentBeaconBlockRoot; protected final Bytes32 parentBeaconBlockRoot;
// TODO SLD Quantity or UInt64Value<UInt64> instead?
protected final UInt64 targetBlobCount;
protected ProcessableBlockHeader( protected ProcessableBlockHeader(
final Hash parentHash, final Hash parentHash,
@ -56,7 +59,8 @@ public class ProcessableBlockHeader
final long timestamp, final long timestamp,
final Wei baseFee, final Wei baseFee,
final Bytes32 mixHashOrPrevRandao, final Bytes32 mixHashOrPrevRandao,
final Bytes32 parentBeaconBlockRoot) { final Bytes32 parentBeaconBlockRoot,
final UInt64 targetBlobCount) {
this.parentHash = parentHash; this.parentHash = parentHash;
this.coinbase = coinbase; this.coinbase = coinbase;
this.difficulty = difficulty; this.difficulty = difficulty;
@ -66,6 +70,7 @@ public class ProcessableBlockHeader
this.baseFee = baseFee; this.baseFee = baseFee;
this.mixHashOrPrevRandao = mixHashOrPrevRandao; this.mixHashOrPrevRandao = mixHashOrPrevRandao;
this.parentBeaconBlockRoot = parentBeaconBlockRoot; this.parentBeaconBlockRoot = parentBeaconBlockRoot;
this.targetBlobCount = targetBlobCount;
} }
/** /**
@ -178,6 +183,16 @@ public class ProcessableBlockHeader
return Optional.ofNullable(parentBeaconBlockRoot); return Optional.ofNullable(parentBeaconBlockRoot);
} }
/**
* Returns the target blob count if available.
*
* @return the target blob count if available.
*/
@Override
public Optional<UInt64> getTargetBlobCount() {
return Optional.ofNullable(targetBlobCount);
}
public String toLogString() { public String toLogString() {
return getNumber() + " (time: " + getTimestamp() + ")"; return getNumber() + " (time: " + getTimestamp() + ")";
} }

@ -24,6 +24,7 @@ import java.util.Optional;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
/** A block header capable of being sealed. */ /** A block header capable of being sealed. */
public class SealableBlockHeader extends ProcessableBlockHeader { public class SealableBlockHeader extends ProcessableBlockHeader {
@ -69,7 +70,8 @@ public class SealableBlockHeader extends ProcessableBlockHeader {
final Long blobGasUsed, final Long blobGasUsed,
final BlobGas excessBlobGas, final BlobGas excessBlobGas,
final Bytes32 parentBeaconBlockRoot, final Bytes32 parentBeaconBlockRoot,
final Hash requestsHash) { final Hash requestsHash,
final UInt64 targetBlobCount) {
super( super(
parentHash, parentHash,
coinbase, coinbase,
@ -79,7 +81,8 @@ public class SealableBlockHeader extends ProcessableBlockHeader {
timestamp, timestamp,
baseFee, baseFee,
mixHashOrPrevRandao, mixHashOrPrevRandao,
parentBeaconBlockRoot); parentBeaconBlockRoot,
targetBlobCount);
this.ommersHash = ommersHash; this.ommersHash = ommersHash;
this.stateRoot = stateRoot; this.stateRoot = stateRoot;
this.transactionsRoot = transactionsRoot; this.transactionsRoot = transactionsRoot;

@ -25,6 +25,7 @@ import java.util.Optional;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
public class BlockHeaderTestFixture { public class BlockHeaderTestFixture {
@ -55,6 +56,7 @@ public class BlockHeaderTestFixture {
private Optional<BlobGas> excessBlobGas = Optional.empty(); private Optional<BlobGas> excessBlobGas = Optional.empty();
private Optional<Long> blobGasUsed = Optional.empty(); private Optional<Long> blobGasUsed = Optional.empty();
private Optional<Bytes32> parentBeaconBlockRoot = Optional.empty(); private Optional<Bytes32> parentBeaconBlockRoot = Optional.empty();
private Optional<UInt64> targetBlobCount = Optional.empty();
public BlockHeader buildHeader() { public BlockHeader buildHeader() {
final BlockHeaderBuilder builder = BlockHeaderBuilder.create(); final BlockHeaderBuilder builder = BlockHeaderBuilder.create();
@ -80,6 +82,7 @@ public class BlockHeaderTestFixture {
blobGasUsed.ifPresent(builder::blobGasUsed); blobGasUsed.ifPresent(builder::blobGasUsed);
requestsHash.ifPresent(builder::requestsHash); requestsHash.ifPresent(builder::requestsHash);
parentBeaconBlockRoot.ifPresent(builder::parentBeaconBlockRoot); parentBeaconBlockRoot.ifPresent(builder::parentBeaconBlockRoot);
targetBlobCount.ifPresent(builder::targetBlobCount);
builder.blockHeaderFunctions(blockHeaderFunctions); builder.blockHeaderFunctions(blockHeaderFunctions);
return builder.buildBlockHeader(); return builder.buildBlockHeader();
@ -201,4 +204,9 @@ public class BlockHeaderTestFixture {
this.parentBeaconBlockRoot = parentBeaconBlockRoot; this.parentBeaconBlockRoot = parentBeaconBlockRoot;
return this; return this;
} }
public BlockHeaderTestFixture targetBlobCount(final UInt64 targetBlobCount) {
this.targetBlobCount = Optional.of(targetBlobCount);
return this;
}
} }

@ -31,6 +31,7 @@ import java.util.stream.Stream;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
import org.apache.tuweni.units.bigints.UInt64;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext;
@ -287,10 +288,6 @@ final class GenesisStateTest {
GenesisStateTest.class.getResource("genesis_prague.json"), GenesisStateTest.class.getResource("genesis_prague.json"),
ProtocolScheduleFixture.MAINNET); ProtocolScheduleFixture.MAINNET);
final BlockHeader header = genesisState.getBlock().getHeader(); final BlockHeader header = genesisState.getBlock().getHeader();
assertThat(header.getHash())
.isEqualTo(
Hash.fromHexString(
"0x554807b22674e6d335f734485993857bbad7a9543affb0663a10c14d78135ec7"));
assertThat(header.getGasLimit()).isEqualTo(0x2fefd8); assertThat(header.getGasLimit()).isEqualTo(0x2fefd8);
assertThat(header.getGasUsed()).isZero(); assertThat(header.getGasUsed()).isZero();
assertThat(header.getNumber()).isZero(); assertThat(header.getNumber()).isZero();
@ -331,6 +328,13 @@ final class GenesisStateTest {
.isEqualTo( .isEqualTo(
Hash.fromHexString( Hash.fromHexString(
"0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f")); "0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f"));
assertThat(header.getTargetBlobCount().isPresent()).isTrue();
assertThat(header.getTargetBlobCount().get()).isEqualTo(UInt64.ONE);
assertThat(header.getHash())
.isEqualTo(
Hash.fromHexString(
"0xdbc64edecb3a432e48cbd270b4a248ffc611b5f3dd666c8a10d546672cae17bd"));
} }
@Test @Test

@ -99,6 +99,7 @@ class LogRollingTests {
null, null,
null, null,
null, null,
null,
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
private static final BlockHeader headerTwo = private static final BlockHeader headerTwo =
new BlockHeader( new BlockHeader(
@ -123,6 +124,7 @@ class LogRollingTests {
null, null,
null, null,
null, null,
null,
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
@BeforeEach @BeforeEach

@ -4073,5 +4073,6 @@
"number": "0x0", "number": "0x0",
"gasUsed": "0x0", "gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"baseFeePerGas": "0x3b9aca00" "baseFeePerGas": "0x3b9aca00",
"targetBlobCount": "0x1"
} }

@ -398,6 +398,7 @@ public class MessageWrapperTest {
null, null,
null, null,
null, null,
null,
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
} }
} }

@ -61,6 +61,7 @@ public class ChainForTestCreator {
null, null,
null, null,
null, null,
null,
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
} }
@ -89,6 +90,7 @@ public class ChainForTestCreator {
blockHeader.getExcessBlobGas().orElse(null), blockHeader.getExcessBlobGas().orElse(null),
blockHeader.getParentBeaconBlockRoot().orElse(null), blockHeader.getParentBeaconBlockRoot().orElse(null),
blockHeader.getRequestsHash().orElse(null), blockHeader.getRequestsHash().orElse(null),
blockHeader.getTargetBlobCount().orElse(null),
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
} }
@ -139,6 +141,7 @@ public class ChainForTestCreator {
null, null,
null, null,
null, null,
null,
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
} }
} }

@ -529,9 +529,7 @@ public class EvmToolCommand implements Runnable {
messageFrame messageFrame
.getExceptionalHaltReason() .getExceptionalHaltReason()
.ifPresent(haltReason -> out.println(haltReason)); .ifPresent(haltReason -> out.println(haltReason));
messageFrame messageFrame.getRevertReason().ifPresent(bytes -> out.println(bytes.toHexString()));
.getRevertReason()
.ifPresent(bytes -> out.println(new String(bytes.toArrayUnsafe(), UTF_8)));
} }
} }
} }

@ -12,7 +12,7 @@
{"pc":7,"op":82,"gas":"0x2540be3fa","gasCost":"0x6","memSize":0,"stack":["0x4e6f7065","0x0"],"depth":1,"refund":0,"opName":"MSTORE"}, {"pc":7,"op":82,"gas":"0x2540be3fa","gasCost":"0x6","memSize":0,"stack":["0x4e6f7065","0x0"],"depth":1,"refund":0,"opName":"MSTORE"},
{"pc":8,"op":96,"gas":"0x2540be3f4","gasCost":"0x3","memSize":32,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"}, {"pc":8,"op":96,"gas":"0x2540be3f4","gasCost":"0x3","memSize":32,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":10,"op":96,"gas":"0x2540be3f1","gasCost":"0x3","memSize":32,"stack":["0x4"],"depth":1,"refund":0,"opName":"PUSH1"}, {"pc":10,"op":96,"gas":"0x2540be3f1","gasCost":"0x3","memSize":32,"stack":["0x4"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":12,"op":253,"gas":"0x2540be3ee","gasCost":"0x0","memSize":32,"stack":["0x4","0x1c"],"depth":1,"refund":0,"opName":"REVERT","error":"Nope"}, {"pc":12,"op":253,"gas":"0x2540be3ee","gasCost":"0x0","memSize":32,"stack":["0x4","0x1c"],"depth":1,"refund":0,"opName":"REVERT","error":"0x4e6f7065"},
{"stateRoot":"0x405bbd98da2aca6dff77f79e0b270270c48d6a3e07b76db675b20e454b50bbcb","output":"0x4e6f7065","gasUsed":"0x12","pass":true,"fork":"Cancun"} {"stateRoot":"0x405bbd98da2aca6dff77f79e0b270270c48d6a3e07b76db675b20e454b50bbcb","output":"0x4e6f7065","gasUsed":"0x12","pass":true,"fork":"Cancun"}
] ]
} }

@ -195,6 +195,7 @@ public class BlockchainReferenceTestCaseSpec {
excessBlobGas != null ? BlobGas.fromHexString(excessBlobGas) : null, excessBlobGas != null ? BlobGas.fromHexString(excessBlobGas) : null,
parentBeaconBlockRoot != null ? Bytes32.fromHexString(parentBeaconBlockRoot) : null, parentBeaconBlockRoot != null ? Bytes32.fromHexString(parentBeaconBlockRoot) : null,
requestsHash != null ? Hash.fromHexString(requestsHash) : null, requestsHash != null ? Hash.fromHexString(requestsHash) : null,
null, // TODO SLD EIP-7742 use targetBlobCount when reference tests are updated
new BlockHeaderFunctions() { new BlockHeaderFunctions() {
@Override @Override
public Hash hash(final BlockHeader header) { public Hash hash(final BlockHeader header) {

@ -146,6 +146,7 @@ public class ReferenceTestEnv extends BlockHeader {
currentExcessBlobGas == null ? null : BlobGas.of(Long.decode(currentExcessBlobGas)), currentExcessBlobGas == null ? null : BlobGas.of(Long.decode(currentExcessBlobGas)),
beaconRoot == null ? null : Bytes32.fromHexString(beaconRoot), beaconRoot == null ? null : Bytes32.fromHexString(beaconRoot),
null, // requestsHash null, // requestsHash
null, // TODO SLD EIP-7742 use targetBlobCount when reference tests are updated
new MainnetBlockHeaderFunctions()); new MainnetBlockHeaderFunctions());
this.parentDifficulty = parentDifficulty; this.parentDifficulty = parentDifficulty;
this.parentBaseFee = parentBaseFee; this.parentBaseFee = parentBaseFee;

@ -14,8 +14,6 @@
*/ */
package org.hyperledger.besu.evm.tracing; package org.hyperledger.besu.evm.tracing;
import static com.google.common.base.Strings.padStart;
import org.hyperledger.besu.evm.code.OpcodeInfo; import org.hyperledger.besu.evm.code.OpcodeInfo;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
@ -224,7 +222,7 @@ public class StandardJsonTracer implements OperationTracer {
.append("\""); .append("\"");
} else if (messageFrame.getRevertReason().isPresent()) { } else if (messageFrame.getRevertReason().isPresent()) {
sb.append(",\"error\":\"") sb.append(",\"error\":\"")
.append(quoteEscape(messageFrame.getRevertReason().orElse(Bytes.EMPTY))) .append(messageFrame.getRevertReason().get().toHexString())
.append("\""); .append("\"");
} }
@ -232,37 +230,6 @@ public class StandardJsonTracer implements OperationTracer {
out.println(sb); out.println(sb);
} }
private static String quoteEscape(final Bytes bytes) {
final StringBuilder result = new StringBuilder(bytes.size());
for (final byte b : bytes.toArrayUnsafe()) {
final int c = Byte.toUnsignedInt(b);
// list from RFC-4627 section 2
if (c == '"') {
result.append("\\\"");
} else if (c == '\\') {
result.append("\\\\");
} else if (c == '/') {
result.append("\\/");
} else if (c == '\b') {
result.append("\\b");
} else if (c == '\f') {
result.append("\\f");
} else if (c == '\n') {
result.append("\\n");
} else if (c == '\r') {
result.append("\\r");
} else if (c == '\t') {
result.append("\\t");
} else if (c <= 0x1F) {
result.append("\\u");
result.append(padStart(Integer.toHexString(c), 4, '0'));
} else {
result.append((char) b);
}
}
return result.toString();
}
@Override @Override
public void tracePrecompileCall( public void tracePrecompileCall(
final MessageFrame frame, final long gasRequirement, final Bytes output) { final MessageFrame frame, final long gasRequirement, final Bytes output) {

@ -32,7 +32,6 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.io.PrintStream; import java.io.PrintStream;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Deque; import java.util.Deque;
import java.util.List; import java.util.List;
@ -208,9 +207,7 @@ public class EvmToyCommand implements Runnable {
out.println(messageFrame.getExceptionalHaltReason().get()); out.println(messageFrame.getExceptionalHaltReason().get());
} }
if (messageFrame.getRevertReason().isPresent()) { if (messageFrame.getRevertReason().isPresent()) {
out.println( out.println(messageFrame.getRevertReason().get().toHexString());
new String(
messageFrame.getRevertReason().get().toArrayUnsafe(), StandardCharsets.UTF_8));
} }
} }
if (messageFrameStack.isEmpty()) { if (messageFrameStack.isEmpty()) {

@ -158,8 +158,6 @@ dependencies {
api 'org.springframework.security:spring-security-crypto:6.3.3' api 'org.springframework.security:spring-security-crypto:6.3.3'
api 'org.testcontainers:testcontainers:1.20.2'
api 'org.wiremock:wiremock:3.9.1' api 'org.wiremock:wiremock:3.9.1'
api 'org.web3j:abi:4.12.2' api 'org.web3j:abi:4.12.2'

@ -71,7 +71,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) { tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought" description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files files = sourceSets.main.allJava.files
knownHash = 'G3cpM0HGYp4G1u6dN2CRZiEEsgce6jy9rkIlT1blUb4=' knownHash = 'uNQzVjMa7m1fw3d10NuVOjmzGxmCkgZd88yGFgP3qoY='
} }
check.dependsOn('checkAPIChanges') check.dependsOn('checkAPIChanges')

@ -22,6 +22,7 @@ import org.hyperledger.besu.plugin.Unstable;
import java.util.Optional; import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
/** /**
* The minimum set of data for a BlockHeader, as defined in the <a href= * The minimum set of data for a BlockHeader, as defined in the <a href=
@ -105,4 +106,15 @@ public interface ProcessableBlockHeader {
*/ */
@Unstable @Unstable
Optional<? extends Bytes32> getParentBeaconBlockRoot(); Optional<? extends Bytes32> getParentBeaconBlockRoot();
/**
* The target_blob_count of this header.
*
* @return The target blob count of this header.
*/
@Unstable
// TODO SLD should be Quantity or new subclass of Quantity?
default Optional<UInt64> getTargetBlobCount() {
return Optional.empty();
}
} }

@ -49,6 +49,4 @@ dependencies {
implementation 'org.assertj:assertj-core' implementation 'org.assertj:assertj-core'
implementation 'org.mockito:mockito-core' implementation 'org.mockito:mockito-core'
implementation 'org.web3j:core' implementation 'org.web3j:core'
implementation 'org.testcontainers:testcontainers'
} }

@ -1,290 +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.enclave.testutil;
import static com.google.common.io.Files.readLines;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import com.google.common.base.Charsets;
import io.vertx.core.json.JsonArray;
import org.assertj.core.util.Files;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.MountableFile;
/** The Tessera test harness. */
public class TesseraTestHarness implements EnclaveTestHarness {
private static final Logger LOG = LoggerFactory.getLogger(TesseraTestHarness.class);
private final EnclaveConfiguration enclaveConfiguration;
private boolean isRunning;
private URI nodeURI;
private URI q2TUri;
private URI thirdPartyUri;
/** The constant TESSERA_VERSION. */
public static final String TESSERA_VERSION = "22.10.0";
private final int thirdPartyPort = 9081;
private final int q2TPort = 9082;
/** The constant p2pPort. */
public static final int p2pPort = 9001;
private final String containerKeyDir = "/tmp/keys/";
@SuppressWarnings("rawtypes")
private GenericContainer tesseraContainer;
private final Optional<Network> containerNetwork;
private final String containerName;
/**
* Instantiates a new Tessera test harness.
*
* @param enclaveConfiguration the enclave configuration
* @param containerNetwork the container network
*/
protected TesseraTestHarness(
final EnclaveConfiguration enclaveConfiguration, final Optional<Network> containerNetwork) {
this.enclaveConfiguration = enclaveConfiguration;
this.containerNetwork = containerNetwork;
this.containerName = enclaveConfiguration.getName();
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
}
@Override
public void start() {
if (!isRunning) {
final File tempFolder = Files.newTemporaryFolder();
LOG.info("Temporary directory: " + tempFolder.getAbsolutePath());
final String configFile = createConfigFile(enclaveConfiguration.getName());
tesseraContainer = buildTesseraContainer(configFile);
containerNetwork.ifPresent(network -> addNetwork(tesseraContainer, containerName, network));
tesseraContainer.start();
isRunning = true;
try {
final String host = "http://" + tesseraContainer.getHost();
nodeURI = new URI(host + ":" + tesseraContainer.getMappedPort(p2pPort));
LOG.info("Tessera node URI: {}", nodeURI);
q2TUri = new URI(host + ':' + tesseraContainer.getMappedPort(q2TPort));
LOG.info("Tessera client URI: {}", q2TUri);
thirdPartyUri = new URI(host + ':' + tesseraContainer.getMappedPort(thirdPartyPort));
LOG.info("Tessera thirdParty URI: {}", thirdPartyUri);
} catch (final URISyntaxException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void stop() {
if (isRunning) {
tesseraContainer.stop();
isRunning = false;
}
}
@Override
public void close() {
stop();
}
@Override
public List<Path> getPublicKeyPaths() {
return Arrays.asList(enclaveConfiguration.getPublicKeys());
}
@Override
public String getDefaultPublicKey() {
return readFile(enclaveConfiguration.getPublicKeys()[0]);
}
@Override
public List<String> getPublicKeys() {
return Arrays.stream(enclaveConfiguration.getPublicKeys())
.map(TesseraTestHarness::readFile)
.collect(Collectors.toList());
}
private static String readFile(final Path path) {
try {
return readLines(path.toFile(), Charsets.UTF_8).get(0);
} catch (final IOException e) {
e.printStackTrace();
return "";
}
}
@Override
public URI clientUrl() {
return q2TUri;
}
@Override
public URI nodeUrl() {
return nodeURI;
}
@Override
public void addOtherNode(final URI otherNode) {
enclaveConfiguration.addOtherNode(otherNode.toString());
}
@Override
public EnclaveType getEnclaveType() {
return EnclaveType.TESSERA;
}
private String createConfigFile(final String nodeName) {
// create a config file
// @formatter:off
String confString =
"{\n"
+ " \"mode\" : \"orion\",\n"
+ enclaveConfiguration.getEnclaveEncryptorType().toTesseraEncryptorConfigJSON()
+ " \"useWhiteList\": false,\n"
+ " \"jdbc\": {\n"
+ " \"username\": \"sa\",\n"
+ " \"password\": \"\",\n"
+ " \"url\": \"jdbc:h2:/tmp/db;MODE=Oracle;TRACE_LEVEL_SYSTEM_OUT=0\",\n"
+ " \"autoCreateTables\": true\n"
+ " },\n"
+ " \"serverConfigs\":[\n"
+ " {\n"
+ " \"app\":\"ThirdParty\",\n"
+ " \"enabled\": true,\n"
+ " \"serverAddress\": \"http://"
+ nodeName
+ ":"
+ thirdPartyPort
+ "\",\n"
+ " \"cors\" : {\n"
+ " \"allowedMethods\" : [\"GET\", \"OPTIONS\"],\n"
+ " \"allowedOrigins\" : [\"*\"]\n"
+ " },\n"
+ " \"communicationType\" : \"REST\"\n"
+ " },\n"
+ " {\n"
+ " \"app\":\"Q2T\",\n"
+ " \"enabled\": true,\n"
+ " \"serverAddress\":\"http://"
+ nodeName
+ ":"
+ q2TPort
+ "\",\n"
+ " \"communicationType\" : \"REST\"\n"
+ " },\n"
+ " {\n"
+ " \"app\":\"P2P\",\n"
+ " \"enabled\": true,\n"
+ " \"serverAddress\":\"http://"
+ nodeName
+ ":"
+ p2pPort
+ "\",\n"
+ " \"communicationType\" : \"REST\"\n"
+ " }\n"
+ " ],\n"
+ " \"keys\": {\n"
+ " \"passwords\": [],\n"
+ " \"keyData\": "
+ buildKeyConfig()
+ "\n"
+ " },\n"
+ " \"alwaysSendTo\": []";
if (enclaveConfiguration.getOtherNodes().size() != 0) {
confString +=
",\n"
+ " \"peer\": [\n"
+ " {\n"
+ " \"url\": \""
+ enclaveConfiguration.getOtherNodes().get(0)
+ "\"\n"
+ " }\n"
+ " ]";
} else {
confString += ",\n" + " \"peer\": []";
}
confString += "\n}";
final File configFile = Files.newTemporaryFile();
try {
final FileWriter fw = new FileWriter(configFile, StandardCharsets.UTF_8);
fw.write(confString);
fw.close();
} catch (final IOException e) {
throw new RuntimeException(e);
}
return configFile.getAbsolutePath();
}
private String buildKeyConfig() {
final JsonArray keyArray = new JsonArray();
final List<Path> pubKeysPaths = Arrays.asList(enclaveConfiguration.getPublicKeys());
final List<Path> privKeyPaths = Arrays.asList(enclaveConfiguration.getPrivateKeys());
for (int count = 0; count < pubKeysPaths.size(); count++) {
final HashMap<String, String> stringStringHashMap = new HashMap<>();
stringStringHashMap.put(
"publicKeyPath", containerKeyDir + pubKeysPaths.get(count).getFileName());
stringStringHashMap.put(
"privateKeyPath", containerKeyDir + privKeyPaths.get(count).getFileName());
keyArray.add(stringStringHashMap);
}
return keyArray.toString();
}
@SuppressWarnings("rawtypes")
private GenericContainer buildTesseraContainer(final String configFilePath) {
final String containerConfigFilePath = "/tmp/config.json";
final String keyDir = enclaveConfiguration.getTempDir().toString();
return new GenericContainer<>("quorumengineering/tessera:" + TESSERA_VERSION)
.withCopyFileToContainer(MountableFile.forHostPath(configFilePath), containerConfigFilePath)
.withFileSystemBind(keyDir, containerKeyDir)
.withCommand("--configfile " + containerConfigFilePath)
.withExposedPorts(p2pPort, q2TPort, thirdPartyPort)
.waitingFor(Wait.forHttp("/upcheck").withMethod("GET").forStatusCode(200));
}
@SuppressWarnings("rawtypes")
private void addNetwork(
final GenericContainer container, final String containerName, final Network network) {
container.withNetwork(network).withNetworkAliases(containerName);
}
}

@ -1,126 +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.enclave.testutil;
import static org.apache.tuweni.io.file.Files.copyResource;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nonnull;
import org.testcontainers.containers.Network;
/** The Tessera test harness factory. */
public class TesseraTestHarnessFactory {
private static final String storage = "memory";
/** Default constructor */
private TesseraTestHarnessFactory() {}
/**
* Create tessera test harness.
*
* @param name the name
* @param tempDir the temp dir
* @param enclaveConfig the enclave config
* @param containerNetwork the container network
* @return the tessera test harness
*/
public static TesseraTestHarness create(
final String name,
final Path tempDir,
final EnclaveKeyConfiguration enclaveConfig,
final Optional<Network> containerNetwork) {
return create(
name,
tempDir,
enclaveConfig.getPubKeyPaths(),
enclaveConfig.getPrivKeyPaths(),
enclaveConfig.getEnclaveEncryptorType(),
Collections.emptyList(),
containerNetwork);
}
/**
* Create tessera test harness.
*
* @param name the name
* @param tempDir the temp dir
* @param pubKeyPaths the pub key paths
* @param privKeyPaths the priv key paths
* @param enclaveEncryptorType the enclave encryptor type
* @param othernodes the othernodes
* @param containerNetwork the container network
* @return the tessera test harness
*/
public static TesseraTestHarness create(
final String name,
final Path tempDir,
final String[] pubKeyPaths,
final String[] privKeyPaths,
final EnclaveEncryptorType enclaveEncryptorType,
final List<String> othernodes,
final Optional<Network> containerNetwork) {
final Path[] pubKeys = stringArrayToPathArray(tempDir, pubKeyPaths);
final Path[] privKeys = stringArrayToPathArray(tempDir, privKeyPaths);
return create(
name, tempDir, pubKeys, privKeys, enclaveEncryptorType, othernodes, containerNetwork);
}
/**
* Create tessera test harness.
*
* @param name the name
* @param tempDir the temp dir
* @param key1pubs the key 1 pubs
* @param key1keys the key 1 keys
* @param enclaveEncryptorType the enclave encryptor type
* @param othernodes the othernodes
* @param containerNetwork the container network
* @return the tessera test harness
*/
public static TesseraTestHarness create(
final String name,
final Path tempDir,
final Path[] key1pubs,
final Path[] key1keys,
final EnclaveEncryptorType enclaveEncryptorType,
final List<String> othernodes,
final Optional<Network> containerNetwork) {
return new TesseraTestHarness(
new EnclaveConfiguration(
name, key1pubs, key1keys, enclaveEncryptorType, tempDir, othernodes, false, storage),
containerNetwork);
}
@Nonnull
private static Path[] stringArrayToPathArray(final Path tempDir, final String[] privKeyPaths) {
return Arrays.stream(privKeyPaths)
.map(
(pk) -> {
try {
return copyResource(pk, tempDir.resolve(pk));
} catch (final IOException e) {
throw new RuntimeException(e);
}
})
.toArray(Path[]::new);
}
}
Loading…
Cancel
Save