|
|
|
@ -19,52 +19,63 @@ import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
|
import org.hyperledger.besu.crypto.SignatureAlgorithm; |
|
|
|
|
import org.hyperledger.besu.datatypes.AccessListEntry; |
|
|
|
|
import org.hyperledger.besu.datatypes.Address; |
|
|
|
|
import org.hyperledger.besu.datatypes.BlobsWithCommitments; |
|
|
|
|
import org.hyperledger.besu.datatypes.TransactionType; |
|
|
|
|
import org.hyperledger.besu.datatypes.Wei; |
|
|
|
|
import org.hyperledger.besu.ethereum.core.Transaction; |
|
|
|
|
import org.hyperledger.besu.ethereum.core.TransactionTestFixture; |
|
|
|
|
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; |
|
|
|
|
import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; |
|
|
|
|
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; |
|
|
|
|
import org.hyperledger.besu.ethereum.eth.transactions.layered.BaseTransactionPoolTest; |
|
|
|
|
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; |
|
|
|
|
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; |
|
|
|
|
|
|
|
|
|
import java.math.BigInteger; |
|
|
|
|
import java.util.Arrays; |
|
|
|
|
import java.util.HashSet; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Optional; |
|
|
|
|
import java.util.Set; |
|
|
|
|
import java.util.SortedSet; |
|
|
|
|
import java.util.TreeSet; |
|
|
|
|
import java.util.concurrent.atomic.LongAdder; |
|
|
|
|
import java.util.function.Function; |
|
|
|
|
|
|
|
|
|
import com.google.common.collect.Sets; |
|
|
|
|
import org.apache.tuweni.bytes.Bytes; |
|
|
|
|
import org.apache.tuweni.bytes.Bytes32; |
|
|
|
|
import org.junit.jupiter.api.Disabled; |
|
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
|
import org.junit.jupiter.api.condition.EnabledOnOs; |
|
|
|
|
import org.junit.jupiter.api.condition.OS; |
|
|
|
|
import org.openjdk.jol.info.ClassLayout; |
|
|
|
|
import org.openjdk.jol.info.GraphPathRecord; |
|
|
|
|
import org.openjdk.jol.info.GraphVisitor; |
|
|
|
|
import org.openjdk.jol.info.GraphWalker; |
|
|
|
|
|
|
|
|
|
@Disabled("Need to handle different results on different OS") |
|
|
|
|
@EnabledOnOs(OS.LINUX) |
|
|
|
|
public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPoolTest { |
|
|
|
|
private static final Set<Class<?>> SHARED_CLASSES = |
|
|
|
|
Set.of(SignatureAlgorithm.class, TransactionType.class); |
|
|
|
|
private static final Set<String> EIP1559_CONSTANT_FIELD_PATHS = Set.of(".gasPrice"); |
|
|
|
|
private static final Set<String> EIP1559_VARIABLE_SIZE_PATHS = |
|
|
|
|
Set.of(".to", ".payload", ".maybeAccessList"); |
|
|
|
|
|
|
|
|
|
private static final Set<String> COMMON_CONSTANT_FIELD_PATHS = |
|
|
|
|
Set.of(".value.ctor", ".hashNoSignature"); |
|
|
|
|
private static final Set<String> EIP1559_EIP4844_CONSTANT_FIELD_PATHS = |
|
|
|
|
Sets.union(COMMON_CONSTANT_FIELD_PATHS, Set.of(".gasPrice")); |
|
|
|
|
private static final Set<String> FRONTIER_ACCESS_LIST_CONSTANT_FIELD_PATHS = |
|
|
|
|
Set.of(".maxFeePerGas", ".maxPriorityFeePerGas"); |
|
|
|
|
private static final Set<String> FRONTIER_ACCESS_LIST_VARIABLE_SIZE_PATHS = |
|
|
|
|
Set.of(".to", ".payload", ".maybeAccessList"); |
|
|
|
|
Sets.union(COMMON_CONSTANT_FIELD_PATHS, Set.of(".maxFeePerGas", ".maxPriorityFeePerGas")); |
|
|
|
|
private static final Set<String> VARIABLE_SIZE_PATHS = |
|
|
|
|
Set.of(".chainId", ".to", ".payload", ".maybeAccessList"); |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void toSize() { |
|
|
|
|
TransactionTestFixture preparedTx = |
|
|
|
|
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), 10); |
|
|
|
|
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), 10, 0); |
|
|
|
|
Transaction txTo = |
|
|
|
|
preparedTx.to(Optional.of(Address.extract(Bytes32.random()))).createTransaction(KEYS1); |
|
|
|
|
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); |
|
|
|
|
txTo.writeTo(rlpOut); |
|
|
|
|
|
|
|
|
|
txTo = Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)); |
|
|
|
|
txTo = Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)).detachedCopy(); |
|
|
|
|
System.out.println(txTo.getSender()); |
|
|
|
|
System.out.println(txTo.getHash()); |
|
|
|
|
System.out.println(txTo.getSize()); |
|
|
|
@ -78,34 +89,17 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo |
|
|
|
|
|
|
|
|
|
GraphVisitor gv = |
|
|
|
|
gpr -> { |
|
|
|
|
// byte[] is shared so only count the specific part for each field
|
|
|
|
|
if (gpr.path().endsWith(".bytes")) { |
|
|
|
|
if (gpr.path().contains("delegate")) { |
|
|
|
|
size.add(20); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ size |
|
|
|
|
+ ")[20 = fixed address size; overrides: " |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
size.add(gpr.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ size |
|
|
|
|
+ ")[" |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
} |
|
|
|
|
size.add(gpr.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ size |
|
|
|
|
+ ")[" |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
GraphWalker gw = new GraphWalker(gv); |
|
|
|
@ -121,12 +115,13 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo |
|
|
|
|
public void payloadSize() { |
|
|
|
|
|
|
|
|
|
TransactionTestFixture preparedTx = |
|
|
|
|
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), 10); |
|
|
|
|
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), 10, 0); |
|
|
|
|
Transaction txPayload = preparedTx.createTransaction(KEYS1); |
|
|
|
|
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); |
|
|
|
|
txPayload.writeTo(rlpOut); |
|
|
|
|
|
|
|
|
|
txPayload = Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)); |
|
|
|
|
txPayload = |
|
|
|
|
Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)).detachedCopy(); |
|
|
|
|
System.out.println(txPayload.getSender()); |
|
|
|
|
System.out.println(txPayload.getHash()); |
|
|
|
|
System.out.println(txPayload.getSize()); |
|
|
|
@ -141,16 +136,141 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo |
|
|
|
|
assertThat(size.sum()).isEqualTo(PendingTransaction.PAYLOAD_BASE_MEMORY_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void chainIdSize() { |
|
|
|
|
|
|
|
|
|
BigInteger chainId = BigInteger.valueOf(1); |
|
|
|
|
Optional<BigInteger> maybeChainId = Optional.of(chainId); |
|
|
|
|
|
|
|
|
|
final ClassLayout cl = ClassLayout.parseInstance(maybeChainId); |
|
|
|
|
System.out.println(cl.toPrintable()); |
|
|
|
|
LongAdder size = new LongAdder(); |
|
|
|
|
size.add(cl.instanceSize()); |
|
|
|
|
System.out.println("Base chainId size: " + size); |
|
|
|
|
|
|
|
|
|
GraphVisitor gv = |
|
|
|
|
gpr -> { |
|
|
|
|
size.add(gpr.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ size |
|
|
|
|
+ ")[" |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
GraphWalker gw = new GraphWalker(gv); |
|
|
|
|
|
|
|
|
|
gw.walk(maybeChainId); |
|
|
|
|
|
|
|
|
|
assertThat(size.sum()).isEqualTo(PendingTransaction.OPTIONAL_CHAIN_ID_MEMORY_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void kgzCommitmentsSize() { |
|
|
|
|
blobsWithCommitmentsFieldSize( |
|
|
|
|
t -> t.getBlobsWithCommitments().get().getKzgCommitments(), |
|
|
|
|
PendingTransaction.BASE_LIST_SIZE, |
|
|
|
|
PendingTransaction.KZG_COMMITMENT_OR_PROOF_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void kgzProofsSize() { |
|
|
|
|
blobsWithCommitmentsFieldSize( |
|
|
|
|
t -> t.getBlobsWithCommitments().get().getKzgProofs(), |
|
|
|
|
PendingTransaction.BASE_LIST_SIZE, |
|
|
|
|
PendingTransaction.KZG_COMMITMENT_OR_PROOF_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void blobsSize() { |
|
|
|
|
blobsWithCommitmentsFieldSize( |
|
|
|
|
t -> t.getBlobsWithCommitments().get().getBlobs(), |
|
|
|
|
PendingTransaction.BASE_LIST_SIZE, |
|
|
|
|
PendingTransaction.BLOB_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void versionedHashesSize() { |
|
|
|
|
blobsWithCommitmentsFieldSize( |
|
|
|
|
t -> t.getBlobsWithCommitments().get().getVersionedHashes(), |
|
|
|
|
PendingTransaction.BASE_LIST_SIZE, |
|
|
|
|
PendingTransaction.VERSIONED_HASH_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void blobsWithCommitmentsFieldSize( |
|
|
|
|
final Function<Transaction, List<? extends Object>> containerExtractor, |
|
|
|
|
final long containerSize, |
|
|
|
|
final long itemSize) { |
|
|
|
|
TransactionTestFixture preparedTx = |
|
|
|
|
prepareTransaction(TransactionType.BLOB, 10, Wei.of(500), 10, 1); |
|
|
|
|
Transaction txBlob = preparedTx.createTransaction(KEYS1); |
|
|
|
|
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); |
|
|
|
|
TransactionEncoder.encodeRLP(txBlob, rlpOut, EncodingContext.POOLED_TRANSACTION); |
|
|
|
|
|
|
|
|
|
txBlob = |
|
|
|
|
TransactionDecoder.decodeRLP( |
|
|
|
|
new BytesValueRLPInput(rlpOut.encoded(), false), EncodingContext.POOLED_TRANSACTION) |
|
|
|
|
.detachedCopy(); |
|
|
|
|
System.out.println(txBlob.getSender()); |
|
|
|
|
System.out.println(txBlob.getHash()); |
|
|
|
|
System.out.println(txBlob.getSize()); |
|
|
|
|
|
|
|
|
|
final List<? extends Object> list = containerExtractor.apply(txBlob); |
|
|
|
|
|
|
|
|
|
final long cSize = sizeOfField(list, ".elements["); |
|
|
|
|
|
|
|
|
|
System.out.println("Container size: " + cSize); |
|
|
|
|
|
|
|
|
|
assertThat(cSize).isEqualTo(containerSize); |
|
|
|
|
|
|
|
|
|
final Object item = list.get(0); |
|
|
|
|
final long iSize = sizeOfField(item); |
|
|
|
|
|
|
|
|
|
System.out.println("Item size: " + iSize); |
|
|
|
|
|
|
|
|
|
assertThat(iSize).isEqualTo(itemSize); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void blobsWithCommitmentsSize() { |
|
|
|
|
TransactionTestFixture preparedTx = |
|
|
|
|
prepareTransaction(TransactionType.BLOB, 10, Wei.of(500), 10, 1); |
|
|
|
|
Transaction txBlob = preparedTx.createTransaction(KEYS1); |
|
|
|
|
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); |
|
|
|
|
TransactionEncoder.encodeRLP(txBlob, rlpOut, EncodingContext.POOLED_TRANSACTION); |
|
|
|
|
|
|
|
|
|
txBlob = |
|
|
|
|
TransactionDecoder.decodeRLP( |
|
|
|
|
new BytesValueRLPInput(rlpOut.encoded(), false), EncodingContext.POOLED_TRANSACTION) |
|
|
|
|
.detachedCopy(); |
|
|
|
|
System.out.println(txBlob.getSender()); |
|
|
|
|
System.out.println(txBlob.getHash()); |
|
|
|
|
System.out.println(txBlob.getSize()); |
|
|
|
|
|
|
|
|
|
final BlobsWithCommitments bwc = txBlob.getBlobsWithCommitments().get(); |
|
|
|
|
final ClassLayout cl = ClassLayout.parseInstance(bwc); |
|
|
|
|
System.out.println(cl.toPrintable()); |
|
|
|
|
System.out.println("BlobsWithCommitments size: " + cl.instanceSize()); |
|
|
|
|
|
|
|
|
|
assertThat(cl.instanceSize()).isEqualTo(PendingTransaction.BLOBS_WITH_COMMITMENTS_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void pendingTransactionSize() { |
|
|
|
|
|
|
|
|
|
TransactionTestFixture preparedTx = |
|
|
|
|
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), 10); |
|
|
|
|
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), 10, 0); |
|
|
|
|
Transaction txPayload = preparedTx.createTransaction(KEYS1); |
|
|
|
|
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); |
|
|
|
|
txPayload.writeTo(rlpOut); |
|
|
|
|
|
|
|
|
|
txPayload = Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)); |
|
|
|
|
txPayload = |
|
|
|
|
Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)).detachedCopy(); |
|
|
|
|
System.out.println(txPayload.getSender()); |
|
|
|
|
System.out.println(txPayload.getHash()); |
|
|
|
|
System.out.println(txPayload.getSize()); |
|
|
|
@ -176,12 +296,13 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo |
|
|
|
|
final List<AccessListEntry> ales = List.of(ale1); |
|
|
|
|
|
|
|
|
|
TransactionTestFixture preparedTx = |
|
|
|
|
prepareTransaction(TransactionType.ACCESS_LIST, 0, Wei.of(500), 0); |
|
|
|
|
prepareTransaction(TransactionType.ACCESS_LIST, 0, Wei.of(500), 0, 0); |
|
|
|
|
Transaction txAccessList = preparedTx.accessList(ales).createTransaction(KEYS1); |
|
|
|
|
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); |
|
|
|
|
txAccessList.writeTo(rlpOut); |
|
|
|
|
|
|
|
|
|
txAccessList = Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)); |
|
|
|
|
txAccessList = |
|
|
|
|
Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)).detachedCopy(); |
|
|
|
|
System.out.println(txAccessList.getSender()); |
|
|
|
|
System.out.println(txAccessList.getHash()); |
|
|
|
|
System.out.println(txAccessList.getSize()); |
|
|
|
@ -200,55 +321,11 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo |
|
|
|
|
|
|
|
|
|
final AccessListEntry ale = optAL.get().get(0); |
|
|
|
|
|
|
|
|
|
final ClassLayout cl3 = ClassLayout.parseInstance(ale); |
|
|
|
|
System.out.println(cl3.toPrintable()); |
|
|
|
|
System.out.println("AccessListEntry size: " + cl3.instanceSize()); |
|
|
|
|
|
|
|
|
|
LongAdder size = new LongAdder(); |
|
|
|
|
size.add(cl3.instanceSize()); |
|
|
|
|
|
|
|
|
|
GraphVisitor gv = |
|
|
|
|
gpr -> { |
|
|
|
|
// byte[] is shared so only count the specific part for each field
|
|
|
|
|
if (gpr.path().endsWith(".bytes")) { |
|
|
|
|
if (gpr.path().contains("address")) { |
|
|
|
|
size.add(20); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ size |
|
|
|
|
+ ")[20 = fixed address size; overrides: " |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
} |
|
|
|
|
} else if (!gpr.path() |
|
|
|
|
.contains( |
|
|
|
|
"storageKeys.elementData[")) { // exclude elements since we want the container
|
|
|
|
|
// size
|
|
|
|
|
size.add(gpr.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ size |
|
|
|
|
+ ")[" |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
GraphWalker gw = new GraphWalker(gv); |
|
|
|
|
|
|
|
|
|
gw.walk(ale); |
|
|
|
|
long aleSize = sizeOfField(ale, "storageKeys.elementData["); |
|
|
|
|
|
|
|
|
|
System.out.println("AccessListEntry container size: " + size); |
|
|
|
|
System.out.println("AccessListEntry container size: " + aleSize); |
|
|
|
|
|
|
|
|
|
assertThat(size.sum()).isEqualTo(PendingTransaction.ACCESS_LIST_ENTRY_BASE_MEMORY_SIZE); |
|
|
|
|
assertThat(aleSize).isEqualTo(PendingTransaction.ACCESS_LIST_ENTRY_BASE_MEMORY_SIZE); |
|
|
|
|
|
|
|
|
|
final Bytes32 storageKey = ale.storageKeys().get(0); |
|
|
|
|
final ClassLayout cl4 = ClassLayout.parseInstance(storageKey); |
|
|
|
@ -260,13 +337,14 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void baseEIP1559TransactionMemorySize() { |
|
|
|
|
public void baseEIP1559AndEIP4844TransactionMemorySize() { |
|
|
|
|
System.setProperty("jol.magicFieldOffset", "true"); |
|
|
|
|
Transaction txEip1559 = createEIP1559Transaction(1, KEYS1, 10); |
|
|
|
|
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); |
|
|
|
|
txEip1559.writeTo(rlpOut); |
|
|
|
|
|
|
|
|
|
txEip1559 = Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)); |
|
|
|
|
txEip1559 = |
|
|
|
|
Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)).detachedCopy(); |
|
|
|
|
System.out.println(txEip1559.getSender()); |
|
|
|
|
System.out.println(txEip1559.getHash()); |
|
|
|
|
System.out.println(txEip1559.getSize()); |
|
|
|
@ -277,138 +355,141 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo |
|
|
|
|
eip1559size.add(cl.instanceSize()); |
|
|
|
|
System.out.println(eip1559size); |
|
|
|
|
|
|
|
|
|
final Set<String> skipPrefixes = new HashSet<>(); |
|
|
|
|
|
|
|
|
|
GraphVisitor gv = |
|
|
|
|
gpr -> { |
|
|
|
|
if (!skipPrefixes.stream().anyMatch(sp -> gpr.path().startsWith(sp))) { |
|
|
|
|
if (SHARED_CLASSES.stream().anyMatch(scz -> scz.isAssignableFrom(gpr.klass()))) { |
|
|
|
|
skipPrefixes.add(gpr.path()); |
|
|
|
|
} else if (!startWithAnyOf(EIP1559_CONSTANT_FIELD_PATHS, gpr) |
|
|
|
|
&& !startWithAnyOf(EIP1559_VARIABLE_SIZE_PATHS, gpr)) { |
|
|
|
|
eip1559size.add(gpr.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ eip1559size |
|
|
|
|
+ ")[" |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
GraphWalker gw = new GraphWalker(gv); |
|
|
|
|
final SortedSet<FieldSize> fieldSizes = new TreeSet<>(); |
|
|
|
|
GraphWalker gw = getGraphWalker(EIP1559_EIP4844_CONSTANT_FIELD_PATHS, fieldSizes); |
|
|
|
|
|
|
|
|
|
gw.walk(txEip1559); |
|
|
|
|
|
|
|
|
|
fieldSizes.forEach( |
|
|
|
|
fieldSize -> { |
|
|
|
|
eip1559size.add(fieldSize.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ eip1559size |
|
|
|
|
+ ")[" |
|
|
|
|
+ fieldSize.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ fieldSize.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ fieldSize |
|
|
|
|
+ "]"); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
System.out.println("Base EIP1559 size: " + eip1559size); |
|
|
|
|
assertThat(eip1559size.sum()).isEqualTo(PendingTransaction.EIP1559_BASE_MEMORY_SIZE); |
|
|
|
|
assertThat(eip1559size.sum()) |
|
|
|
|
.isEqualTo(PendingTransaction.EIP1559_AND_EIP4844_BASE_MEMORY_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void baseAccessListTransactionMemorySize() { |
|
|
|
|
public void baseFrontierAndAccessListTransactionMemorySize() { |
|
|
|
|
System.setProperty("jol.magicFieldOffset", "true"); |
|
|
|
|
Transaction txAccessList = |
|
|
|
|
createTransaction(TransactionType.ACCESS_LIST, 1, Wei.of(500), 0, KEYS1); |
|
|
|
|
Transaction txFrontier = createTransaction(TransactionType.FRONTIER, 1, Wei.of(500), 0, KEYS1); |
|
|
|
|
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); |
|
|
|
|
txAccessList.writeTo(rlpOut); |
|
|
|
|
txFrontier.writeTo(rlpOut); |
|
|
|
|
|
|
|
|
|
txAccessList = Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)); |
|
|
|
|
System.out.println(txAccessList.getSender()); |
|
|
|
|
System.out.println(txAccessList.getHash()); |
|
|
|
|
System.out.println(txAccessList.getSize()); |
|
|
|
|
txFrontier = |
|
|
|
|
Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)).detachedCopy(); |
|
|
|
|
System.out.println(txFrontier.getSender()); |
|
|
|
|
System.out.println(txFrontier.getHash()); |
|
|
|
|
System.out.println(txFrontier.getSize()); |
|
|
|
|
|
|
|
|
|
final ClassLayout cl = ClassLayout.parseInstance(txAccessList); |
|
|
|
|
final ClassLayout cl = ClassLayout.parseInstance(txFrontier); |
|
|
|
|
System.out.println(cl.toPrintable()); |
|
|
|
|
LongAdder accessListSize = new LongAdder(); |
|
|
|
|
accessListSize.add(cl.instanceSize()); |
|
|
|
|
System.out.println(accessListSize); |
|
|
|
|
LongAdder frontierSize = new LongAdder(); |
|
|
|
|
frontierSize.add(cl.instanceSize()); |
|
|
|
|
System.out.println(frontierSize); |
|
|
|
|
|
|
|
|
|
final Set<String> skipPrefixes = new HashSet<>(); |
|
|
|
|
final SortedSet<FieldSize> fieldSizes = new TreeSet<>(); |
|
|
|
|
|
|
|
|
|
GraphWalker gw = getGraphWalker(FRONTIER_ACCESS_LIST_CONSTANT_FIELD_PATHS, fieldSizes); |
|
|
|
|
|
|
|
|
|
gw.walk(txFrontier); |
|
|
|
|
|
|
|
|
|
fieldSizes.forEach( |
|
|
|
|
fieldSize -> { |
|
|
|
|
frontierSize.add(fieldSize.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ frontierSize |
|
|
|
|
+ ")[" |
|
|
|
|
+ fieldSize.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ fieldSize.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ fieldSize |
|
|
|
|
+ "]"); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
System.out.println("Base Frontier size: " + frontierSize); |
|
|
|
|
assertThat(frontierSize.sum()) |
|
|
|
|
.isEqualTo(PendingTransaction.FRONTIER_AND_ACCESS_LIST_BASE_MEMORY_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private GraphWalker getGraphWalker( |
|
|
|
|
final Set<String> constantFieldPaths, final SortedSet<FieldSize> fieldSizes) { |
|
|
|
|
final Set<String> skipPrefixes = new HashSet<>(); |
|
|
|
|
GraphVisitor gv = |
|
|
|
|
gpr -> { |
|
|
|
|
if (!skipPrefixes.stream().anyMatch(sp -> gpr.path().startsWith(sp))) { |
|
|
|
|
if (SHARED_CLASSES.stream().anyMatch(scz -> scz.isAssignableFrom(gpr.klass()))) { |
|
|
|
|
skipPrefixes.add(gpr.path()); |
|
|
|
|
} else if (!startWithAnyOf(FRONTIER_ACCESS_LIST_CONSTANT_FIELD_PATHS, gpr) |
|
|
|
|
&& !startWithAnyOf(FRONTIER_ACCESS_LIST_VARIABLE_SIZE_PATHS, gpr)) { |
|
|
|
|
accessListSize.add(gpr.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ accessListSize |
|
|
|
|
+ ")[" |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
} else if (!startWithAnyOf(constantFieldPaths, gpr) |
|
|
|
|
&& !startWithAnyOf(VARIABLE_SIZE_PATHS, gpr)) { |
|
|
|
|
|
|
|
|
|
fieldSizes.add(new FieldSize(gpr.path(), gpr.klass(), gpr.size())); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
GraphWalker gw = new GraphWalker(gv); |
|
|
|
|
|
|
|
|
|
gw.walk(txAccessList); |
|
|
|
|
System.out.println("Base Access List size: " + accessListSize); |
|
|
|
|
assertThat(accessListSize.sum()).isEqualTo(PendingTransaction.ACCESS_LIST_BASE_MEMORY_SIZE); |
|
|
|
|
return gw; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void baseFrontierTransactionMemorySize() { |
|
|
|
|
System.setProperty("jol.magicFieldOffset", "true"); |
|
|
|
|
Transaction txFrontier = createTransaction(TransactionType.FRONTIER, 1, Wei.of(500), 0, KEYS1); |
|
|
|
|
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); |
|
|
|
|
txFrontier.writeTo(rlpOut); |
|
|
|
|
|
|
|
|
|
txFrontier = Transaction.readFrom(new BytesValueRLPInput(rlpOut.encoded(), false)); |
|
|
|
|
System.out.println(txFrontier.getSender()); |
|
|
|
|
System.out.println(txFrontier.getHash()); |
|
|
|
|
System.out.println(txFrontier.getSize()); |
|
|
|
|
private boolean startWithAnyOf(final Set<String> prefixes, final GraphPathRecord path) { |
|
|
|
|
return prefixes.stream().anyMatch(prefix -> path.path().startsWith(prefix)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
final ClassLayout cl = ClassLayout.parseInstance(txFrontier); |
|
|
|
|
private long sizeOfField(final Object container, final String... excludePaths) { |
|
|
|
|
final ClassLayout cl = ClassLayout.parseInstance(container); |
|
|
|
|
System.out.println(cl.toPrintable()); |
|
|
|
|
LongAdder frontierSize = new LongAdder(); |
|
|
|
|
frontierSize.add(cl.instanceSize()); |
|
|
|
|
System.out.println(frontierSize); |
|
|
|
|
System.out.println("Base container size: " + cl.instanceSize()); |
|
|
|
|
|
|
|
|
|
final Set<String> skipPrefixes = new HashSet<>(); |
|
|
|
|
LongAdder size = new LongAdder(); |
|
|
|
|
size.add(cl.instanceSize()); |
|
|
|
|
|
|
|
|
|
GraphVisitor gv = |
|
|
|
|
gpr -> { |
|
|
|
|
if (!skipPrefixes.stream().anyMatch(sp -> gpr.path().startsWith(sp))) { |
|
|
|
|
if (SHARED_CLASSES.stream().anyMatch(scz -> scz.isAssignableFrom(gpr.klass()))) { |
|
|
|
|
skipPrefixes.add(gpr.path()); |
|
|
|
|
} else if (!startWithAnyOf(FRONTIER_ACCESS_LIST_CONSTANT_FIELD_PATHS, gpr) |
|
|
|
|
&& !startWithAnyOf(FRONTIER_ACCESS_LIST_VARIABLE_SIZE_PATHS, gpr)) { |
|
|
|
|
frontierSize.add(gpr.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ frontierSize |
|
|
|
|
+ ")[" |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
} |
|
|
|
|
if (Arrays.stream(excludePaths) |
|
|
|
|
.anyMatch(excludePath -> gpr.path().contains(excludePath))) { |
|
|
|
|
System.out.println("Excluded path " + gpr.path()); |
|
|
|
|
} else { |
|
|
|
|
size.add(gpr.size()); |
|
|
|
|
System.out.println( |
|
|
|
|
"(" |
|
|
|
|
+ size |
|
|
|
|
+ ")[" |
|
|
|
|
+ gpr.size() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.path() |
|
|
|
|
+ ", " |
|
|
|
|
+ gpr.klass().toString() |
|
|
|
|
+ "]"); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
GraphWalker gw = new GraphWalker(gv); |
|
|
|
|
|
|
|
|
|
gw.walk(txFrontier); |
|
|
|
|
System.out.println("Base Frontier size: " + frontierSize); |
|
|
|
|
assertThat(frontierSize.sum()).isEqualTo(PendingTransaction.FRONTIER_BASE_MEMORY_SIZE); |
|
|
|
|
gw.walk(container); |
|
|
|
|
|
|
|
|
|
System.out.println("Container size: " + size); |
|
|
|
|
return size.sum(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private boolean startWithAnyOf(final Set<String> prefixes, final GraphPathRecord path) { |
|
|
|
|
return prefixes.stream().anyMatch(prefix -> path.path().startsWith(prefix)); |
|
|
|
|
record FieldSize(String path, Class<?> clazz, long size) implements Comparable<FieldSize> { |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public int compareTo(final FieldSize o) { |
|
|
|
|
return path.compareTo(o.path); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|