Conversation
Signed-off-by: stefan.pingel@consensys.net <stefan.pingel@consensys.net>
Signed-off-by: stefan.pingel@consensys.net <stefan.pingel@consensys.net>
...src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobAndProofV1.java
Outdated
Show resolved
Hide resolved
| return blobQuad; | ||
| } | ||
|
|
||
| public void onTransactionAdded(final Transaction transaction) { |
There was a problem hiding this comment.
idk if the RPC should be itself managing the blob cache?
There was a problem hiding this comment.
I was wondering where that should live. The other option would be the TransactionPool. The BlobCache is taken care of in the TransactionPool, because these blobs are needed in case we have a reorg.
The blobMap is not needed by the TransactionPool. Here we just keep track of the blobs that we have available in our transaction pool and we have to update the map when blob transactions are added or removed from the pool.
There was a problem hiding this comment.
I have moved that logic into the TransactionPool
.../org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsV1Test.java
Outdated
Show resolved
Hide resolved
| new TransactionPoolMetrics(metricsSystem), | ||
| poolConf); | ||
| poolConf, | ||
| new BlobCache()); |
There was a problem hiding this comment.
@jflo can we daggerise the BlobCache or does it need other infra first?
There was a problem hiding this comment.
It is kind of daggerised. It is available in BesuComponent, but I did not know how to use that in the engine RPC. Maybe @jflo can tell us!
There was a problem hiding this comment.
To make this a more complete approach, the RPC and the TransactionPool would need to be daggerized as well, which would allow all intermediate references to be removed.
Signed-off-by: stefan.pingel@consensys.net <stefan.pingel@consensys.net>
…sonrpc/internal/methods/engine/EngineGetBlobsV1Test.java Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com> Signed-off-by: Stefan Pingel <16143240+pinges@users.noreply.github.com>
fab-10
left a comment
There was a problem hiding this comment.
LGTM, see the note on the of passing blobCache, then add a changelog entry and doc-change-required label
| if (blobQuad == null) { | ||
| blobQuad = blobCache.get(vh); | ||
| } |
There was a problem hiding this comment.
in theory this fallback should not be necessary, and removing the need to have the blobCache will simplify a lot the change, removing the need to pass it around, or am I missing something?
There was a problem hiding this comment.
I also don't understand. It seems to me that blobMap is redundant, and this RPC should just use the same instance of the blobCache that the transactionpool does. Management of the cache contents should be ignored by the RPC and treated as a "read only" concern.
There was a problem hiding this comment.
The blob cache does contain all the blobs that have been put into a block recently. These blobs are used to re-add the blob transactions in case of a reorg, as the blobs are not part of the block. After 3 epochs these blobs are removed from the cache. Blobs that are in the cache are not part of Transactions that are in the pool.
The blob map keeps track of all the blobs that are part of transactions that are in our transaction pool. These are the blobs that the CL will most likely ask for. We do keep them in the map for as long as their transactions are in the transaction pool.
@fab-10 @jflo
There was a problem hiding this comment.
According to the specification of the new method, the CL should be interested in blobs that are in the txpool, and not blobs that have been already included in a block, so blobMap should be enough, because in case of a reorg a new add notification will be sent.
jflo
left a comment
There was a problem hiding this comment.
Need to remove the responsibility of managing blobs from the RPC method.
| if (blobQuad == null) { | ||
| blobQuad = blobCache.get(vh); | ||
| } |
There was a problem hiding this comment.
I also don't understand. It seems to me that blobMap is redundant, and this RPC should just use the same instance of the blobCache that the transactionpool does. Management of the cache contents should be ignored by the RPC and treated as a "read only" concern.
| */ | ||
| public class EngineGetBlobsV1 extends ExecutionEngineJsonRpcMethod { | ||
|
|
||
| private final Map<VersionedHash, BlobsWithCommitments.BlobQuad> blobMap = new HashMap<>(); |
There was a problem hiding this comment.
I think naming this something more specific would help me understand why it is necessary. As is, it reads like a synonym for blobCache, and seems like duplication.
| new TransactionPoolMetrics(metricsSystem), | ||
| poolConf); | ||
| poolConf, | ||
| new BlobCache()); |
There was a problem hiding this comment.
To make this a more complete approach, the RPC and the TransactionPool would need to be daggerized as well, which would allow all intermediate references to be removed.
Signed-off-by: stefan.pingel@consensys.net <stefan.pingel@consensys.net>
| private final SaveRestoreManager saveRestoreManager = new SaveRestoreManager(); | ||
| private final Set<Address> localSenders = ConcurrentHashMap.newKeySet(); | ||
| private final EthScheduler.OrderedProcessor<BlockAddedEvent> blockAddedEventOrderedProcessor; | ||
| private final Map<VersionedHash, BlobsWithCommitments.BlobQuad> blobMap = new HashMap<>(); |
There was a problem hiding this comment.
what about a more talking name, like liveBlobs or pendingBlobs?
| private void mapBlobsOnTransactionAdded( | ||
| final org.hyperledger.besu.datatypes.Transaction transaction) { | ||
| final Optional<BlobsWithCommitments> maybeBlobsWithCommitments = | ||
| transaction.getBlobsWithCommitments(); | ||
| if (maybeBlobsWithCommitments.isEmpty()) { | ||
| return; | ||
| } | ||
| final List<BlobsWithCommitments.BlobQuad> blobQuads = | ||
| maybeBlobsWithCommitments.get().getBlobQuads(); | ||
| blobQuads.forEach(bq -> blobMap.put(bq.versionedHash(), bq)); | ||
| } | ||
|
|
||
| private void unmapBlobsOnTransactionDropped( | ||
| final org.hyperledger.besu.datatypes.Transaction transaction) { | ||
| final Optional<BlobsWithCommitments> maybeBlobsWithCommitments = | ||
| transaction.getBlobsWithCommitments(); | ||
| if (maybeBlobsWithCommitments.isEmpty()) { | ||
| return; | ||
| } | ||
| final List<BlobsWithCommitments.BlobQuad> blobQuads = | ||
| maybeBlobsWithCommitments.get().getBlobQuads(); | ||
| blobQuads.forEach(bq -> blobMap.remove(bq.versionedHash())); | ||
| } | ||
|
|
||
| public BlobsWithCommitments.BlobQuad getBlobQuad(final VersionedHash vh) { | ||
| BlobsWithCommitments.BlobQuad blobQuad = blobMap.get(vh); | ||
| if (blobQuad == null) { | ||
| blobQuad = blobCache.get(vh); | ||
| } | ||
| return blobQuad; | ||
| } | ||
|
|
There was a problem hiding this comment.
it is better to have the logic here, and I am tempted to suggest to go a step further and extending the current BlobCache to manage both the confirmed blobs, as it does now, plus those pending blobs. (However not a blocking request, just a suggestion to manage blobs in a single place)
There was a problem hiding this comment.
I was thinking about that as well, but it felt like these are two different concerns and I think that the "map" should be part of the Transaction pool, as it points to the blobs of transactions in the pool.
Signed-off-by: stefan.pingel@consensys.net <stefan.pingel@consensys.net>
Signed-off-by: stefan.pingel@consensys.net <stefan.pingel@consensys.net>
jflo
left a comment
There was a problem hiding this comment.
Much better. The only suggestion I have would be to consider using another instance of BlobCache internally for the pooled transaction, instead of just a map. That would afford some protection from unexpected cache growth, but I think trusting the add/drop tx events is a safe assumption.
That's a good point, and in the related PRs that are fixing the notifications in the layered txpool, I will make sure they are reliable, but I think it is worth to export a metrics with the size of the map, so we can monitor its growth, but this could be part of a following PR. |
fab-10
left a comment
There was a problem hiding this comment.
LGTM, just move the changelog entry to the right place, and add doc-change-required label
CHANGELOG.md
Outdated
| - Performance optimzation for ECMUL (2 of 2) [#7543](https://github.com/hyperledger/besu/pull/7543) | ||
| - Include current chain head block when computing `eth_maxPriorityFeePerGas` [#7485](https://github.com/hyperledger/besu/pull/7485) | ||
| - Remove (old) documentation updates from the changelog [#7562](https://github.com/hyperledger/besu/pull/7562) | ||
| - Add `engine_getBlobsV1` method to the Engine API [#7553](https://github.com/hyperledger/besu/pull/7553) |
There was a problem hiding this comment.
Need to move this to the Unreleased section
|
FYI: task for adding the metrics #7578 |
Signed-off-by: stefan.pingel@consensys.net <stefan.pingel@consensys.net>
Signed-off-by: stefan.pingel@consensys.net <stefan.pingel@consensys.net>
| - Remove (old) documentation updates from the changelog [#7562](https://github.com/hyperledger/besu/pull/7562) | ||
| - Add `engine_getBlobsV1` method to the Engine API [#7553](https://github.com/hyperledger/besu/pull/7553) | ||
|
|
||
| ### Bug fixes |
| } | ||
| final List<BlobsWithCommitments.BlobQuad> blobQuads = | ||
| maybeBlobsWithCommitments.get().getBlobQuads(); | ||
| blobQuads.forEach(bq -> mapOfBlobsInTransactionPool.put(bq.versionedHash(), bq)); |
There was a problem hiding this comment.
This can be used my a malicious transaction to corrupt the mapping by sending the same blobs as a benign tx. Then send a replacement to nuke out all blobs, and the original correct mapping disappears, making the blob non-retrievable any more.
PR description
Implements the engine RPC engine_getBlobsV1 as described in ethereum/execution-apis#559
Fixed Issue(s)
#7445