Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- Add `--max-blobs-per-transaction` CLI option to configure the maximum number of blobs per transaction [#9912](https://github.com/hyperledger/besu/pull/9912)
- Add blockTimestamp to transaction RPC results [#9887](https://github.com/hyperledger/besu/pull/9887)
- Plugin API: Allow the registration of multiple PluginTransactionPoolValidatorFactory [#9964](https://github.com/hyperledger/besu/pull/9964)
- Support [EIP-7975](https://eips.ethereum.org/EIPS/eip-7975): eth/70 - partial block receipt lists

## 26.2.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"response": {
"jsonrpc": "2.0",
"id": 2,
"result": "0x45"
"result": "0x46"
},
"statusCode": 200
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@
/**
* Eth protocol messages as defined in <a
* href="https://github.com/ethereum/devp2p/blob/master/caps/eth.md">Ethereum Wire Protocol
* (ETH)</a>}
* (ETH)</a>
*/
public class EthProtocol implements SubProtocol {
public static final String NAME = "eth";
private static final EthProtocol INSTANCE = new EthProtocol();
public static final Capability ETH68 = Capability.create(NAME, EthProtocolVersion.V68);
public static final Capability ETH69 = Capability.create(NAME, EthProtocolVersion.V69);
public static final Capability ETH70 = Capability.create(NAME, EthProtocolVersion.V70);
public static final BitSet REQUEST_ID_MESSAGES;

static {
Expand All @@ -52,7 +53,7 @@ public class EthProtocol implements SubProtocol {
}

// Latest version of the Eth protocol
public static final Capability LATEST = ETH69;
public static final Capability LATEST = ETH70;

public static boolean requestIdCompatible(final int code) {
return REQUEST_ID_MESSAGES.get(code);
Expand All @@ -67,7 +68,7 @@ public String getName() {
public int messageSpace(final int protocolVersion) {
return switch (protocolVersion) {
case EthProtocolVersion.V68 -> 17;
case EthProtocolVersion.V69 -> 18;
case EthProtocolVersion.V69, EthProtocolVersion.V70 -> 18;
default -> 0;
};
}
Expand Down Expand Up @@ -106,4 +107,8 @@ public static EthProtocol get() {
public static boolean isEth69Compatible(final Capability capability) {
return NAME.equals(capability.getName()) && capability.getVersion() >= ETH69.getVersion();
}

public static boolean isEth70Compatible(final Capability capability) {
return NAME.equals(capability.getName()) && capability.getVersion() >= ETH70.getVersion();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
public class EthProtocolVersion {
public static final int V68 = 68;
public static final int V69 = 69;
public static final int V70 = 70;

/** eth/68 */
private static final List<Integer> eth68Messages =
Expand Down Expand Up @@ -76,7 +77,7 @@ public class EthProtocolVersion {
public static List<Integer> getSupportedMessages(final int protocolVersion) {
return switch (protocolVersion) {
case EthProtocolVersion.V68 -> eth68Messages;
case EthProtocolVersion.V69 -> eth69Messages;
case EthProtocolVersion.V69, EthProtocolVersion.V70 -> eth69Messages;
default -> Collections.emptyList();
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ private List<Capability> calculateCapabilities(

capabilities.add(EthProtocol.ETH68);
capabilities.add(EthProtocol.ETH69);
capabilities.add(EthProtocol.ETH70);
capabilities.removeIf(cap -> cap.getVersion() > ethProtocolConfiguration.getMaxEthCapability());
capabilities.removeIf(cap -> cap.getVersion() < ethProtocolConfiguration.getMinEthCapability());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.eth.manager;

import static org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason.INVALID_FIRST_BLOCK_RECEIPT_INDEX;

import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockBody;
Expand All @@ -32,9 +34,11 @@
import org.hyperledger.besu.ethereum.eth.messages.GetBlockBodiesMessage;
import org.hyperledger.besu.ethereum.eth.messages.GetBlockHeadersMessage;
import org.hyperledger.besu.ethereum.eth.messages.GetNodeDataMessage;
import org.hyperledger.besu.ethereum.eth.messages.GetPaginatedReceiptsMessage;
import org.hyperledger.besu.ethereum.eth.messages.GetPooledTransactionsMessage;
import org.hyperledger.besu.ethereum.eth.messages.GetReceiptsMessage;
import org.hyperledger.besu.ethereum.eth.messages.NodeDataMessage;
import org.hyperledger.besu.ethereum.eth.messages.PaginatedReceiptsMessage;
import org.hyperledger.besu.ethereum.eth.messages.PooledTransactionsMessage;
import org.hyperledger.besu.ethereum.eth.messages.ReceiptsMessage;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
Expand Down Expand Up @@ -96,13 +100,22 @@ private void registerResponseConstructors() {
maxMessageSize));
ethMessages.registerResponseConstructor(
EthProtocolMessages.GET_RECEIPTS,
(peer, messageData, capability) ->
constructGetReceiptsResponse(
(peer, messageData, capability) -> {
if (EthProtocol.isEth70Compatible(capability)) {
return constructGetPaginatedReceiptsResponse(
peer,
blockchain,
messageData,
ethereumWireProtocolConfiguration.getMaxGetReceipts(),
maxMessageSize,
capability));
maxMessageSize);
}
return constructGetReceiptsResponse(
blockchain,
messageData,
ethereumWireProtocolConfiguration.getMaxGetReceipts(),
maxMessageSize,
capability);
});
ethMessages.registerResponseConstructor(
EthProtocolMessages.GET_NODE_DATA,
(peer, messageData, capability) ->
Expand Down Expand Up @@ -226,18 +239,18 @@ static MessageData constructGetReceiptsResponse(
final int maxMessageSize,
final Capability cap) {
final GetReceiptsMessage getReceipts = GetReceiptsMessage.readFrom(message);
final Iterable<Hash> hashes = getReceipts.hashes();
final Iterable<Hash> blockHashes = getReceipts.blockHashes();

int responseSizeEstimate = RLP.MAX_PREFIX_SIZE;
final BytesValueRLPOutput rlp = new BytesValueRLPOutput();
rlp.startList();
int count = 0;
for (final Hash hash : hashes) {
for (final Hash blockHash : blockHashes) {
if (count >= requestLimit) {
break;
}
count++;
final Optional<List<TransactionReceipt>> maybeReceipts = blockchain.getTxReceipts(hash);
final Optional<List<TransactionReceipt>> maybeReceipts = blockchain.getTxReceipts(blockHash);
if (maybeReceipts.isEmpty()) {
continue;
}
Expand Down Expand Up @@ -265,6 +278,97 @@ static MessageData constructGetReceiptsResponse(
return ReceiptsMessage.createUnsafe(rlp.encoded());
}

static MessageData constructGetPaginatedReceiptsResponse(
final EthPeer peer,
final Blockchain blockchain,
final MessageData message,
final int requestLimit,
final int maxMessageSize) {
final GetPaginatedReceiptsMessage getPaginatedReceipts =
GetPaginatedReceiptsMessage.readFrom(message);
final List<Hash> requestedBlockHashes = getPaginatedReceipts.blockHashes();
final List<Hash> blockHashes;
if (requestedBlockHashes.size() > requestLimit) {
LOG.atDebug()
.setMessage(
"Requested receipts for {} blocks, more than allowed max number of {}, ignoring extra blocks")
.addArgument(requestedBlockHashes::size)
.addArgument(requestLimit)
.log();
blockHashes = requestedBlockHashes.subList(0, requestLimit);
} else {
blockHashes = requestedBlockHashes;
}

final var blockReceiptsRLPs = new ArrayList<BytesValueRLPOutput>(blockHashes.size());

int skipBefore = getPaginatedReceipts.firstBlockReceiptIndex();
int responseSizeEstimate = RLP.MAX_PREFIX_SIZE;
boolean lastBlockIncomplete = false;

for (final Hash blockHash : blockHashes) {
final Optional<List<TransactionReceipt>> maybeReceipts = blockchain.getTxReceipts(blockHash);
if (maybeReceipts.isEmpty()) {
LOG.debug(
"Invalid request from peer {}, block {} does not exists, returning", peer, blockHash);
break;
}
Comment thread
macfarla marked this conversation as resolved.

final List<TransactionReceipt> blockReceipts = maybeReceipts.get();
final List<TransactionReceipt> requestedReceipts;

if (skipBefore > blockReceipts.size()) {
Comment thread
fab-10 marked this conversation as resolved.
LOG.debug(
"Invalid request from peer {}, firstBlockReceiptIndex {} is greater than the receipt count of {} for block {}",
peer,
skipBefore,
blockReceipts.size(),
blockHash);
peer.disconnect(INVALID_FIRST_BLOCK_RECEIPT_INDEX);
Comment thread
fab-10 marked this conversation as resolved.
Outdated
return PaginatedReceiptsMessage.createUnsafe(Bytes.EMPTY, false);
Comment thread
fab-10 marked this conversation as resolved.
Outdated
}

if (skipBefore > 0) {
requestedReceipts = blockReceipts.subList(skipBefore, blockReceipts.size());
skipBefore = 0;
} else {
requestedReceipts = blockReceipts;
}

final BytesValueRLPOutput encodedBlockReceipts = new BytesValueRLPOutput();
encodedBlockReceipts.startList();

for (final TransactionReceipt receipt : requestedReceipts) {
final BytesValueRLPOutput encodedReceipt = new BytesValueRLPOutput();
TransactionReceiptEncoder.writeTo(
receipt,
encodedReceipt,
TransactionReceiptEncodingConfiguration.ETH69_RECEIPT_CONFIGURATION);
if (responseSizeEstimate + encodedReceipt.encodedSize() + RLP.MAX_PREFIX_SIZE
> maxMessageSize) {
lastBlockIncomplete = true;
break;
}
responseSizeEstimate += encodedReceipt.encodedSize();
encodedBlockReceipts.writeRaw(encodedReceipt.encoded());
}

encodedBlockReceipts.endList();
blockReceiptsRLPs.add(encodedBlockReceipts);
if (lastBlockIncomplete) {
break;
}
}

final BytesValueRLPOutput rlp = new BytesValueRLPOutput();
rlp.writeLongScalar(lastBlockIncomplete ? 1 : 0);
rlp.startList();
blockReceiptsRLPs.forEach(r -> rlp.writeRaw(r.encoded()));
rlp.endList();

return PaginatedReceiptsMessage.createUnsafe(rlp.encoded(), lastBlockIncomplete);
}

static MessageData constructGetPooledTransactionsResponse(
final TransactionPool transactionPool,
final EthPeer peer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public enum PeerTaskValidationResponse {
RESULTS_DO_NOT_MATCH_QUERY(null, true),
NON_SEQUENTIAL_HEADERS_RETURNED(
DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL_NON_SEQUENTIAL_HEADERS, true),
RESULTS_VALID_AND_GOOD(null, false);
RESULTS_VALID_AND_GOOD(null, false),
INVALID_RECEIPT_RETURNED(DisconnectMessage.DisconnectReason.INVALID_RECEIPT_RECEIVED, true);
private final Optional<DisconnectMessage.DisconnectReason> disconnectReason;
private final boolean recordUselessResponse;

Expand Down
Loading