mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-09 22:07:59 -05:00
Blob transaction replacement rule (#6874)
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
- Experimental Snap Sync Server [#6640](https://github.com/hyperledger/besu/pull/6640)
|
||||
- Upgrade Reference Tests to 13.2 [#6854](https://github.com/hyperledger/besu/pull/6854)
|
||||
- Update Web3j dependencies [#6811](https://github.com/hyperledger/besu/pull/6811)
|
||||
- Add `tx-pool-blob-price-bump` option to configure the price bump percentage required to replace blob transactions (by default 100%) [#6874](https://github.com/hyperledger/besu/pull/6874)
|
||||
|
||||
### Bug fixes
|
||||
- Fix txpool dump/restore race condition [#6665](https://github.com/hyperledger/besu/pull/6665)
|
||||
|
||||
@@ -52,6 +52,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
|
||||
private static final String TX_POOL_ENABLE_SAVE_RESTORE = "--tx-pool-enable-save-restore";
|
||||
private static final String TX_POOL_SAVE_FILE = "--tx-pool-save-file";
|
||||
private static final String TX_POOL_PRICE_BUMP = "--tx-pool-price-bump";
|
||||
private static final String TX_POOL_BLOB_PRICE_BUMP = "--tx-pool-blob-price-bump";
|
||||
private static final String RPC_TX_FEECAP = "--rpc-tx-feecap";
|
||||
private static final String STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG =
|
||||
"--strict-tx-replay-protection-enabled";
|
||||
@@ -102,6 +103,15 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
|
||||
arity = "1")
|
||||
private Percentage priceBump = TransactionPoolConfiguration.DEFAULT_PRICE_BUMP;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {TX_POOL_BLOB_PRICE_BUMP},
|
||||
paramLabel = "<Percentage>",
|
||||
converter = PercentageConverter.class,
|
||||
description =
|
||||
"Blob price bump percentage to replace an already existing transaction blob tx (default: ${DEFAULT-VALUE})",
|
||||
arity = "1")
|
||||
private Percentage blobPriceBump = TransactionPoolConfiguration.DEFAULT_BLOB_PRICE_BUMP;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {RPC_TX_FEECAP},
|
||||
description =
|
||||
@@ -277,6 +287,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
|
||||
options.saveRestoreEnabled = config.getEnableSaveRestore();
|
||||
options.noLocalPriority = config.getNoLocalPriority();
|
||||
options.priceBump = config.getPriceBump();
|
||||
options.blobPriceBump = config.getBlobPriceBump();
|
||||
options.txFeeCap = config.getTxFeeCap();
|
||||
options.saveFile = config.getSaveFile();
|
||||
options.strictTxReplayProtectionEnabled = config.getStrictTransactionReplayProtectionEnabled();
|
||||
@@ -334,6 +345,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
|
||||
.enableSaveRestore(saveRestoreEnabled)
|
||||
.noLocalPriority(noLocalPriority)
|
||||
.priceBump(priceBump)
|
||||
.blobPriceBump(blobPriceBump)
|
||||
.txFeeCap(txFeeCap)
|
||||
.saveFile(saveFile)
|
||||
.strictTransactionReplayProtectionEnabled(strictTxReplayProtectionEnabled)
|
||||
|
||||
@@ -168,6 +168,31 @@ public class TransactionPoolOptionsTest
|
||||
"101");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blobPriceBump() {
|
||||
final Percentage blobPriceBump = Percentage.fromInt(50);
|
||||
internalTestSuccess(
|
||||
config -> assertThat(config.getBlobPriceBump()).isEqualTo(blobPriceBump),
|
||||
"--tx-pool-blob-price-bump",
|
||||
blobPriceBump.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidBlobPriceBumpShouldFail() {
|
||||
internalTestFailure(
|
||||
"Invalid value: 101, should be a number between 0 and 100 inclusive",
|
||||
"--tx-pool-blob-price-bump",
|
||||
"101");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultBlobPriceBump() {
|
||||
internalTestSuccess(
|
||||
config ->
|
||||
assertThat(config.getBlobPriceBump())
|
||||
.isEqualTo(TransactionPoolConfiguration.DEFAULT_BLOB_PRICE_BUMP));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void txFeeCap() {
|
||||
final Wei txFeeCap = Wei.fromEth(2);
|
||||
|
||||
@@ -174,6 +174,7 @@ privacy-flexible-groups-enabled=false
|
||||
# Transaction Pool
|
||||
tx-pool="layered"
|
||||
tx-pool-price-bump=13
|
||||
tx-pool-blob-price-bump=100
|
||||
rpc-tx-feecap=2000000000000000000
|
||||
strict-tx-replay-protection-enabled=true
|
||||
tx-pool-no-local-priority=false
|
||||
|
||||
@@ -116,7 +116,8 @@ public abstract class AbstractIsolationTests {
|
||||
ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(100).build();
|
||||
|
||||
protected final TransactionPoolReplacementHandler transactionReplacementHandler =
|
||||
new TransactionPoolReplacementHandler(poolConfiguration.getPriceBump());
|
||||
new TransactionPoolReplacementHandler(
|
||||
poolConfiguration.getPriceBump(), poolConfiguration.getBlobPriceBump());
|
||||
|
||||
protected final BiFunction<PendingTransaction, PendingTransaction, Boolean>
|
||||
transactionReplacementTester =
|
||||
|
||||
@@ -64,6 +64,7 @@ public interface TransactionPoolConfiguration {
|
||||
int DEFAULT_TX_RETENTION_HOURS = 13;
|
||||
boolean DEFAULT_STRICT_TX_REPLAY_PROTECTION_ENABLED = false;
|
||||
Percentage DEFAULT_PRICE_BUMP = Percentage.fromInt(10);
|
||||
Percentage DEFAULT_BLOB_PRICE_BUMP = Percentage.fromInt(100);
|
||||
Wei DEFAULT_RPC_TX_FEE_CAP = Wei.fromEth(1);
|
||||
boolean DEFAULT_NO_LOCAL_PRIORITY = false;
|
||||
boolean DEFAULT_ENABLE_SAVE_RESTORE = false;
|
||||
@@ -102,6 +103,11 @@ public interface TransactionPoolConfiguration {
|
||||
return DEFAULT_PRICE_BUMP;
|
||||
}
|
||||
|
||||
@Value.Default
|
||||
default Percentage getBlobPriceBump() {
|
||||
return DEFAULT_BLOB_PRICE_BUMP;
|
||||
}
|
||||
|
||||
@Value.Default
|
||||
default Wei getTxFeeCap() {
|
||||
return DEFAULT_RPC_TX_FEE_CAP;
|
||||
|
||||
@@ -292,7 +292,9 @@ public class TransactionPoolFactory {
|
||||
final MiningParameters miningParameters) {
|
||||
|
||||
final TransactionPoolReplacementHandler transactionReplacementHandler =
|
||||
new TransactionPoolReplacementHandler(transactionPoolConfiguration.getPriceBump());
|
||||
new TransactionPoolReplacementHandler(
|
||||
transactionPoolConfiguration.getPriceBump(),
|
||||
transactionPoolConfiguration.getBlobPriceBump());
|
||||
|
||||
final BiFunction<PendingTransaction, PendingTransaction, Boolean> transactionReplacementTester =
|
||||
(t1, t2) ->
|
||||
|
||||
@@ -26,11 +26,12 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
public class TransactionPoolReplacementHandler {
|
||||
private final List<TransactionPoolReplacementRule> rules;
|
||||
|
||||
public TransactionPoolReplacementHandler(final Percentage priceBump) {
|
||||
public TransactionPoolReplacementHandler(
|
||||
final Percentage priceBump, final Percentage blobPriceBump) {
|
||||
this(
|
||||
asList(
|
||||
new TransactionReplacementByGasPriceRule(priceBump),
|
||||
new TransactionReplacementByFeeMarketRule(priceBump)));
|
||||
new TransactionReplacementByFeeMarketRule(priceBump, blobPriceBump)));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -28,9 +28,12 @@ public class TransactionReplacementByFeeMarketRule implements TransactionPoolRep
|
||||
private static final TransactionPriceCalculator EIP1559_CALCULATOR =
|
||||
TransactionPriceCalculator.eip1559();
|
||||
private final Percentage priceBump;
|
||||
private final Percentage blobPriceBump;
|
||||
|
||||
public TransactionReplacementByFeeMarketRule(final Percentage priceBump) {
|
||||
public TransactionReplacementByFeeMarketRule(
|
||||
final Percentage priceBump, final Percentage blobPriceBump) {
|
||||
this.priceBump = priceBump;
|
||||
this.blobPriceBump = blobPriceBump;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,6 +42,16 @@ public class TransactionReplacementByFeeMarketRule implements TransactionPoolRep
|
||||
final PendingTransaction newPendingTransaction,
|
||||
final Optional<Wei> maybeBaseFee) {
|
||||
|
||||
return validExecutionPriceReplacement(
|
||||
existingPendingTransaction, newPendingTransaction, maybeBaseFee)
|
||||
&& validBlobPriceReplacement(existingPendingTransaction, newPendingTransaction);
|
||||
}
|
||||
|
||||
private boolean validExecutionPriceReplacement(
|
||||
final PendingTransaction existingPendingTransaction,
|
||||
final PendingTransaction newPendingTransaction,
|
||||
final Optional<Wei> maybeBaseFee) {
|
||||
|
||||
// bail early if basefee is absent or neither transaction supports 1559 fee market
|
||||
if (maybeBaseFee.isEmpty()
|
||||
|| !(isNotGasPriced(existingPendingTransaction) || isNotGasPriced(newPendingTransaction))) {
|
||||
@@ -65,6 +78,37 @@ public class TransactionReplacementByFeeMarketRule implements TransactionPoolRep
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean validBlobPriceReplacement(
|
||||
final PendingTransaction existingPendingTransaction,
|
||||
final PendingTransaction newPendingTransaction) {
|
||||
|
||||
final var existingType = existingPendingTransaction.getTransaction().getType();
|
||||
final var newType = newPendingTransaction.getTransaction().getType();
|
||||
|
||||
if (existingType.supportsBlob() || newType.supportsBlob()) {
|
||||
if (existingType.supportsBlob() && newType.supportsBlob()) {
|
||||
final Wei replacementThreshold =
|
||||
existingPendingTransaction
|
||||
.getTransaction()
|
||||
.getMaxFeePerBlobGas()
|
||||
.orElseThrow()
|
||||
.multiply(100 + blobPriceBump.getValue())
|
||||
.divide(100);
|
||||
return newPendingTransaction
|
||||
.getTransaction()
|
||||
.getMaxFeePerBlobGas()
|
||||
.orElseThrow()
|
||||
.compareTo(replacementThreshold)
|
||||
>= 0;
|
||||
}
|
||||
// blob tx can only replace and be replaced by blob tx
|
||||
return false;
|
||||
}
|
||||
|
||||
// in case no blob tx, then we are fine
|
||||
return true;
|
||||
}
|
||||
|
||||
private Wei priceOf(final Transaction transaction, final Optional<Wei> maybeBaseFee) {
|
||||
final TransactionPriceCalculator transactionPriceCalculator =
|
||||
transaction.getType().supports1559FeeMarket() ? EIP1559_CALCULATOR : FRONTIER_CALCULATOR;
|
||||
|
||||
@@ -110,7 +110,8 @@ public abstract class AbstractPendingTransactionsSorter implements PendingTransa
|
||||
this.clock = clock;
|
||||
this.chainHeadHeaderSupplier = chainHeadHeaderSupplier;
|
||||
this.transactionReplacementHandler =
|
||||
new TransactionPoolReplacementHandler(poolConfig.getPriceBump());
|
||||
new TransactionPoolReplacementHandler(
|
||||
poolConfig.getPriceBump(), poolConfig.getBlobPriceBump());
|
||||
final LabelledMetric<Counter> transactionAddedCounter =
|
||||
metricsSystem.createLabelledCounter(
|
||||
BesuMetricCategory.TRANSACTION_POOL,
|
||||
|
||||
@@ -267,7 +267,8 @@ public abstract class AbstractTransactionPoolTest {
|
||||
final TransactionPoolConfiguration poolConfig = configBuilder.build();
|
||||
|
||||
final TransactionPoolReplacementHandler transactionReplacementHandler =
|
||||
new TransactionPoolReplacementHandler(poolConfig.getPriceBump());
|
||||
new TransactionPoolReplacementHandler(
|
||||
poolConfig.getPriceBump(), poolConfig.getBlobPriceBump());
|
||||
|
||||
final BiFunction<PendingTransaction, PendingTransaction, Boolean> transactionReplacementTester =
|
||||
(t1, t2) ->
|
||||
|
||||
@@ -18,10 +18,12 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.datatypes.TransactionType;
|
||||
import org.hyperledger.besu.datatypes.VersionedHash;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.core.Transaction;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
public class AbstractTransactionReplacementTest {
|
||||
protected static PendingTransaction frontierTx(final long price) {
|
||||
@@ -50,4 +52,20 @@ public class AbstractTransactionReplacementTest {
|
||||
when(pendingTransaction.getTransaction()).thenReturn(transaction);
|
||||
return pendingTransaction;
|
||||
}
|
||||
|
||||
protected static PendingTransaction blobTx(
|
||||
final long maxPriorityFeePerGas, final long maxFeePerGas, final long maxFeePerBlobGas) {
|
||||
final PendingTransaction pendingTransaction = mock(PendingTransaction.class);
|
||||
final Transaction transaction =
|
||||
Transaction.builder()
|
||||
.chainId(BigInteger.ZERO)
|
||||
.type(TransactionType.BLOB)
|
||||
.maxPriorityFeePerGas(Wei.of(maxPriorityFeePerGas))
|
||||
.maxFeePerGas(Wei.of(maxFeePerGas))
|
||||
.maxFeePerBlobGas(Wei.of(maxFeePerBlobGas))
|
||||
.versionedHashes(List.of(VersionedHash.DEFAULT_VERSIONED_HASH))
|
||||
.build();
|
||||
when(pendingTransaction.getTransaction()).thenReturn(transaction);
|
||||
return pendingTransaction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,52 +34,60 @@ public class TransactionReplacementByFeeMarketRuleTest extends AbstractTransacti
|
||||
new Object[][] {
|
||||
|
||||
// basefee absent
|
||||
{frontierTx(5L), frontierTx(6L), empty(), 0, false},
|
||||
{frontierTx(5L), frontierTx(5L), empty(), 0, false},
|
||||
{frontierTx(5L), frontierTx(4L), empty(), 0, false},
|
||||
{frontierTx(100L), frontierTx(105L), empty(), 10, false},
|
||||
{frontierTx(100L), frontierTx(110L), empty(), 10, false},
|
||||
{frontierTx(100L), frontierTx(111L), empty(), 10, false},
|
||||
{frontierTx(5L), frontierTx(6L), empty(), 0, 100, false},
|
||||
{frontierTx(5L), frontierTx(5L), empty(), 0, 100, false},
|
||||
{frontierTx(5L), frontierTx(4L), empty(), 0, 100, false},
|
||||
{frontierTx(100L), frontierTx(105L), empty(), 10, 100, false},
|
||||
{frontierTx(100L), frontierTx(110L), empty(), 10, 100, false},
|
||||
{frontierTx(100L), frontierTx(111L), empty(), 10, 100, false},
|
||||
// basefee present
|
||||
{frontierTx(5L), frontierTx(6L), Optional.of(Wei.of(3L)), 0, false},
|
||||
{frontierTx(5L), frontierTx(5L), Optional.of(Wei.of(3L)), 0, false},
|
||||
{frontierTx(5L), frontierTx(4L), Optional.of(Wei.of(3L)), 0, false},
|
||||
{frontierTx(100L), frontierTx(105L), Optional.of(Wei.of(3L)), 10, false},
|
||||
{frontierTx(100L), frontierTx(110L), Optional.of(Wei.of(3L)), 10, false},
|
||||
{frontierTx(100L), frontierTx(111L), Optional.of(Wei.of(3L)), 10, false},
|
||||
{frontierTx(5L), frontierTx(6L), Optional.of(Wei.of(3L)), 0, 100, false},
|
||||
{frontierTx(5L), frontierTx(5L), Optional.of(Wei.of(3L)), 0, 100, false},
|
||||
{frontierTx(5L), frontierTx(4L), Optional.of(Wei.of(3L)), 0, 100, false},
|
||||
{frontierTx(100L), frontierTx(105L), Optional.of(Wei.of(3L)), 10, 100, false},
|
||||
{frontierTx(100L), frontierTx(110L), Optional.of(Wei.of(3L)), 10, 100, false},
|
||||
{frontierTx(100L), frontierTx(111L), Optional.of(Wei.of(3L)), 10, 100, false},
|
||||
// eip1559 replacing frontier
|
||||
{frontierTx(5L), eip1559Tx(3L, 6L), Optional.of(Wei.of(1L)), 0, false},
|
||||
{frontierTx(5L), eip1559Tx(3L, 5L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{frontierTx(5L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{frontierTx(5L), eip1559Tx(3L, 6L), Optional.of(Wei.of(1L)), 0, 100, false},
|
||||
{frontierTx(5L), eip1559Tx(3L, 5L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{frontierTx(5L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
// frontier replacing 1559
|
||||
{eip1559Tx(3L, 8L), frontierTx(7L), Optional.of(Wei.of(4L)), 0, true},
|
||||
{eip1559Tx(3L, 8L), frontierTx(7L), Optional.of(Wei.of(5L)), 0, false},
|
||||
{eip1559Tx(3L, 8L), frontierTx(8L), Optional.of(Wei.of(4L)), 0, true},
|
||||
{eip1559Tx(3L, 8L), frontierTx(7L), Optional.of(Wei.of(4L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 8L), frontierTx(7L), Optional.of(Wei.of(5L)), 0, 100, false},
|
||||
{eip1559Tx(3L, 8L), frontierTx(8L), Optional.of(Wei.of(4L)), 0, 100, true},
|
||||
// eip1559 replacing eip1559
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(4L)), 0, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(5L)), 0, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(6L)), 0, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(7L)), 0, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(8L)), 0, true},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(10L, 200L), Optional.of(Wei.of(90L)), 10, false},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(15L, 200L), Optional.of(Wei.of(90L)), 10, false},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(20L, 200L), Optional.of(Wei.of(90L)), 10, true},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(20L, 200L), Optional.of(Wei.of(200L)), 10, true},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(10L, 220L), Optional.of(Wei.of(220L)), 10, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(4L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(5L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(6L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(7L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(8L)), 0, 100, true},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(10L, 200L), Optional.of(Wei.of(90L)), 10, 100, false},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(15L, 200L), Optional.of(Wei.of(90L)), 10, 100, false},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(20L, 200L), Optional.of(Wei.of(90L)), 10, 100, true},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(20L, 200L), Optional.of(Wei.of(200L)), 10, 100, true},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(10L, 220L), Optional.of(Wei.of(220L)), 10, 100, true},
|
||||
// pathological, priority fee > max fee
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 6L), Optional.of(Wei.of(2L)), 0, false},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(4L)), 0, true},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 6L), Optional.of(Wei.of(2L)), 0, 100, false},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(4L)), 0, 100, true},
|
||||
// pathological, eip1559 without basefee
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.empty(), 0, false},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.empty(), 0, false},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.empty(), 0, 100, false},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.empty(), 0, 100, false},
|
||||
// zero base fee market
|
||||
{frontierTx(0L), frontierTx(0L), Optional.of(Wei.ZERO), 0, false},
|
||||
{eip1559Tx(0L, 0L), frontierTx(0L), Optional.of(Wei.ZERO), 0, true},
|
||||
{frontierTx(0L), eip1559Tx(0L, 0L), Optional.of(Wei.ZERO), 0, true},
|
||||
{eip1559Tx(0L, 0L), eip1559Tx(0L, 0L), Optional.of(Wei.ZERO), 0, true},
|
||||
{frontierTx(0L), frontierTx(0L), Optional.of(Wei.ZERO), 0, 100, false},
|
||||
{eip1559Tx(0L, 0L), frontierTx(0L), Optional.of(Wei.ZERO), 0, 100, true},
|
||||
{frontierTx(0L), eip1559Tx(0L, 0L), Optional.of(Wei.ZERO), 0, 100, true},
|
||||
{eip1559Tx(0L, 0L), eip1559Tx(0L, 0L), Optional.of(Wei.ZERO), 0, 100, true},
|
||||
// blob tx
|
||||
{blobTx(10L, 200L, 1L), blobTx(20L, 220L, 1L), Optional.of(Wei.of(90L)), 10, 0, true},
|
||||
{blobTx(10L, 200L, 1L), blobTx(20L, 220L, 2L), Optional.of(Wei.of(90L)), 10, 100, true},
|
||||
{blobTx(10L, 200L, 1L), blobTx(20L, 220L, 1L), Optional.of(Wei.of(90L)), 10, 100, false},
|
||||
{blobTx(10L, 200L, 2L), blobTx(20L, 220L, 3L), Optional.of(Wei.of(90L)), 10, 100, false},
|
||||
// // blob tx must be replaced by blob tx only
|
||||
{blobTx(3L, 6L, 1L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, 0, false},
|
||||
{eip1559Tx(3L, 6L), blobTx(3L, 6L, 1L), Optional.of(Wei.of(3L)), 0, 0, false},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,10 +98,12 @@ public class TransactionReplacementByFeeMarketRuleTest extends AbstractTransacti
|
||||
final PendingTransaction newTx,
|
||||
final Optional<Wei> baseFee,
|
||||
final int priceBump,
|
||||
final int blobPriceBump,
|
||||
final boolean expected) {
|
||||
|
||||
assertThat(
|
||||
new TransactionReplacementByFeeMarketRule(Percentage.fromInt(priceBump))
|
||||
new TransactionReplacementByFeeMarketRule(
|
||||
Percentage.fromInt(priceBump), Percentage.fromInt(blobPriceBump))
|
||||
.shouldReplace(oldTx, newTx, baseFee))
|
||||
.isEqualTo(expected);
|
||||
}
|
||||
|
||||
@@ -37,46 +37,54 @@ public class TransactionReplacementRulesTest extends AbstractTransactionReplacem
|
||||
new Object[][] {
|
||||
// TransactionReplacementByGasPriceRule
|
||||
// basefee absent
|
||||
{frontierTx(5L), frontierTx(6L), empty(), 0, true},
|
||||
{frontierTx(5L), frontierTx(5L), empty(), 0, true},
|
||||
{frontierTx(5L), frontierTx(4L), empty(), 0, false},
|
||||
{frontierTx(100L), frontierTx(105L), empty(), 10, false},
|
||||
{frontierTx(100L), frontierTx(110L), empty(), 10, true},
|
||||
{frontierTx(100L), frontierTx(111L), empty(), 10, true},
|
||||
{frontierTx(5L), frontierTx(6L), empty(), 0, 100, true},
|
||||
{frontierTx(5L), frontierTx(5L), empty(), 0, 100, true},
|
||||
{frontierTx(5L), frontierTx(4L), empty(), 0, 100, false},
|
||||
{frontierTx(100L), frontierTx(105L), empty(), 10, 100, false},
|
||||
{frontierTx(100L), frontierTx(110L), empty(), 10, 100, true},
|
||||
{frontierTx(100L), frontierTx(111L), empty(), 10, 100, true},
|
||||
// basefee present
|
||||
{frontierTx(5L), frontierTx(6L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{frontierTx(5L), frontierTx(5L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{frontierTx(5L), frontierTx(4L), Optional.of(Wei.of(3L)), 0, false},
|
||||
{frontierTx(100L), frontierTx(105L), Optional.of(Wei.of(3L)), 10, false},
|
||||
{frontierTx(100L), frontierTx(110L), Optional.of(Wei.of(3L)), 10, true},
|
||||
{frontierTx(100L), frontierTx(111L), Optional.of(Wei.of(3L)), 10, true},
|
||||
{frontierTx(5L), frontierTx(6L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{frontierTx(5L), frontierTx(5L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{frontierTx(5L), frontierTx(4L), Optional.of(Wei.of(3L)), 0, 100, false},
|
||||
{frontierTx(100L), frontierTx(105L), Optional.of(Wei.of(3L)), 10, 100, false},
|
||||
{frontierTx(100L), frontierTx(110L), Optional.of(Wei.of(3L)), 10, 100, true},
|
||||
{frontierTx(100L), frontierTx(111L), Optional.of(Wei.of(3L)), 10, 100, true},
|
||||
// TransactionReplacementByFeeMarketRule
|
||||
// eip1559 replacing frontier
|
||||
{frontierTx(5L), eip1559Tx(3L, 6L), Optional.of(Wei.of(1L)), 0, false},
|
||||
{frontierTx(5L), eip1559Tx(3L, 5L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{frontierTx(5L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{frontierTx(5L), eip1559Tx(3L, 6L), Optional.of(Wei.of(1L)), 0, 100, false},
|
||||
{frontierTx(5L), eip1559Tx(3L, 5L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{frontierTx(5L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
// frontier replacing 1559
|
||||
{eip1559Tx(3L, 8L), frontierTx(6L), Optional.of(Wei.of(4L)), 0, false},
|
||||
{eip1559Tx(3L, 8L), frontierTx(7L), Optional.of(Wei.of(4L)), 0, true},
|
||||
{eip1559Tx(3L, 8L), frontierTx(8L), Optional.of(Wei.of(4L)), 0, true},
|
||||
{eip1559Tx(3L, 8L), frontierTx(6L), Optional.of(Wei.of(4L)), 0, 100, false},
|
||||
{eip1559Tx(3L, 8L), frontierTx(7L), Optional.of(Wei.of(4L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 8L), frontierTx(8L), Optional.of(Wei.of(4L)), 0, 100, true},
|
||||
// eip1559 replacing eip1559
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(4L)), 0, true},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(10L, 200L), Optional.of(Wei.of(90L)), 10, false},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(15L, 200L), Optional.of(Wei.of(90L)), 10, false},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(21L, 200L), Optional.of(Wei.of(90L)), 10, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{eip1559Tx(3L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(4L)), 0, 100, true},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(10L, 200L), Optional.of(Wei.of(90L)), 10, 100, false},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(15L, 200L), Optional.of(Wei.of(90L)), 10, 100, false},
|
||||
{eip1559Tx(10L, 200L), eip1559Tx(21L, 200L), Optional.of(Wei.of(90L)), 10, 100, true},
|
||||
// pathological, priority fee > max fee
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(3L)), 0, true},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(4L)), 0, true},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.of(Wei.of(4L)), 0, 100, true},
|
||||
// pathological, eip1559 without basefee
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.empty(), 0, false},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.empty(), 0, false},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.empty(), 0, 100, false},
|
||||
{eip1559Tx(8L, 6L), eip1559Tx(3L, 7L), Optional.empty(), 0, 100, false},
|
||||
// zero base fee market
|
||||
{frontierTx(0L), frontierTx(0L), Optional.of(Wei.ZERO), 0, true},
|
||||
{eip1559Tx(0L, 0L), frontierTx(0L), Optional.of(Wei.ZERO), 0, true},
|
||||
{frontierTx(0L), eip1559Tx(0L, 0L), Optional.of(Wei.ZERO), 0, true},
|
||||
{eip1559Tx(0L, 0L), eip1559Tx(0L, 0L), Optional.of(Wei.ZERO), 0, true},
|
||||
{frontierTx(0L), frontierTx(0L), Optional.of(Wei.ZERO), 0, 100, true},
|
||||
{eip1559Tx(0L, 0L), frontierTx(0L), Optional.of(Wei.ZERO), 0, 100, true},
|
||||
{frontierTx(0L), eip1559Tx(0L, 0L), Optional.of(Wei.ZERO), 0, 100, true},
|
||||
{eip1559Tx(0L, 0L), eip1559Tx(0L, 0L), Optional.of(Wei.ZERO), 0, 100, true},
|
||||
// blob tx
|
||||
{blobTx(3L, 6L, 1L), blobTx(3L, 6L, 1L), Optional.of(Wei.of(3L)), 0, 0, true},
|
||||
{blobTx(3L, 6L, 1L), blobTx(3L, 6L, 2L), Optional.of(Wei.of(3L)), 0, 100, true},
|
||||
{blobTx(10L, 200L, 1L), blobTx(10L, 200L, 1L), Optional.of(Wei.of(90L)), 10, 100, false},
|
||||
{blobTx(10L, 200L, 2L), blobTx(15L, 200L, 3L), Optional.of(Wei.of(90L)), 10, 100, false},
|
||||
// blob tx must be replaced by blob tx only
|
||||
{blobTx(3L, 6L, 1L), eip1559Tx(3L, 6L), Optional.of(Wei.of(3L)), 0, 0, false},
|
||||
{eip1559Tx(3L, 6L), blobTx(3L, 6L, 1L), Optional.of(Wei.of(3L)), 0, 0, false},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,12 +95,14 @@ public class TransactionReplacementRulesTest extends AbstractTransactionReplacem
|
||||
final PendingTransaction newTx,
|
||||
final Optional<Wei> baseFee,
|
||||
final int priceBump,
|
||||
final int blobPriceBump,
|
||||
final boolean expected) {
|
||||
BlockHeader mockHeader = mock(BlockHeader.class);
|
||||
when(mockHeader.getBaseFee()).thenReturn(baseFee);
|
||||
|
||||
assertThat(
|
||||
new TransactionPoolReplacementHandler(Percentage.fromInt(priceBump))
|
||||
new TransactionPoolReplacementHandler(
|
||||
Percentage.fromInt(priceBump), Percentage.fromInt(blobPriceBump))
|
||||
.shouldReplace(oldTx, newTx, mockHeader))
|
||||
.isEqualTo(expected);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ public abstract class AbstractPrioritizedTransactionsTestBase extends BaseTransa
|
||||
final PendingTransaction pt1,
|
||||
final PendingTransaction pt2) {
|
||||
final TransactionPoolReplacementHandler transactionReplacementHandler =
|
||||
new TransactionPoolReplacementHandler(poolConfig.getPriceBump());
|
||||
new TransactionPoolReplacementHandler(
|
||||
poolConfig.getPriceBump(), poolConfig.getBlobPriceBump());
|
||||
return transactionReplacementHandler.shouldReplace(pt1, pt2, mockBlockHeader());
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
|
||||
|
||||
final BiFunction<PendingTransaction, PendingTransaction, Boolean> transactionReplacementTester =
|
||||
(t1, t2) ->
|
||||
new TransactionPoolReplacementHandler(poolConf.getPriceBump())
|
||||
new TransactionPoolReplacementHandler(
|
||||
poolConf.getPriceBump(), poolConfig.getBlobPriceBump())
|
||||
.shouldReplace(t1, t2, mockBlockHeader());
|
||||
|
||||
final EvictCollectorLayer evictCollector = new EvictCollectorLayer(txPoolMetrics);
|
||||
|
||||
@@ -1194,7 +1194,8 @@ public class LayersTest extends BaseTransactionPoolTest {
|
||||
final PendingTransaction pt1,
|
||||
final PendingTransaction pt2) {
|
||||
final TransactionPoolReplacementHandler transactionReplacementHandler =
|
||||
new TransactionPoolReplacementHandler(poolConfig.getPriceBump());
|
||||
new TransactionPoolReplacementHandler(
|
||||
poolConfig.getPriceBump(), poolConfig.getBlobPriceBump());
|
||||
return transactionReplacementHandler.shouldReplace(pt1, pt2, mockBlockHeader());
|
||||
}
|
||||
|
||||
|
||||
@@ -305,7 +305,8 @@ public class ReplayTest {
|
||||
final PendingTransaction pt1,
|
||||
final PendingTransaction pt2) {
|
||||
final TransactionPoolReplacementHandler transactionReplacementHandler =
|
||||
new TransactionPoolReplacementHandler(poolConfig.getPriceBump());
|
||||
new TransactionPoolReplacementHandler(
|
||||
poolConfig.getPriceBump(), poolConfig.getBlobPriceBump());
|
||||
return transactionReplacementHandler.shouldReplace(pt1, pt2, currBlockHeader);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user