Skip to content

Commit

Permalink
Support code delegations when purging confirmed blocks in the layered…
Browse files Browse the repository at this point in the history
… txpool

Signed-off-by: Fabio Di Fabio <[email protected]>
  • Loading branch information
fab-10 committed Dec 17, 2024
1 parent 49ed3ce commit 3f11111
Show file tree
Hide file tree
Showing 8 changed files with 321 additions and 67 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

### Additions and Improvements
- Retrieve all transaction receipts for a block in one request [#6646](https://github.com/hyperledger/besu/pull/6646)
- Add support for EIP-7702 transaction in the txpool [#8018](https://github.com/hyperledger/besu/pull/8018) [#7984](https://github.com/hyperledger/besu/pull/7984)

### Bug fixes
- Fix serialization of state overrides when `movePrecompileToAddress` is present [#8204](https://github.com/hyperledger/besu/pull/8024)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,35 @@
*/
package org.hyperledger.besu.ethereum.core;

import org.hyperledger.besu.crypto.CodeDelegationSignature;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationTransactionEncoder;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;

import java.math.BigInteger;
import java.util.List;
import java.util.Optional;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes;

public class TransactionTestFixture {
private final SECPSignature signature =
new SECPSignature(BigInteger.ONE, BigInteger.ONE, (byte) 0);
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
private static final KeyPair KEY_PAIR = SIGNATURE_ALGORITHM.get().generateKeyPair();
private static final org.hyperledger.besu.datatypes.CodeDelegation CODE_DELEGATION =
createSignedCodeDelegation(BigInteger.ZERO, Address.ZERO, 0, KEY_PAIR);

private TransactionType transactionType = TransactionType.FRONTIER;

private long nonce = 0;
Expand Down Expand Up @@ -100,9 +111,7 @@ public Transaction createTransaction(final KeyPair keys) {
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))));
builder.codeDelegations(codeDelegations.orElse(List.of(CODE_DELEGATION)));
break;
}

