From f18c370ed97386c5c53b2797bd1de1ba925beeac Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 8 Jun 2023 22:08:51 +1000 Subject: [PATCH] validate versioned hashes (#5546) * wip - added versioned hashes checking Signed-off-by: Sally MacFarlane * optional handling, updated test mocks Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane Signed-off-by: Justin Florentine Co-authored-by: Justin Florentine --- .../engine/AbstractEngineNewPayload.java | 45 +++++++++++++++++++ .../parameters/EnginePayloadParameter.java | 9 +++- .../engine/AbstractEngineNewPayloadTest.java | 1 + 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index 2a4d97ee349..a89b2c53fd7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -66,6 +66,7 @@ import io.vertx.core.Vertx; import io.vertx.core.json.Json; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -206,6 +207,50 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) "Block already present in bad block manager."); } + final List transactionVersionedHashes = new ArrayList<>(); + // get versioned hashes, in order, from all blob tx + transactions.stream() + .filter(tx -> tx.getBlobCount() > 0) + .forEachOrdered( + tx -> + transactionVersionedHashes.addAll( + tx.getVersionedHashes().get().stream() + .map(vh -> vh.toBytes()) + .collect(toList()))); + // and compare with expected versioned hashes param + final Optional> maybeVersionedHashes = + Optional.ofNullable(blockParam.getVersionedHashes()); + // check if one is empty + if (maybeVersionedHashes.isPresent() && transactionVersionedHashes.isEmpty()) { + return respondWithInvalid( + reqId, + blockParam, + null, + INVALID, + "Versioned hashes from blob transactions (empty) do not match expected values"); + } + if (maybeVersionedHashes.isEmpty() && !transactionVersionedHashes.isEmpty()) { + return respondWithInvalid( + reqId, + blockParam, + null, + INVALID, + "Versioned hashes from blob transactions do not match expected values (empty)"); + } + if (maybeVersionedHashes.isEmpty() && transactionVersionedHashes.isEmpty()) { + LOG.trace("Versioned hashes from blob tx (empty) matches expected values (empty)"); + } else { + // otherwise, check list contents + if (!maybeVersionedHashes.get().equals(transactionVersionedHashes)) { + return respondWithInvalid( + reqId, + blockParam, + null, + INVALID, + "Versioned hashes from blob transactions do not match expected values (empty)"); + } + } + final Optional maybeParentHeader = protocolContext.getBlockchain().getBlockHeader(blockParam.getParentHash()); if (maybeParentHeader.isPresent() diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java index d3294fa9219..29e06be25fd 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java @@ -48,6 +48,7 @@ public class EnginePayloadParameter { private final List transactions; private final List withdrawals; private final List deposits; + private final List versionedHashes; private final long dataGasUsed; private final String excessDataGas; @@ -70,7 +71,8 @@ public EnginePayloadParameter( @JsonProperty("withdrawals") final List withdrawals, @JsonProperty("dataGasUsed") final UnsignedLongParameter dataGasUsed, @JsonProperty("deposits") final List deposits, - @JsonProperty("excessDataGas") final String excessDataGas) { + @JsonProperty("excessDataGas") final String excessDataGas, + @JsonProperty("versionedHashes") final List versionedHashes) { this.blockHash = blockHash; this.parentHash = parentHash; this.feeRecipient = feeRecipient; @@ -89,6 +91,7 @@ public EnginePayloadParameter( this.deposits = deposits; this.dataGasUsed = dataGasUsed.getValue(); this.excessDataGas = excessDataGas; + this.versionedHashes = versionedHashes; } public Hash getBlockHash() { @@ -162,4 +165,8 @@ public String getExcessDataGas() { public List getDeposits() { return deposits; } + + public List getVersionedHashes() { + return versionedHashes; + } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java index 7955762835c..8fc0fa94551 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java @@ -617,6 +617,7 @@ private EnginePayloadParameter mockPayload( header.getPrevRandao().map(Bytes32::toHexString).orElse("0x0"), txs, withdrawals, + null, new UnsignedLongParameter(header.getDataGasUsed()), deposits, header.getExcessDataGas().map(DataGas::toHexString).orElse(null));