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

Add profitable transaction selector #530

Merged
merged 10 commits into from
Jan 10, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ private enum LineaStatus implements TransactionSelectionResult.Status {
BLOCK_MODULE_LINE_COUNT_FULL(true, false),
TX_GAS_EXCEEDS_USER_MAX_BLOCK_GAS(false, true),
TX_TOO_LARGE_FOR_REMAINING_USER_GAS(false, false),
TX_MODULE_LINE_COUNT_OVERFLOW(false, true);
TX_MODULE_LINE_COUNT_OVERFLOW(false, true),
TX_UNPROFITABLE(false, false);

private final boolean stop;
private final boolean discard;
Expand Down Expand Up @@ -57,4 +58,7 @@ protected LineaTransactionSelectionResult(LineaStatus status) {
new LineaTransactionSelectionResult(LineaStatus.TX_TOO_LARGE_FOR_REMAINING_USER_GAS);
public static final TransactionSelectionResult TX_MODULE_LINE_COUNT_OVERFLOW =
new LineaTransactionSelectionResult(LineaStatus.TX_MODULE_LINE_COUNT_OVERFLOW);

public static final TransactionSelectionResult TX_UNPROFITABLE =
new LineaTransactionSelectionResult(LineaStatus.TX_UNPROFITABLE);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,40 +20,71 @@

/** The Linea CLI options. */
public class LineaTransactionSelectorCliOptions {
public static final int DEFAULT_MAX_BLOCK_CALLDATA_SIZE = 70000;
public static final int DEFAULT_MAX_BLOCK_CALLDATA_SIZE = 70_000;
private static final String DEFAULT_MODULE_LIMIT_FILE_PATH = "moduleLimitFile.toml";
public static final long DEFAULT_MAX_GAS_PER_BLOCK = 30_000_000L;
public static final int DEFAULT_VERIFICATION_GAS_COST = 1_200_000;
public static final int DEFAULT_VERIFICATION_CAPACITY = 90_000;
public static final int DEFAULT_GAS_PRICE_RATIO = 15;
public static final double DEFAULT_MIN_MARGIN = 1.0;
private static final String MAX_BLOCK_CALLDATA_SIZE = "--plugin-linea-max-block-calldata-size";
private static final String MODULE_LIMIT_FILE_PATH = "--plugin-linea-module-limit-file-path";
private static final String MAX_GAS_PER_BLOCK = "--plugin-linea-max-block-gas";
private static final String VERIFICATION_GAS_COST = "--plugin-linea-verification-gas-cost";
private static final String VERIFICATION_CAPACITY = "--plugin-linea-verification-capacity";
private static final String GAS_PRICE_RATIO = "--plugin-linea-gas-price-ratio";
private static final String MIN_MARGIN = "--plugin-linea-min-margin";

@CommandLine.Option(
names = {MAX_BLOCK_CALLDATA_SIZE},
hidden = true,
paramLabel = "<INTEGER>",
description =
"Maximum size for the calldata of a Block (default: "
+ DEFAULT_MAX_BLOCK_CALLDATA_SIZE
+ ")")
description = "Maximum size for the calldata of a block (default: ${DEFAULT-VALUE})")
private int maxBlockCallDataSize = DEFAULT_MAX_BLOCK_CALLDATA_SIZE;

@CommandLine.Option(
names = {MODULE_LIMIT_FILE_PATH},
hidden = true,
paramLabel = "<STRING>",
description =
"Path to the toml file containing the module limits (default: "
+ DEFAULT_MODULE_LIMIT_FILE_PATH
+ ")")
"Path to the toml file containing the module limits (default: ${DEFAULT-VALUE})")
private String moduleLimitFilePath = DEFAULT_MODULE_LIMIT_FILE_PATH;

@CommandLine.Option(
names = {MAX_GAS_PER_BLOCK},
hidden = true,
paramLabel = "<LONG>",
description = "Sets max gas per block.")
description = "Sets max gas per block (default: ${DEFAULT-VALUE})")
private Long maxGasPerBlock = DEFAULT_MAX_GAS_PER_BLOCK;

@CommandLine.Option(
names = {VERIFICATION_GAS_COST},
hidden = true,
paramLabel = "<INTEGER>",
description = "L1 verification gas cost (default: ${DEFAULT-VALUE})")
private int verificationGasCost = DEFAULT_VERIFICATION_GAS_COST;

@CommandLine.Option(
names = {VERIFICATION_CAPACITY},
hidden = true,
paramLabel = "<INTEGER>",
description = "L1 verification capacity (default: ${DEFAULT-VALUE})")
private int verificationCapacity = DEFAULT_VERIFICATION_CAPACITY;