Expand Down Expand Up @@ -196,7 +205,28 @@ public TransactionTestFixture blobsWithCommitments(final Optional<BlobsWithCommi

public TransactionTestFixture codeDelegations(
final List<org.hyperledger.besu.datatypes.CodeDelegation> codeDelegations) {
this.codeDelegations = Optional.of(codeDelegations);
this.codeDelegations = Optional.ofNullable(codeDelegations);
return this;
}

public static CodeDelegation createSignedCodeDelegation(
final BigInteger chainId, final Address address, final long nonce, final KeyPair keys) {
BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
CodeDelegationTransactionEncoder.encodeSingleCodeDelegationWithoutSignature(
new org.hyperledger.besu.ethereum.core.CodeDelegation(chainId, address, nonce, null),
rlpOutput);

final Hash hash =
Hash.hash(
Bytes.concatenate(
org.hyperledger.besu.ethereum.core.CodeDelegation.MAGIC, rlpOutput.encoded()));

final var signature = SIGNATURE_ALGORITHM.get().sign(hash, keys);

return new org.hyperledger.besu.ethereum.core.CodeDelegation(
chainId,
address,
nonce,
CodeDelegationSignature.create(signature.getR(), signature.getS(), signature.getRecId()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ public interface MemorySize {
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 = 472;
int CODE_DELEGATION_ENTRY_SIZE = 520;
int VERSIONED_HASH_SIZE = 96;
int LIST_SHALLOW_SIZE = 48;
int OPTIONAL_SHALLOW_SIZE = 16;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ public OptionalLong getNextNonceForSender(final Address sender) {
}

@Override
public synchronized void manageBlockAdded(
public void manageBlockAdded(
final BlockHeader blockHeader,
final List<Transaction> confirmedTransactions,
final List<Transaction> reorgTransactions,
Expand All @@ -447,19 +447,21 @@ public synchronized void manageBlockAdded(

final var reorgNonceRangeBySender = nonceRangeBySender(reorgTransactions);

try {
prioritizedTransactions.blockAdded(feeMarket, blockHeader, maxConfirmedNonceBySender);
} catch (final Throwable throwable) {
LOG.warn(
"Unexpected error {} when managing added block {}, maxNonceBySender {}, reorgNonceRangeBySender {}",
throwable,
blockHeader.toLogString(),
maxConfirmedNonceBySender,
reorgTransactions);
LOG.warn("Stack trace", throwable);
}
synchronized (this) {
try {
prioritizedTransactions.blockAdded(feeMarket, blockHeader, maxConfirmedNonceBySender);
} catch (final Throwable throwable) {
LOG.warn(
"Unexpected error {} when managing added block {}, maxNonceBySender {}, reorgNonceRangeBySender {}",
throwable,
blockHeader.toLogString(),
maxConfirmedNonceBySender,
reorgTransactions);
LOG.warn("Stack trace", throwable);
}

logBlockHeaderForReplay(blockHeader, maxConfirmedNonceBySender, reorgNonceRangeBySender);
logBlockHeaderForReplay(blockHeader, maxConfirmedNonceBySender, reorgNonceRangeBySender);
}
}

private void logBlockHeaderForReplay(
Expand Down Expand Up @@ -498,10 +500,25 @@ private void logBlockHeaderForReplay(
}

private Map<Address, Long> maxNonceBySender(final List<Transaction> confirmedTransactions) {
record SenderNonce(Address sender, long nonce) {}

return confirmedTransactions.stream()
.<SenderNonce>mapMulti(
(transaction, consumer) -> {
// always consider the sender
consumer.accept(new SenderNonce(transaction.getSender(), transaction.getNonce()));

// and if a code delegation tx also the authorities
if (transaction.getType().supportsDelegateCode()) {
transaction.getCodeDelegationList().get().stream()
.map(cd -> cd.authorizer().map(address -> new SenderNonce(address, cd.nonce())))
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(consumer);
}
})
.collect(
groupingBy(
Transaction::getSender, mapping(Transaction::getNonce, reducing(0L, Math::max))));
groupingBy(SenderNonce::sender, mapping(SenderNonce::nonce, reducing(0L, Math::max))));
}

private Map<Address, LongRange> nonceRangeBySender(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo
@Test
public void toSize() {
TransactionTestFixture preparedTx =
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), Wei.ZERO, 10, 0);
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), Wei.ZERO, 10, 0, null);
Transaction txTo =
preparedTx.to(Optional.of(Address.extract(Bytes32.random()))).createTransaction(KEYS1);
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput();
Expand Down Expand Up @@ -187,7 +187,7 @@ public void toSize() {
public void payloadSize() {

TransactionTestFixture preparedTx =
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), Wei.ZERO, 10, 0);
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), Wei.ZERO, 10, 0, null);
Transaction txPayload = preparedTx.createTransaction(KEYS1);
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput();
txPayload.writeTo(rlpOut);
Expand Down Expand Up @@ -277,7 +277,7 @@ private void blobsWithCommitmentsFieldSize(
final long containerSize,
final long itemSize) {
TransactionTestFixture preparedTx =
prepareTransaction(TransactionType.BLOB, 10, Wei.of(500), Wei.of(50), 10, 1);
prepareTransaction(TransactionType.BLOB, 10, Wei.of(500), Wei.of(50), 10, 1, null);
Transaction txBlob = preparedTx.createTransaction(KEYS1);
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput();
TransactionEncoder.encodeRLP(txBlob, rlpOut, EncodingContext.POOLED_TRANSACTION);
Expand Down Expand Up @@ -309,7 +309,7 @@ private void blobsWithCommitmentsFieldSize(
@Test
public void blobsWithCommitmentsSize() {
TransactionTestFixture preparedTx =
prepareTransaction(TransactionType.BLOB, 10, Wei.of(500), Wei.of(50), 10, 1);
prepareTransaction(TransactionType.BLOB, 10, Wei.of(500), Wei.of(50), 10, 1, null);
Transaction txBlob = preparedTx.createTransaction(KEYS1);
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput();
TransactionEncoder.encodeRLP(txBlob, rlpOut, EncodingContext.POOLED_TRANSACTION);
Expand Down Expand Up @@ -337,7 +337,7 @@ public void blobsWithCommitmentsSize() {
public void pendingTransactionSize() {

TransactionTestFixture preparedTx =
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), Wei.ZERO, 10, 0);
prepareTransaction(TransactionType.ACCESS_LIST, 10, Wei.of(500), Wei.ZERO, 10, 0, null);
Transaction txPayload = preparedTx.createTransaction(KEYS1);
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput();
txPayload.writeTo(rlpOut);
Expand Down Expand Up @@ -369,7 +369,7 @@ public void accessListSize() {
final List<AccessListEntry> ales = List.of(ale1);

TransactionTestFixture preparedTx =
prepareTransaction(TransactionType.ACCESS_LIST, 0, Wei.of(500), Wei.ZERO, 0, 0);
prepareTransaction(TransactionType.ACCESS_LIST, 0, Wei.of(500), Wei.ZERO, 0, 0, null);
Transaction txAccessList = preparedTx.accessList(ales).createTransaction(KEYS1);
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput();
txAccessList.writeTo(rlpOut);
Expand Down Expand Up @@ -416,7 +416,14 @@ public void codeDelegationListSize() {
System.setProperty("jol.magicFieldOffset", "true");

TransactionTestFixture preparedTx =
prepareTransaction(TransactionType.DELEGATE_CODE, 0, Wei.of(500), Wei.ZERO, 0, 0);
prepareTransaction(
TransactionType.DELEGATE_CODE,
0,
Wei.of(500),
Wei.ZERO,
0,
0,
List.of(CODE_DELEGATION_SENDER_1));
Transaction txDelegateCode = preparedTx.createTransaction(KEYS1);
BytesValueRLPOutput rlpOut = new BytesValueRLPOutput();
txDelegateCode.writeTo(rlpOut);
Expand Down Expand Up @@ -461,7 +468,7 @@ public void baseEIP1559AndEIP4844TransactionMemorySize() {
@Test
public void baseFrontierAndAccessListTransactionMemorySize() {
final Transaction txFrontier =
createTransaction(TransactionType.FRONTIER, 1, Wei.of(500), 0, KEYS1);
createTransaction(TransactionType.FRONTIER, 1, Wei.of(500), 0, List.of(), KEYS1);
assertThat(baseTransactionMemorySize(txFrontier, FRONTIER_ACCESS_LIST_CONSTANT_FIELD_PATHS))
.isEqualTo(FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE);
}
Expand Down Expand Up @@ -575,15 +582,18 @@ private long sizeOfField(final Object container, final String... excludePaths) {
*
* @param filePath where to save the heap dump
* @param live true to only include live objects
* @throws IOException if any errors happen during the saving
*/
@SuppressWarnings("unused")
private static void dumpHeap(final String filePath, final boolean live) throws IOException {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean mxBean =
ManagementFactory.newPlatformMXBeanProxy(
server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
mxBean.dumpHeap(filePath, live);
private static void dumpHeap(final String filePath, final boolean live) {
try {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean mxBean =
ManagementFactory.newPlatformMXBeanProxy(
server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
mxBean.dumpHeap(filePath, live);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

record FieldSize(String path, Class<?> clazz, long size) implements Comparable<FieldSize> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ protected Transaction createTransactionReplacement(
originalTransaction.getMaxGasPrice().multiply(2).divide(10),
originalTransaction.getPayload().size(),
originalTransaction.getBlobCount(),
originalTransaction.getCodeDelegationList().orElse(List.of()),
keys);
}

Expand Down Expand Up @@ -191,7 +192,7 @@ public void txWithEffectiveGasPriceBelowCurrentMineableMinGasPriceIsNotPrioritiz
final TransactionType type) {
final PendingTransaction lowGasPriceTx =
createRemotePendingTransaction(
createTransaction(type, 0, DEFAULT_MIN_GAS_PRICE, Wei.ONE, 0, 1, KEYS1));
createTransaction(type, 0, DEFAULT_MIN_GAS_PRICE, Wei.ONE, 0, 1, List.of(), KEYS1));
assertThat(prioritizeTransaction(lowGasPriceTx)).isEqualTo(DROPPED);
assertEvicted(lowGasPriceTx);
assertTransactionNotPrioritized(lowGasPriceTx);
Expand All @@ -217,6 +218,7 @@ public void shouldPrioritizePriorityFeeThenTimeAddedToPoolSameTypeTxs(
0,
DEFAULT_MIN_GAS_PRICE.add(1).multiply(20),
0,
List.of(),
SIGNATURE_ALGORITHM.get().generateKeyPair())))
.collect(Collectors.toUnmodifiableList());

Expand All @@ -238,6 +240,7 @@ public void maxNumberOfTxsForTypeIsEnforced() {
DEFAULT_MIN_GAS_PRICE.divide(10),
0,
1,
List.of(),
SIGNATURE_ALGORITHM.get().generateKeyPair());
addedTxs.add(tx);
assertThat(prioritizeTransaction(tx)).isEqualTo(ADDED);
Expand All @@ -251,6 +254,7 @@ public void maxNumberOfTxsForTypeIsEnforced() {
DEFAULT_MIN_GAS_PRICE.divide(10),
0,
1,
List.of(),
SIGNATURE_ALGORITHM.get().generateKeyPair());
assertThat(prioritizeTransaction(overflowTx)).isEqualTo(DROPPED);

Expand All @@ -272,6 +276,7 @@ public void maxNumberOfTxsForTypeWithReplacement() {
DEFAULT_MIN_GAS_PRICE.divide(10),
0,
1,
List.of(),
KEYS1);
addedTxs.add(tx);
assertThat(prioritizeTransaction(tx)).isEqualTo(ADDED);
Expand Down
Loading

0 comments on commit 3f11111

Please sign in to comment.