EIP-7742: Add target_blob_count to block header (#7808)

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
besu-for-fleet
Simon Dudley 3 weeks ago committed by GitHub
parent 42b3cd4291
commit f855d5b72f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java
  2. 3
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java
  3. 1
      besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java
  4. 1
      besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java
  5. 2
      besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java
  6. 11
      config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java
  7. 3
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java
  8. 6
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java
  9. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java
  10. 7
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java
  11. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java
  12. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java
  13. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java
  14. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java
  15. 2
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java
  16. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java
  17. 14
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java
  18. 20
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java
  19. 17
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java
  20. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java
  21. 8
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java
  22. 12
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java
  23. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java
  24. 3
      ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague.json
  25. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java
  26. 3
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java
  27. 1
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java
  28. 1
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java
  29. 2
      plugin-api/build.gradle
  30. 12
      plugin-api/src/main/java/org/hyperledger/besu/plugin/data/ProcessableBlockHeader.java

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

@ -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/";

@ -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.
* *

@ -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));

@ -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());
} }
} }

@ -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;

@ -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();
}
} }

Loading…
Cancel
Save