@CommandLine.Option(
names = {GAS_PRICE_RATIO},
hidden = true,
paramLabel = "<INTEGER>",
description = "L1/L2 gas price ratio (default: ${DEFAULT-VALUE})")
private int gasPriceRatio = DEFAULT_GAS_PRICE_RATIO;

@CommandLine.Option(
names = {MIN_MARGIN},
hidden = true,
paramLabel = "<FLOAT>",
description = "Minimum margin of a transaction to be selected (default: ${DEFAULT-VALUE})")
private double minMargin = DEFAULT_MIN_MARGIN;

private LineaTransactionSelectorCliOptions() {}

/**
Expand All @@ -77,6 +108,10 @@ public static LineaTransactionSelectorCliOptions fromConfig(
options.maxBlockCallDataSize = config.maxBlockCallDataSize();
options.moduleLimitFilePath = config.moduleLimitsFilePath();
options.maxGasPerBlock = config.maxGasPerBlock();
options.verificationGasCost = config.getVerificationGasCost();
options.verificationCapacity = config.getVerificationCapacity();
options.gasPriceRatio = config.getGasPriceRatio();
options.minMargin = config.getMinMargin();
return options;
}

Expand All @@ -90,6 +125,10 @@ public LineaTransactionSelectorConfiguration toDomainObject() {
.maxBlockCallDataSize(maxBlockCallDataSize)
.moduleLimits(moduleLimitFilePath)
.maxGasPerBlock(maxGasPerBlock)
.verificationGasCost(verificationGasCost)
.verificationCapacity(verificationCapacity)
.gasPriceRatio(gasPriceRatio)
.minMargin(minMargin)
.build();
}

Expand All @@ -99,6 +138,10 @@ public String toString() {
.add(MAX_BLOCK_CALLDATA_SIZE, maxBlockCallDataSize)
.add(MODULE_LIMIT_FILE_PATH, moduleLimitFilePath)
.add(MAX_GAS_PER_BLOCK, maxGasPerBlock)
.add(VERIFICATION_GAS_COST, verificationGasCost)
.add(VERIFICATION_CAPACITY, verificationCapacity)
.add(GAS_PRICE_RATIO, gasPriceRatio)
.add(MIN_MARGIN, minMargin)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,26 @@ public final class LineaTransactionSelectorConfiguration {
private final int maxBlockCallDataSize;
private final String moduleLimitsFilePath;
private final long maxGasPerBlock;
private final int verificationGasCost;
private final int verificationCapacity;
private final int gasPriceRatio;
private final double minMargin;

private LineaTransactionSelectorConfiguration(
int maxBlockCallDataSize, final String moduleLimitsFilePath, long maxGasPerBlock) {
final int maxBlockCallDataSize,
final String moduleLimitsFilePath,
final long maxGasPerBlock,
final int verificationGasCost,
final int verificationCapacity,
final int gasPriceRatio,
final double minMargin) {
this.maxBlockCallDataSize = maxBlockCallDataSize;
this.moduleLimitsFilePath = moduleLimitsFilePath;
this.maxGasPerBlock = maxGasPerBlock;
this.verificationGasCost = verificationGasCost;
this.verificationCapacity = verificationCapacity;
this.gasPriceRatio = gasPriceRatio;
this.minMargin = minMargin;
}

public int maxBlockCallDataSize() {
Expand All @@ -40,10 +54,30 @@ public long maxGasPerBlock() {
return maxGasPerBlock;
}

public int getVerificationGasCost() {
return verificationGasCost;
}

public int getVerificationCapacity() {
return verificationCapacity;
}

public int getGasPriceRatio() {
return gasPriceRatio;
}

public double getMinMargin() {
return minMargin;
}

public static class Builder {
private int maxBlockCallDataSize;
private String moduleLimitsFilePath;
private long maxGasPerBlock;
private int verificationGasCost;
private int verificationCapacity;
private int gasPriceRatio;
private double minMargin;

public Builder maxBlockCallDataSize(final int maxBlockCallDataSize) {
this.maxBlockCallDataSize = maxBlockCallDataSize;
Expand All @@ -55,14 +89,40 @@ public Builder moduleLimits(final String moduleLimitFilePath) {
return this;
}

public Builder maxGasPerBlock(long maxGasPerBlock) {
public Builder maxGasPerBlock(final long maxGasPerBlock) {
this.maxGasPerBlock = maxGasPerBlock;
return this;
}

public Builder verificationGasCost(final int verificationGasCost) {
this.verificationGasCost = verificationGasCost;
return this;
}

public Builder verificationCapacity(final int verificationCapacity) {
this.verificationCapacity = verificationCapacity;
return this;
}

public Builder gasPriceRatio(final int gasPriceRatio) {
this.gasPriceRatio = gasPriceRatio;
return this;
}

public Builder minMargin(final double minMargin) {
this.minMargin = minMargin;
return this;
}

public LineaTransactionSelectorConfiguration build() {
return new LineaTransactionSelectorConfiguration(
maxBlockCallDataSize, moduleLimitsFilePath, maxGasPerBlock);
maxBlockCallDataSize,
moduleLimitsFilePath,
maxGasPerBlock,
verificationGasCost,
verificationCapacity,
gasPriceRatio,
minMargin);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer;
import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector;
import org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext;

/** Class for transaction selection using a list of selectors. */
@Slf4j
Expand Down Expand Up @@ -57,21 +58,26 @@ private static List<PluginTransactionSelector> createTransactionSelectors(
return List.of(
new MaxBlockCallDataTransactionSelector(lineaConfiguration.maxBlockCallDataSize()),
new MaxBlockGasTransactionSelector(lineaConfiguration.maxGasPerBlock()),
traceLineLimitTransactionSelector);
traceLineLimitTransactionSelector,
new ProfitableTransactionSelector(
lineaConfiguration.getVerificationGasCost(),
lineaConfiguration.getVerificationCapacity(),
lineaConfiguration.getGasPriceRatio(),
lineaConfiguration.getMinMargin()));
}

