Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Estimate the memory size of EIP-7702 transactions #7984

Merged
merged 2 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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
Loading