From ce705b6da2c1df35ea351bb91870a0f59ca8ed03 Mon Sep 17 00:00:00 2001 From: "stefan.pingel@consensys.net" Date: Fri, 20 Sep 2024 17:25:51 +1000 Subject: [PATCH 1/6] keep the rlp when it makes sense Signed-off-by: stefan.pingel@consensys.net --- .../ethereum/core/TransactionReceipt.java | 56 ++++++++++++++++--- .../besu/ethereum/mainnet/BodyValidation.java | 21 +++++-- .../manager/task/GetReceiptsFromPeerTask.java | 2 +- .../eth/messages/ReceiptsMessage.java | 6 +- 4 files changed, 69 insertions(+), 16 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java index 79fb1a50149..114f3578129 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java @@ -57,6 +57,7 @@ public class TransactionReceipt implements org.hyperledger.besu.plugin.data.Tran private final int status; private final TransactionReceiptType transactionReceiptType; private final Optional revertReason; + private final Bytes rlp; /** * Creates an instance of a state root-encoded transaction receipt. @@ -78,7 +79,8 @@ public TransactionReceipt( cumulativeGasUsed, logs, LogsBloomFilter.builder().insertLogs(logs).build(), - revertReason); + revertReason, + null); } private TransactionReceipt( @@ -87,7 +89,8 @@ private TransactionReceipt( final long cumulativeGasUsed, final List logs, final LogsBloomFilter bloomFilter, - final Optional revertReason) { + final Optional revertReason, + final Bytes rlp) { this( transactionType, stateRoot, @@ -95,7 +98,8 @@ private TransactionReceipt( cumulativeGasUsed, logs, bloomFilter, - revertReason); + revertReason, + rlp); } /** @@ -118,7 +122,8 @@ public TransactionReceipt( cumulativeGasUsed, logs, LogsBloomFilter.builder().insertLogs(logs).build(), - revertReason); + revertReason, + null); } public TransactionReceipt( @@ -128,7 +133,18 @@ public TransactionReceipt( final List logs, final LogsBloomFilter bloomFilter, final Optional revertReason) { - this(transactionType, null, status, cumulativeGasUsed, logs, bloomFilter, revertReason); + this(transactionType, null, status, cumulativeGasUsed, logs, bloomFilter, revertReason, null); + } + + public TransactionReceipt( + final TransactionType transactionType, + final int status, + final long cumulativeGasUsed, + final List logs, + final LogsBloomFilter bloomFilter, + final Optional revertReason, + final Bytes rlp) { + this(transactionType, null, status, cumulativeGasUsed, logs, bloomFilter, revertReason, rlp); } public TransactionReceipt( @@ -153,7 +169,8 @@ private TransactionReceipt( final long cumulativeGasUsed, final List logs, final LogsBloomFilter bloomFilter, - final Optional revertReason) { + final Optional revertReason, + final Bytes rlp) { this.transactionType = transactionType; this.stateRoot = stateRoot; this.cumulativeGasUsed = cumulativeGasUsed; @@ -163,6 +180,7 @@ private TransactionReceipt( this.transactionReceiptType = stateRoot == null ? TransactionReceiptType.STATUS : TransactionReceiptType.ROOT; this.revertReason = revertReason; + this.rlp = rlp; } /** @@ -233,6 +251,19 @@ public static TransactionReceipt readFrom(final RLPInput input) { */ public static TransactionReceipt readFrom( final RLPInput rlpInput, final boolean revertReasonAllowed) { + return readFrom(rlpInput, revertReasonAllowed, false); + } + + /** + * Creates a transaction receipt for the given RLP + * + * @param rlpInput the RLP-encoded transaction receipt + * @param revertReasonAllowed whether the rlp input is allowed to have a revert reason + * @param keepRlp whether to store the rlp with the receipt + * @return the transaction receipt + */ + public static TransactionReceipt readFrom( + final RLPInput rlpInput, final boolean revertReasonAllowed, final boolean keepRlp) { RLPInput input = rlpInput; TransactionType transactionType = TransactionType.FRONTIER; if (!rlpInput.nextIsList()) { @@ -271,18 +302,23 @@ public static TransactionReceipt readFrom( revertReason = Optional.of(input.readBytes()); } + Bytes raw = null; + if (keepRlp) { + raw = input.raw(); + } + // Status code-encoded transaction receipts have a single // byte for success (0x01) or failure (0x80). if (firstElement.raw().size() == 1) { final int status = firstElement.readIntScalar(); input.leaveList(); return new TransactionReceipt( - transactionType, status, cumulativeGas, logs, bloomFilter, revertReason); + transactionType, status, cumulativeGas, logs, bloomFilter, revertReason, raw); } else { final Hash stateRoot = Hash.wrap(firstElement.readBytes32()); input.leaveList(); return new TransactionReceipt( - transactionType, stateRoot, cumulativeGas, logs, bloomFilter, revertReason); + transactionType, stateRoot, cumulativeGas, logs, bloomFilter, revertReason, raw); } } @@ -353,6 +389,10 @@ public Optional getRevertReason() { return revertReason; } + public Optional getRlp() { + return Optional.ofNullable(rlp); + } + @Override public boolean equals(final Object obj) { if (obj == this) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java index 15e8c3c804f..86249ab527b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java @@ -112,12 +112,21 @@ public static Hash receiptsRoot(final List receipts) { IntStream.range(0, receipts.size()) .forEach( - i -> - trie.put( - indexKey(i), - RLP.encode( - rlpOutput -> - receipts.get(i).writeToForReceiptTrie(rlpOutput, false, false)))); + i -> { + final TransactionReceipt receipt = receipts.get(i); + if (receipt.getRlp().isPresent()) { + System.out.println(receipt.getRlp().get()); + } + System.out.println( + RLP.encode(rlpOutput -> receipt.writeToForReceiptTrie(rlpOutput, false, false))); + System.out.println(); + trie.put( + indexKey(i), + receipt.getRlp().isPresent() + ? receipt.getRlp().get() + : RLP.encode( + rlpOutput -> receipt.writeToForReceiptTrie(rlpOutput, false, false))); + }); return Hash.wrap(trie.getRootHash()); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetReceiptsFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetReceiptsFromPeerTask.java index 5b52078b23e..8716c2b8849 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetReceiptsFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetReceiptsFromPeerTask.java @@ -104,7 +104,7 @@ protected Optional>> processResponse( } final ReceiptsMessage receiptsMessage = ReceiptsMessage.readFrom(message); - final List> receiptsByBlock = receiptsMessage.receipts(); + final List> receiptsByBlock = receiptsMessage.receipts(true); if (receiptsByBlock.isEmpty()) { return Optional.empty(); } else if (receiptsByBlock.size() > blockHeaders.size()) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/ReceiptsMessage.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/ReceiptsMessage.java index 7ca823cd8d7..beda51b60b2 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/ReceiptsMessage.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/ReceiptsMessage.java @@ -74,6 +74,10 @@ public int getCode() { } public List> receipts() { + return receipts(false); + } + + public List> receipts(final boolean keepRlp) { final RLPInput input = new BytesValueRLPInput(data, false); input.enterList(); final List> receipts = new ArrayList<>(); @@ -81,7 +85,7 @@ public List> receipts() { final int setSize = input.enterList(); final List receiptSet = new ArrayList<>(setSize); for (int i = 0; i < setSize; i++) { - receiptSet.add(TransactionReceipt.readFrom(input, false)); + receiptSet.add(TransactionReceipt.readFrom(input.readAsRlp(), false, keepRlp)); } input.leaveList(); receipts.add(receiptSet); From 7f2337003fc398aa20aaf400fb8b90d0efe51ce4 Mon Sep 17 00:00:00 2001 From: "stefan.pingel@consensys.net" Date: Fri, 20 Sep 2024 17:39:10 +1000 Subject: [PATCH 2/6] use the rlp when it is available Signed-off-by: stefan.pingel@consensys.net --- .../hyperledger/besu/ethereum/core/TransactionReceipt.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java index 114f3578129..7c16a7c6c7b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java @@ -208,6 +208,11 @@ void writeTo(final RLPOutput rlpOutput, final boolean withRevertReason, final bo public void writeToForReceiptTrie( final RLPOutput rlpOutput, final boolean withRevertReason, final boolean compacted) { + if (rlp != null) { + rlpOutput.writeBytes(rlp); + return; + } + if (!transactionType.equals(TransactionType.FRONTIER)) { rlpOutput.writeIntScalar(transactionType.getSerializedType()); } From aa41457f1145e90995747587004da193a9c45a0f Mon Sep 17 00:00:00 2001 From: "stefan.pingel@consensys.net" Date: Fri, 20 Sep 2024 18:20:37 +1000 Subject: [PATCH 3/6] spotless Signed-off-by: stefan.pingel@consensys.net --- .../org/hyperledger/besu/ethereum/core/TransactionReceipt.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java index 7c16a7c6c7b..8a6c00472a8 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java @@ -212,7 +212,7 @@ public void writeToForReceiptTrie( rlpOutput.writeBytes(rlp); return; } - + if (!transactionType.equals(TransactionType.FRONTIER)) { rlpOutput.writeIntScalar(transactionType.getSerializedType()); } From 1a24d2c94a82032b085663edf7200d6e872cce72 Mon Sep 17 00:00:00 2001 From: "stefan.pingel@consensys.net" Date: Tue, 1 Oct 2024 13:55:56 +1000 Subject: [PATCH 4/6] remove debug prints Signed-off-by: stefan.pingel@consensys.net --- .../hyperledger/besu/ethereum/mainnet/BodyValidation.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java index 86249ab527b..7051ec51118 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java @@ -114,12 +114,6 @@ public static Hash receiptsRoot(final List receipts) { .forEach( i -> { final TransactionReceipt receipt = receipts.get(i); - if (receipt.getRlp().isPresent()) { - System.out.println(receipt.getRlp().get()); - } - System.out.println( - RLP.encode(rlpOutput -> receipt.writeToForReceiptTrie(rlpOutput, false, false))); - System.out.println(); trie.put( indexKey(i), receipt.getRlp().isPresent() From f62d15f99d80799a08a47891ba7be173e3f8ee23 Mon Sep 17 00:00:00 2001 From: "stefan.pingel@consensys.net" Date: Thu, 3 Oct 2024 15:14:10 +1000 Subject: [PATCH 5/6] clean up Signed-off-by: stefan.pingel@consensys.net --- .../ethereum/core/TransactionReceipt.java | 21 +++++++++++-------- .../besu/ethereum/rlp/AbstractRLPInput.java | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java index 8a6c00472a8..45b20448519 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java @@ -208,8 +208,10 @@ void writeTo(final RLPOutput rlpOutput, final boolean withRevertReason, final bo public void writeToForReceiptTrie( final RLPOutput rlpOutput, final boolean withRevertReason, final boolean compacted) { - if (rlp != null) { - rlpOutput.writeBytes(rlp); + if (rlp != null && !compacted) { + // at this point we can ignore withRevertReason, because we would only have the rlp if the + // receipt was received via p2p, which means the receipt does not contain the revert reason. + rlpOutput.writeRaw(rlp); return; } @@ -285,13 +287,14 @@ public static TransactionReceipt readFrom( LogsBloomFilter bloomFilter = null; - final boolean hasLogs = !input.nextIsList() && input.nextSize() == LogsBloomFilter.BYTE_SIZE; - if (hasLogs) { + final boolean hasBloomFilter = + !input.nextIsList() && input.nextSize() == LogsBloomFilter.BYTE_SIZE; + if (!hasBloomFilter) { // The logs below will populate the bloom filter upon construction. bloomFilter = LogsBloomFilter.readFrom(input); } // TODO consider validating that the logs and bloom filter match. - final boolean compacted = !hasLogs; + final boolean compacted = !hasBloomFilter; final List logs = input.readList(logInput -> Log.readFrom(logInput, compacted)); if (compacted) { bloomFilter = LogsBloomFilter.builder().insertLogs(logs).build(); @@ -307,9 +310,9 @@ public static TransactionReceipt readFrom( revertReason = Optional.of(input.readBytes()); } - Bytes raw = null; + Bytes rlpBytes = null; if (keepRlp) { - raw = input.raw(); + rlpBytes = rlpInput.raw(); } // Status code-encoded transaction receipts have a single @@ -318,12 +321,12 @@ public static TransactionReceipt readFrom( final int status = firstElement.readIntScalar(); input.leaveList(); return new TransactionReceipt( - transactionType, status, cumulativeGas, logs, bloomFilter, revertReason, raw); + transactionType, status, cumulativeGas, logs, bloomFilter, revertReason, rlpBytes); } else { final Hash stateRoot = Hash.wrap(firstElement.readBytes32()); input.leaveList(); return new TransactionReceipt( - transactionType, stateRoot, cumulativeGas, logs, bloomFilter, revertReason, raw); + transactionType, stateRoot, cumulativeGas, logs, bloomFilter, revertReason, rlpBytes); } } diff --git a/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/AbstractRLPInput.java b/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/AbstractRLPInput.java index 51a7f87e12e..6558832a844 100644 --- a/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/AbstractRLPInput.java +++ b/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/AbstractRLPInput.java @@ -476,7 +476,7 @@ public int enterList() { * * @see #enterList() * @param skipCount true if the element count is not required. - * @return -1 if skipCount==true, otherwise, the number of item of the entered list. + * @return -1 if skipCount==true, otherwise, the number of items of the entered list. */ public int enterList(final boolean skipCount) { if (currentItem >= size) { From f53ae35912e153b3046e1895bbd4980eb7a1c11f Mon Sep 17 00:00:00 2001 From: "stefan.pingel@consensys.net" Date: Thu, 3 Oct 2024 16:24:29 +1000 Subject: [PATCH 6/6] fix clean-up Signed-off-by: stefan.pingel@consensys.net --- .../org/hyperledger/besu/ethereum/core/TransactionReceipt.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java index 45b20448519..e0da32c03ff 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java @@ -289,7 +289,7 @@ public static TransactionReceipt readFrom( final boolean hasBloomFilter = !input.nextIsList() && input.nextSize() == LogsBloomFilter.BYTE_SIZE; - if (!hasBloomFilter) { + if (hasBloomFilter) { // The logs below will populate the bloom filter upon construction. bloomFilter = LogsBloomFilter.readFrom(input); }