/**
* Evaluates a transaction before processing using all selectors. Stops if any selector doesn't
* select the transaction.
*
* @param pendingTransaction The transaction to evaluate.
* @param evaluationContext The current selection context.
* @return The first non-SELECTED result or SELECTED if all selectors select the transaction.
*/
@Override
public TransactionSelectionResult evaluateTransactionPreProcessing(
PendingTransaction pendingTransaction) {
final TransactionEvaluationContext<? extends PendingTransaction> evaluationContext) {
return selectors.stream()
.map(selector -> selector.evaluateTransactionPreProcessing(pendingTransaction))
.map(selector -> selector.evaluateTransactionPreProcessing(evaluationContext))
.filter(result -> !result.equals(TransactionSelectionResult.SELECTED))
.findFirst()
.orElse(TransactionSelectionResult.SELECTED);
Expand All @@ -81,16 +87,17 @@ public TransactionSelectionResult evaluateTransactionPreProcessing(
* Evaluates a transaction considering its processing result. Stops if any selector doesn't select
* the transaction.
*
* @param pendingTransaction The processed transaction.
* @param evaluationContext The current selection context.
* @param processingResult The result of the transaction processing.
* @return The first non-SELECTED result or SELECTED if all selectors select the transaction.
*/
@Override
public TransactionSelectionResult evaluateTransactionPostProcessing(
PendingTransaction pendingTransaction, TransactionProcessingResult processingResult) {
final TransactionEvaluationContext<? extends PendingTransaction> evaluationContext,
final TransactionProcessingResult processingResult) {
for (var selector : selectors) {
TransactionSelectionResult result =
selector.evaluateTransactionPostProcessing(pendingTransaction, processingResult);
selector.evaluateTransactionPostProcessing(evaluationContext, processingResult);
if (!result.equals(TransactionSelectionResult.SELECTED)) {
return result;
}
Expand All @@ -101,30 +108,30 @@ public TransactionSelectionResult evaluateTransactionPostProcessing(
/**
* Notifies all selectors when a transaction is selected.
*
* @param pendingTransaction The selected transaction.
* @param evaluationContext The current selection context.
* @param processingResult The transaction processing result.
*/
@Override
public void onTransactionSelected(
final PendingTransaction pendingTransaction,
final TransactionEvaluationContext<? extends PendingTransaction> evaluationContext,
final TransactionProcessingResult processingResult) {
selectors.forEach(
selector -> selector.onTransactionSelected(pendingTransaction, processingResult));
selector -> selector.onTransactionSelected(evaluationContext, processingResult));
}

/**
* Notifies all selectors when a transaction is not selected.
*
* @param pendingTransaction The non-selected transaction.
* @param evaluationContext The current selection context.
* @param transactionSelectionResult The reason for not selecting the transaction.
*/
@Override
public void onTransactionNotSelected(
final PendingTransaction pendingTransaction,
final TransactionEvaluationContext<? extends PendingTransaction> evaluationContext,
final TransactionSelectionResult transactionSelectionResult) {
selectors.forEach(
selector ->
selector.onTransactionNotSelected(pendingTransaction, transactionSelectionResult));
selector.onTransactionNotSelected(evaluationContext, transactionSelectionResult));
}

/**
Expand Down
Loading
Loading