Skip to content

Commit

Permalink
Estimate the memory size of EIP-7702 transactions (hyperledger#7984)
Browse files Browse the repository at this point in the history
* Estimate the memory size of EIP-7702 transactions

Signed-off-by: Fabio Di Fabio <[email protected]>

* Apply suggestions from code review

Signed-off-by: Fabio Di Fabio <[email protected]>

---------

Signed-off-by: Fabio Di Fabio <[email protected]>
  • Loading branch information
fab-10 authored Dec 11, 2024
1 parent e2bd137 commit ea04b25
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,10 @@ public Transaction detachedCopy() {
blobsWithCommitments.map(
withCommitments ->
blobsWithCommitmentsDetachedCopy(withCommitments, detachedVersionedHashes.get()));
final Optional<List<CodeDelegation>> detachedCodeDelegationList =
maybeCodeDelegationList.map(
codeDelegations ->
codeDelegations.stream().map(this::codeDelegationDetachedCopy).toList());

final var copiedTx =
new Transaction(
Expand All @@ -1112,7 +1116,7 @@ public Transaction detachedCopy() {
chainId,
detachedVersionedHashes,
detachedBlobsWithCommitments,
maybeCodeDelegationList);
detachedCodeDelegationList);

// copy also the computed fields, to avoid to recompute them
copiedTx.sender = this.sender;
Expand All @@ -1129,6 +1133,15 @@ private AccessListEntry accessListDetachedCopy(final AccessListEntry accessListE
return new AccessListEntry(detachedAddress, detachedStorage);
}

private CodeDelegation codeDelegationDetachedCopy(final CodeDelegation codeDelegation) {
final Address detachedAddress = Address.wrap(codeDelegation.address().copy());
return new org.hyperledger.besu.ethereum.core.CodeDelegation(
codeDelegation.chainId(),
detachedAddress,
codeDelegation.nonce(),
codeDelegation.signature());
}

private BlobsWithCommitments blobsWithCommitmentsDetachedCopy(
final BlobsWithCommitments blobsWithCommitments, final List<VersionedHash> versionedHashes) {
final var detachedCommitments =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.core;

import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
Expand All @@ -29,7 +30,8 @@
import org.apache.tuweni.bytes.Bytes;

public class TransactionTestFixture {

private final SECPSignature signature =
new SECPSignature(BigInteger.ONE, BigInteger.ONE, (byte) 0);
private TransactionType transactionType = TransactionType.FRONTIER;

private long nonce = 0;
Expand All @@ -56,6 +58,8 @@ public class TransactionTestFixture {

private Optional<BlobsWithCommitments> blobs = Optional.empty();
private Optional<BigInteger> v = Optional.empty();
private Optional<List<org.hyperledger.besu.datatypes.CodeDelegation>> codeDelegations =
Optional.empty();

public Transaction createTransaction(final KeyPair keys) {
final Transaction.Builder builder = Transaction.builder();
Expand Down Expand Up @@ -93,6 +97,12 @@ public Transaction createTransaction(final KeyPair keys) {
}
break;
case DELEGATE_CODE:
builder.maxPriorityFeePerGas(maxPriorityFeePerGas.orElse(Wei.of(500)));
builder.maxFeePerGas(maxFeePerGas.orElse(Wei.of(5000)));
builder.accessList(accessListEntries.orElse(List.of()));
builder.codeDelegations(
codeDelegations.orElse(
List.of(new CodeDelegation(chainId.get(), sender, 0, signature))));
break;
}

Expand Down Expand Up @@ -183,4 +193,10 @@ public TransactionTestFixture blobsWithCommitments(final Optional<BlobsWithCommi
this.blobs = blobs;
return this;
}

public TransactionTestFixture codeDelegations(
final List<org.hyperledger.besu.datatypes.CodeDelegation> codeDelegations) {
this.codeDelegations = Optional.of(codeDelegations);
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@
*/
package org.hyperledger.besu.ethereum.eth.transactions;

import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_ENTRY_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_STORAGE_KEY_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOBS_WITH_COMMITMENTS_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOB_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.CODE_DELEGATION_ENTRY_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.EIP1559_AND_EIP4844_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.KZG_COMMITMENT_OR_PROOF_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_ACCESS_LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CHAIN_ID_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_TO_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.PAYLOAD_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.PENDING_TRANSACTION_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.VERSIONED_HASH_SIZE;

import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
Expand All @@ -31,21 +49,6 @@
public abstract class PendingTransaction
implements org.hyperledger.besu.datatypes.PendingTransaction {
static final int NOT_INITIALIZED = -1;
static final int FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE = 904;
static final int EIP1559_AND_EIP4844_SHALLOW_MEMORY_SIZE = 1016;
static final int OPTIONAL_TO_MEMORY_SIZE = 112;
static final int OPTIONAL_CHAIN_ID_MEMORY_SIZE = 80;
static final int PAYLOAD_BASE_MEMORY_SIZE = 32;
static final int ACCESS_LIST_STORAGE_KEY_MEMORY_SIZE = 32;
static final int ACCESS_LIST_ENTRY_BASE_MEMORY_SIZE = 248;
static final int OPTIONAL_ACCESS_LIST_MEMORY_SIZE = 24;
static final int VERSIONED_HASH_SIZE = 96;
static final int BASE_LIST_SIZE = 48;
static final int BASE_OPTIONAL_SIZE = 16;
static final int KZG_COMMITMENT_OR_PROOF_SIZE = 112;
static final int BLOB_SIZE = 131136;
static final int BLOBS_WITH_COMMITMENTS_SIZE = 40;
static final int PENDING_TRANSACTION_MEMORY_SIZE = 40;
private static final AtomicLong TRANSACTIONS_ADDED = new AtomicLong();
private final Transaction transaction;
private final long addedAt;
Expand Down Expand Up @@ -147,28 +150,28 @@ private int computeMemorySize() {
case ACCESS_LIST -> computeAccessListMemorySize();
case EIP1559 -> computeEIP1559MemorySize();
case BLOB -> computeBlobMemorySize();
case DELEGATE_CODE -> computeSetCodeMemorySize();
case DELEGATE_CODE -> computeDelegateCodeMemorySize();
}
+ PENDING_TRANSACTION_MEMORY_SIZE;
+ PENDING_TRANSACTION_SHALLOW_SIZE;
}

private int computeFrontierMemorySize() {
return FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE
return FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE
+ computePayloadMemorySize()
+ computeToMemorySize()
+ computeChainIdMemorySize();
}

private int computeAccessListMemorySize() {
return FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE
return FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE
+ computePayloadMemorySize()
+ computeToMemorySize()
+ computeChainIdMemorySize()
+ computeAccessListEntriesMemorySize();
}

private int computeEIP1559MemorySize() {
return EIP1559_AND_EIP4844_SHALLOW_MEMORY_SIZE
return EIP1559_AND_EIP4844_SHALLOW_SIZE
+ computePayloadMemorySize()
+ computeToMemorySize()
+ computeChainIdMemorySize()
Expand All @@ -177,41 +180,41 @@ private int computeEIP1559MemorySize() {

private int computeBlobMemorySize() {
return computeEIP1559MemorySize()
+ BASE_OPTIONAL_SIZE // for the versionedHashes field
+ OPTIONAL_SHALLOW_SIZE // for the versionedHashes field
+ computeBlobWithCommitmentsMemorySize();
}

private int computeSetCodeMemorySize() {
return 0;
private int computeDelegateCodeMemorySize() {
return computeEIP1559MemorySize() + computeCodeDelegationListMemorySize();
}

private int computeBlobWithCommitmentsMemorySize() {
final int blobCount = transaction.getBlobCount();

return BASE_OPTIONAL_SIZE
return OPTIONAL_SHALLOW_SIZE
+ BLOBS_WITH_COMMITMENTS_SIZE
+ (BASE_LIST_SIZE * 4)
+ (LIST_SHALLOW_SIZE * 4)
+ (KZG_COMMITMENT_OR_PROOF_SIZE * blobCount * 2)
+ (VERSIONED_HASH_SIZE * blobCount)
+ (BLOB_SIZE * blobCount);
}

private int computePayloadMemorySize() {
return transaction.getPayload().size() > 0
? PAYLOAD_BASE_MEMORY_SIZE + transaction.getPayload().size()
return !transaction.getPayload().isEmpty()
? PAYLOAD_SHALLOW_SIZE + transaction.getPayload().size()
: 0;
}

private int computeToMemorySize() {
if (transaction.getTo().isPresent()) {
return OPTIONAL_TO_MEMORY_SIZE;
return OPTIONAL_TO_SIZE;
}
return 0;
}

private int computeChainIdMemorySize() {
if (transaction.getChainId().isPresent()) {
return OPTIONAL_CHAIN_ID_MEMORY_SIZE;
return OPTIONAL_CHAIN_ID_SIZE;
}
return 0;
}
Expand All @@ -221,11 +224,23 @@ private int computeAccessListEntriesMemorySize() {
.getAccessList()
.map(
al -> {
int totalSize = OPTIONAL_ACCESS_LIST_MEMORY_SIZE;
totalSize += al.size() * ACCESS_LIST_ENTRY_BASE_MEMORY_SIZE;
int totalSize = OPTIONAL_ACCESS_LIST_SHALLOW_SIZE;
totalSize += al.size() * ACCESS_LIST_ENTRY_SHALLOW_SIZE;
totalSize +=
al.stream().map(AccessListEntry::storageKeys).mapToInt(List::size).sum()
* ACCESS_LIST_STORAGE_KEY_MEMORY_SIZE;
* ACCESS_LIST_STORAGE_KEY_SIZE;
return totalSize;
})
.orElse(0);
}

private int computeCodeDelegationListMemorySize() {
return transaction
.getCodeDelegationList()
.map(
cd -> {
int totalSize = OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE;
totalSize += cd.size() * CODE_DELEGATION_ENTRY_SIZE;
return totalSize;
})
.orElse(0);
Expand All @@ -252,7 +267,7 @@ public boolean equals(final Object o) {

@Override
public int hashCode() {
return 31 * (int) (sequence ^ (sequence >>> 32));
return 31 * Long.hashCode(sequence);
}

@Override
Expand Down Expand Up @@ -399,4 +414,29 @@ public boolean hasPriority() {
}
}
}

/**
* The memory size of an object is calculated using the PendingTransactionEstimatedMemorySizeTest
* look there for the details of the calculation and to adapt the code when any of the related
* class changes its structure.
*/
public interface MemorySize {
int FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE = 904;
int EIP1559_AND_EIP4844_SHALLOW_SIZE = 1016;
int OPTIONAL_TO_SIZE = 112;
int OPTIONAL_CHAIN_ID_SIZE = 80;
int PAYLOAD_SHALLOW_SIZE = 32;
int ACCESS_LIST_STORAGE_KEY_SIZE = 32;
int ACCESS_LIST_ENTRY_SHALLOW_SIZE = 248;
int OPTIONAL_ACCESS_LIST_SHALLOW_SIZE = 40;
int OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE = 40;
int CODE_DELEGATION_ENTRY_SIZE = 432;
int VERSIONED_HASH_SIZE = 96;
int LIST_SHALLOW_SIZE = 48;
int OPTIONAL_SHALLOW_SIZE = 16;
int KZG_COMMITMENT_OR_PROOF_SIZE = 112;
int BLOB_SIZE = 131136;
int BLOBS_WITH_COMMITMENTS_SIZE = 40;
int PENDING_TRANSACTION_SHALLOW_SIZE = 40;
}
}
Loading

0 comments on commit ea04b25

Please sign in to comment.