mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-09 20:27:58 -05:00
Gas pricing refactoring + transaction sample calculator for legacy gas price estimation (#27)
* Transaction cost calculator implementation and a comparative test. * Refactored gas pricing config to make it cleaner * Added DTO objects for easier instantination * Better type for VariableFeesCalculator configs
This commit is contained in:
@@ -10,6 +10,13 @@ max_line_length=120
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{kt,kts}]
|
||||
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
|
||||
|
||||
ij_kotlin_name_count_to_use_star_import = 2147483647
|
||||
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
|
||||
ij_kotlin_packages_to_use_import_on_demand = unset
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = tab
|
||||
|
||||
4
.github/workflows/reuse-run-e2e-tests.yml
vendored
4
.github/workflows/reuse-run-e2e-tests.yml
vendored
@@ -157,14 +157,14 @@ jobs:
|
||||
mkdir -p docker_logs
|
||||
docker ps -a >> docker_logs/docker_ps.txt
|
||||
docker logs prover --since 1h &>> docker_logs/prover.txt
|
||||
docker logs prover-v3 --since 1h &>> docker_logs/prover-v3.txt
|
||||
docker logs prover-v3 --since 1h &>> docker_logs/prover-v3.txt;
|
||||
docker logs coordinator --since 1h &>> docker_logs/coordinator.txt
|
||||
docker logs shomei --since 1h &>> docker_logs/shomei.txt
|
||||
docker logs zkbesu-shomei --since 1h &>> docker_logs/zkbesu-shomei.txt
|
||||
docker logs shomei-frontend --since 1h &>> docker_logs/shomei-frontend.txt
|
||||
docker logs postman --since 1h &>> docker_logs/postman.txt
|
||||
docker logs traces-node --since 1h &>> docker_logs/traces-node.txt
|
||||
docker logs traces-node-v2 --since 1h &>> docker_logs/traces-node-v2.txt
|
||||
docker logs traces-node-v2 --since 1h &>> docker_logs/traces-node-v2.txt;
|
||||
docker logs sequencer --since 1h &>> docker_logs/sequencer.txt
|
||||
- name: Archive debug logs
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
@@ -206,39 +206,47 @@ disabled=false
|
||||
polling-interval="PT10S"
|
||||
max-messages-to-anchor=100
|
||||
|
||||
[dynamic-gas-price-service]
|
||||
disabled=false
|
||||
price-update-interval="PT12S"
|
||||
fee-history-block-count=50
|
||||
fee-history-reward-percentile=15
|
||||
base-fee-coefficient=0.1
|
||||
priority-fee-coefficient=1.0
|
||||
base-fee-blob-coefficient=0.1
|
||||
expected-blob-gas = 131072.0 # 2^17
|
||||
[l2-network-gas-pricing]
|
||||
disabled = false
|
||||
price-update-interval = "PT12S"
|
||||
|
||||
fee-history-block-count = 50
|
||||
fee-history-reward-percentile = 15
|
||||
|
||||
blob-submission-expected-execution-gas = 213000.0 # Lower to 120k as we improve efficiency
|
||||
gas-price-upper-bound=10000000000 # 10 GWEI
|
||||
gas-price-lower-bound=90000000 # 0.09 GWEI
|
||||
gas-price-fixed-cost=3000000
|
||||
geth-gas-price-update-recipients=[
|
||||
# Defaults to expected-blob-gas
|
||||
#bytes-per-data-submission=131072.0 # 2^17
|
||||
l1-blob-gas = 131072 # 2^17
|
||||
|
||||
[l2-network-gas-pricing.request-retry]
|
||||
max-retries = 3
|
||||
timeout = "PT6S"
|
||||
backoff-delay = "PT1S"
|
||||
failures-warning-threshold = 2
|
||||
|
||||
[l2-network-gas-pricing.variable-cost-pricing]
|
||||
gas-price-fixed-cost = 3000000
|
||||
legacy-fees-multiplier = 1.2
|
||||
margin = 4.0
|
||||
variable-cost-upper-bound = 10000000001 # ~10 GWEI
|
||||
variable-cost-lower-bound = 90000001 # ~0.09 GWEI
|
||||
|
||||
[l2-network-gas-pricing.extra-data-pricing-propagation]
|
||||
extra-data-update-recipient = "http://sequencer:8545/"
|
||||
|
||||
[l2-network-gas-pricing.legacy]
|
||||
type="SampleTransaction"
|
||||
gas-price-upper-bound = 10000000000 # 10 GWEI
|
||||
gas-price-lower-bound = 90000000 # 0.09 GWEI
|
||||
|
||||
[l2-network-gas-pricing.json-rpc-pricing-propagation]
|
||||
geth-gas-price-update-recipients = [
|
||||
"http://traces-node:8545/",
|
||||
"http://l2-node:8545/"
|
||||
]
|
||||
besu-gas-price-update-recipients=[
|
||||
besu-gas-price-update-recipients = [
|
||||
"http://sequencer:8545/"
|
||||
]
|
||||
request-retry.max-retries=3
|
||||
request-retry.timeout="PT6S"
|
||||
request-retry.backoff-delay="PT1S"
|
||||
request-retry.failures-warning-threshold=2
|
||||
extra-data-enabled=true
|
||||
min-mineable-fees-enabled=true
|
||||
legacy-fees-multiplier=1.2
|
||||
margin=4.0
|
||||
extra-data-update-recipient="http://sequencer:8545/"
|
||||
variable-cost-upper-bound=10000000001 # ~10 GWEI
|
||||
variable-cost-lower-bound=90000001 # ~0.09 GWEI
|
||||
# Defaults to expected-blob-gas
|
||||
#bytes-per-data-submission=131072.0 # 2^17
|
||||
|
||||
[l1-dynamic-gas-price-cap-service]
|
||||
disabled=false
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[prover]
|
||||
[prover.execution]
|
||||
fs-requests-directory = "/data/prover/v3/execution/requests"
|
||||
fs-responses-directory = "/data/prover/v3/execution/responses"
|
||||
fs-requests-directory = "tmp/local/prover/v3/execution/requests"
|
||||
fs-responses-directory = "tmp/local/prover/v3/execution/responses"
|
||||
[prover.blob-compression]
|
||||
fs-requests-directory = "/data/prover/v3/compression/requests"
|
||||
fs-responses-directory = "/data/prover/v3/compression/responses"
|
||||
fs-requests-directory = "tmp/local/prover/v3/compression/requests"
|
||||
fs-responses-directory = "tmp/local/prover/v3/compression/responses"
|
||||
[prover.proof-aggregation]
|
||||
fs-requests-directory = "/data/prover/v3/aggregation/requests"
|
||||
fs-responses-directory = "/data/prover/v3/aggregation/responses"
|
||||
fs-requests-directory = "tmp/local/prover/v3/aggregation/requests"
|
||||
fs-responses-directory = "tmp/local/prover/v3/aggregation/responses"
|
||||
|
||||
[zk-traces]
|
||||
eth-api="http://127.0.0.1:8745"
|
||||
|
||||
@@ -127,7 +127,7 @@ class L1DependentApp(
|
||||
if (configs.messageAnchoringService.disabled) {
|
||||
log.warn("Message anchoring service is disabled")
|
||||
}
|
||||
if (configs.dynamicGasPriceService.disabled) {
|
||||
if (configs.l2NetworkGasPricingService == null) {
|
||||
log.warn("Dynamic gas price service is disabled")
|
||||
}
|
||||
}
|
||||
@@ -907,14 +907,14 @@ class L1DependentApp(
|
||||
null
|
||||
}
|
||||
|
||||
private val gasPriceUpdaterApp: GasPriceUpdaterApp? =
|
||||
if (configs.dynamicGasPriceService.enabled) {
|
||||
GasPriceUpdaterApp(
|
||||
private val l2NetworkGasPricingService: L2NetworkGasPricingService? =
|
||||
if (configs.l2NetworkGasPricingService != null) {
|
||||
L2NetworkGasPricingService(
|
||||
vertx = vertx,
|
||||
httpJsonRpcClientFactory = httpJsonRpcClientFactory,
|
||||
l1Web3jClient = l1Web3jClient,
|
||||
l1Web3jService = l1Web3jService,
|
||||
config = configs.dynamicGasPriceService
|
||||
config = configs.l2NetworkGasPricingService
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -1001,7 +1001,7 @@ class L1DependentApp(
|
||||
.thenCompose { aggregationFinalizationCoordinator.start() }
|
||||
.thenCompose { proofAggregationCoordinatorService.start() }
|
||||
.thenCompose { messageAnchoringApp?.start() ?: SafeFuture.completedFuture(Unit) }
|
||||
.thenCompose { gasPriceUpdaterApp?.start() ?: SafeFuture.completedFuture(Unit) }
|
||||
.thenCompose { l2NetworkGasPricingService?.start() ?: SafeFuture.completedFuture(Unit) }
|
||||
.thenCompose { l1FeeHistoryCachingService.start() }
|
||||
.thenCompose { deadlineConflationCalculatorRunnerOld.start() }
|
||||
.thenCompose { deadlineConflationCalculatorRunnerNew.start() }
|
||||
@@ -1019,7 +1019,7 @@ class L1DependentApp(
|
||||
aggregationFinalizationCoordinator.stop(),
|
||||
proofAggregationCoordinatorService.stop(),
|
||||
messageAnchoringApp?.stop() ?: SafeFuture.completedFuture(Unit),
|
||||
gasPriceUpdaterApp?.stop() ?: SafeFuture.completedFuture(Unit),
|
||||
l2NetworkGasPricingService?.stop() ?: SafeFuture.completedFuture(Unit),
|
||||
l1FeeHistoryCachingService.stop(),
|
||||
blockCreationMonitor.stop(),
|
||||
deadlineConflationCalculatorRunnerOld.stop(),
|
||||
|
||||
@@ -12,113 +12,104 @@ import net.consensys.linea.ethereum.gaspricing.staticcap.GasPriceUpdaterImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.GasUsageRatioWeightedAverageFeesCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.MinMineableFeesPricerService
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.MinerExtraDataV1CalculatorImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.TransactionCostCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.VariableFeesCalculator
|
||||
import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory
|
||||
import net.consensys.linea.web3j.Web3jBlobExtended
|
||||
import net.consensys.toKWeiUInt
|
||||
import net.consensys.zkevm.LongRunningService
|
||||
import net.consensys.zkevm.coordinator.app.config.DynamicGasPriceServiceConfig
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.web3j.protocol.Web3j
|
||||
import tech.pegasys.teku.infrastructure.async.SafeFuture
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.time.toKotlinDuration
|
||||
import kotlin.time.Duration
|
||||
|
||||
class GasPriceUpdaterApp(
|
||||
class L2NetworkGasPricingService(
|
||||
vertx: Vertx,
|
||||
httpJsonRpcClientFactory: VertxHttpJsonRpcClientFactory,
|
||||
l1Web3jClient: Web3j,
|
||||
l1Web3jService: Web3jBlobExtended,
|
||||
config: DynamicGasPriceServiceConfig
|
||||
config: Config
|
||||
) : LongRunningService {
|
||||
data class LegacyGasPricingCalculatorConfig(
|
||||
val transactionCostCalculatorConfig: TransactionCostCalculator.Config?,
|
||||
val naiveGasPricingCalculatorConfig: GasUsageRatioWeightedAverageFeesCalculator.Config?,
|
||||
val legacyGasPricingCalculatorBounds: BoundableFeeCalculator.Config
|
||||
)
|
||||
|
||||
data class Config(
|
||||
val feeHistoryFetcherConfig: FeeHistoryFetcherImpl.Config,
|
||||
val jsonRpcPricingPropagationEnabled: Boolean,
|
||||
val legacy: LegacyGasPricingCalculatorConfig,
|
||||
val jsonRpcGasPriceUpdaterConfig: GasPriceUpdaterImpl.Config,
|
||||
val jsonRpcPriceUpdateInterval: Duration,
|
||||
val extraDataPricingPropagationEnabled: Boolean,
|
||||
val extraDataUpdateInterval: Duration,
|
||||
val variableFeesCalculatorConfig: VariableFeesCalculator.Config,
|
||||
val variableFeesCalculatorBounds: BoundableFeeCalculator.Config,
|
||||
val extraDataCalculatorConfig: MinerExtraDataV1CalculatorImpl.Config,
|
||||
val extraDataUpdaterConfig: ExtraDataV1UpdaterImpl.Config
|
||||
)
|
||||
private val log = LogManager.getLogger(this::class.java)
|
||||
|
||||
private val gasPricingFeesFetcher: FeesFetcher = FeeHistoryFetcherImpl(
|
||||
l1Web3jClient,
|
||||
l1Web3jService,
|
||||
FeeHistoryFetcherImpl.Config(
|
||||
config.feeHistoryBlockCount.toUInt(),
|
||||
config.feeHistoryRewardPercentile
|
||||
)
|
||||
config.feeHistoryFetcherConfig
|
||||
)
|
||||
|
||||
private val minMineableFeesCalculator: FeesCalculator = run {
|
||||
val gasUsageRatioWeightedAverageFeesCalculator = GasUsageRatioWeightedAverageFeesCalculator(
|
||||
GasUsageRatioWeightedAverageFeesCalculator.Config(
|
||||
baseFeeCoefficient = config.baseFeeCoefficient,
|
||||
priorityFeeCoefficient = config.priorityFeeCoefficient,
|
||||
baseFeeBlobCoefficient = config.baseFeeBlobCoefficient,
|
||||
blobSubmissionExpectedExecutionGas = config.blobSubmissionExpectedExecutionGas,
|
||||
expectedBlobGas = config.expectedBlobGas
|
||||
private val variableCostCalculator = VariableFeesCalculator(
|
||||
config.variableFeesCalculatorConfig
|
||||
)
|
||||
|
||||
private val legacyGasPricingCalculator: FeesCalculator = run {
|
||||
val baseCalculator = if (config.legacy.transactionCostCalculatorConfig != null) {
|
||||
TransactionCostCalculator(variableCostCalculator, config.legacy.transactionCostCalculatorConfig)
|
||||
} else {
|
||||
GasUsageRatioWeightedAverageFeesCalculator(
|
||||
config.legacy.naiveGasPricingCalculatorConfig!!
|
||||
)
|
||||
)
|
||||
}
|
||||
BoundableFeeCalculator(
|
||||
BoundableFeeCalculator.Config(
|
||||
config.gasPriceUpperBound.toDouble(),
|
||||
config.gasPriceLowerBound.toDouble(),
|
||||
config.gasPriceFixedCost.toDouble()
|
||||
),
|
||||
gasUsageRatioWeightedAverageFeesCalculator
|
||||
config.legacy.legacyGasPricingCalculatorBounds,
|
||||
baseCalculator
|
||||
)
|
||||
}
|
||||
|
||||
private val minMineableFeesPricerService: MinMineableFeesPricerService? =
|
||||
if (config.minMineableFeesEnabled) {
|
||||
if (config.jsonRpcPricingPropagationEnabled) {
|
||||
val l2SetGasPriceUpdater: GasPriceUpdater = GasPriceUpdaterImpl(
|
||||
httpJsonRpcClientFactory = httpJsonRpcClientFactory,
|
||||
config = GasPriceUpdaterImpl.Config(
|
||||
gethEndpoints = config.gethGasPriceUpdateRecipients,
|
||||
besuEndPoints = config.besuGasPriceUpdateRecipients,
|
||||
retryConfig = config.requestRetryConfig
|
||||
)
|
||||
config = config.jsonRpcGasPriceUpdaterConfig
|
||||
)
|
||||
|
||||
MinMineableFeesPricerService(
|
||||
pollingInterval = config.priceUpdateInterval.toKotlinDuration(),
|
||||
pollingInterval = config.jsonRpcPriceUpdateInterval,
|
||||
vertx = vertx,
|
||||
feesFetcher = gasPricingFeesFetcher,
|
||||
feesCalculator = minMineableFeesCalculator,
|
||||
feesCalculator = legacyGasPricingCalculator,
|
||||
gasPriceUpdater = l2SetGasPriceUpdater
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
private val extraDataPricerService: ExtraDataV1PricerService? = if (config.extraDataEnabled) {
|
||||
val variableCostCalculator = VariableFeesCalculator(
|
||||
VariableFeesCalculator.Config(
|
||||
blobSubmissionExpectedExecutionGas = config.blobSubmissionExpectedExecutionGas,
|
||||
bytesPerDataSubmission = config.bytesPerDataSubmission,
|
||||
expectedBlobGas = config.expectedBlobGas,
|
||||
margin = config.margin
|
||||
)
|
||||
)
|
||||
private val extraDataPricerService: ExtraDataV1PricerService? = if (config.extraDataPricingPropagationEnabled) {
|
||||
val boundedVariableCostCalculator = BoundableFeeCalculator(
|
||||
config = BoundableFeeCalculator.Config(
|
||||
feeUpperBound = config.variableCostUpperBound.toDouble(),
|
||||
feeLowerBound = config.variableCostLowerBound.toDouble(),
|
||||
feeMargin = 0.0
|
||||
),
|
||||
config = config.variableFeesCalculatorBounds,
|
||||
feesCalculator = variableCostCalculator
|
||||
)
|
||||
ExtraDataV1PricerService(
|
||||
pollingInterval = config.priceUpdateInterval.toKotlinDuration(),
|
||||
pollingInterval = config.extraDataUpdateInterval,
|
||||
vertx = vertx,
|
||||
feesFetcher = gasPricingFeesFetcher,
|
||||
minerExtraDataCalculatorImpl = MinerExtraDataV1CalculatorImpl(
|
||||
config = MinerExtraDataV1CalculatorImpl.Config(
|
||||
fixedCostInKWei = config.gasPriceFixedCost.toKWeiUInt(),
|
||||
ethGasPriceMultiplier = config.legacyFeesMultiplier
|
||||
),
|
||||
config = config.extraDataCalculatorConfig,
|
||||
variableFeesCalculator = boundedVariableCostCalculator,
|
||||
legacyFeesCalculator = minMineableFeesCalculator
|
||||
legacyFeesCalculator = legacyGasPricingCalculator
|
||||
),
|
||||
extraDataUpdater = ExtraDataV1UpdaterImpl(
|
||||
httpJsonRpcClientFactory = httpJsonRpcClientFactory,
|
||||
config = ExtraDataV1UpdaterImpl.Config(
|
||||
config.extraDataUpdateRecipient,
|
||||
config.requestRetryConfig
|
||||
)
|
||||
config = config.extraDataUpdaterConfig
|
||||
)
|
||||
)
|
||||
} else {
|
||||
@@ -18,6 +18,7 @@ import net.consensys.linea.traces.TracesCountersV2
|
||||
import net.consensys.linea.traces.TracingModuleV1
|
||||
import net.consensys.linea.traces.TracingModuleV2
|
||||
import net.consensys.linea.web3j.SmartContractErrors
|
||||
import net.consensys.zkevm.coordinator.app.L2NetworkGasPricingService
|
||||
import net.consensys.zkevm.coordinator.clients.prover.ProversConfig
|
||||
import java.math.BigInteger
|
||||
import java.net.URL
|
||||
@@ -120,7 +121,7 @@ data class PersistenceRetryConfig(
|
||||
override val timeout: Duration? = 10.minutes.toJavaDuration()
|
||||
) : RetryConfig
|
||||
|
||||
private interface RequestRetryConfigurable {
|
||||
internal interface RequestRetryConfigurable {
|
||||
val requestRetry: RequestRetryConfigTomlFriendly
|
||||
val requestRetryConfig: RequestRetryConfig
|
||||
get() = requestRetry.asDomain
|
||||
@@ -366,52 +367,6 @@ data class MessageAnchoringServiceConfig(
|
||||
}
|
||||
}
|
||||
|
||||
data class DynamicGasPriceServiceConfig(
|
||||
val priceUpdateInterval: Duration,
|
||||
val feeHistoryBlockCount: Int,
|
||||
val feeHistoryRewardPercentile: Double,
|
||||
val baseFeeCoefficient: Double,
|
||||
val priorityFeeCoefficient: Double,
|
||||
val baseFeeBlobCoefficient: Double,
|
||||
val expectedBlobGas: Double,
|
||||
val blobSubmissionExpectedExecutionGas: Double,
|
||||
val gasPriceUpperBound: ULong,
|
||||
val gasPriceLowerBound: ULong,
|
||||
val gasPriceFixedCost: ULong,
|
||||
val gethGasPriceUpdateRecipients: List<URL>,
|
||||
val besuGasPriceUpdateRecipients: List<URL>,
|
||||
override val requestRetry: RequestRetryConfigTomlFriendly,
|
||||
@ConfigAlias("disabled") var _disabled: Boolean = false,
|
||||
val extraDataEnabled: Boolean = false,
|
||||
val minMineableFeesEnabled: Boolean = false,
|
||||
val legacyFeesMultiplier: Double,
|
||||
val margin: Double,
|
||||
val extraDataUpdateRecipient: URL,
|
||||
val variableCostUpperBound: ULong,
|
||||
val variableCostLowerBound: ULong,
|
||||
val _bytesPerDataSubmission: Double? // If it is set to null or any default value the test fails for some reason
|
||||
) : FeatureToggleable, RequestRetryConfigurable {
|
||||
val bytesPerDataSubmission = _bytesPerDataSubmission ?: expectedBlobGas
|
||||
|
||||
override val disabled: Boolean
|
||||
get() =
|
||||
_disabled || (gethGasPriceUpdateRecipients.isEmpty() && besuGasPriceUpdateRecipients.isEmpty())
|
||||
|
||||
init {
|
||||
require(feeHistoryBlockCount > 0) { "feeHistoryBlockCount must be greater than 0" }
|
||||
require(gasPriceUpperBound >= gasPriceLowerBound) {
|
||||
"gasPriceUpperBound must be greater than or equal to gasPriceLowerBound"
|
||||
}
|
||||
require(variableCostUpperBound >= variableCostLowerBound) {
|
||||
"variableCostUpperBound must be greater than or equal to variableCostLowerBound"
|
||||
}
|
||||
require(extraDataEnabled || minMineableFeesEnabled) {
|
||||
"At least one of extraDataEnabled or minMineableFeesEnabled is required. If gas price updater is not required, " +
|
||||
"disable it with `disabled` config instead"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class L1DynamicGasPriceCapServiceConfig(
|
||||
val gasPriceCapCalculation: GasPriceCapCalculation,
|
||||
val feeHistoryFetcher: FeeHistoryFetcher,
|
||||
@@ -573,7 +528,7 @@ data class CoordinatorConfigTomlDto(
|
||||
val api: ApiConfig,
|
||||
val l2Signer: SignerConfig,
|
||||
val messageAnchoringService: MessageAnchoringServiceConfig,
|
||||
val dynamicGasPriceService: DynamicGasPriceServiceConfig,
|
||||
val l2NetworkGasPricing: L2NetworkGasPricingTomlDto,
|
||||
val l1DynamicGasPriceCapService: L1DynamicGasPriceCapServiceConfig,
|
||||
val testL1Disabled: Boolean = false,
|
||||
val prover: ProverConfigTomlDto
|
||||
@@ -598,7 +553,7 @@ data class CoordinatorConfigTomlDto(
|
||||
api = api,
|
||||
l2Signer = l2Signer,
|
||||
messageAnchoringService = messageAnchoringService,
|
||||
dynamicGasPriceService = dynamicGasPriceService,
|
||||
l2NetworkGasPricingService = if (!testL1Disabled) l2NetworkGasPricing.reified() else null,
|
||||
l1DynamicGasPriceCapService = l1DynamicGasPriceCapService,
|
||||
testL1Disabled = testL1Disabled,
|
||||
proversConfig = prover.reified()
|
||||
@@ -625,7 +580,7 @@ data class CoordinatorConfig(
|
||||
val api: ApiConfig,
|
||||
val l2Signer: SignerConfig,
|
||||
val messageAnchoringService: MessageAnchoringServiceConfig,
|
||||
val dynamicGasPriceService: DynamicGasPriceServiceConfig,
|
||||
val l2NetworkGasPricingService: L2NetworkGasPricingService.Config?,
|
||||
val l1DynamicGasPriceCapService: L1DynamicGasPriceCapServiceConfig,
|
||||
val testL1Disabled: Boolean = false,
|
||||
val proversConfig: ProversConfig
|
||||
@@ -650,7 +605,6 @@ data class CoordinatorConfig(
|
||||
|
||||
if (testL1Disabled) {
|
||||
messageAnchoringService.disabled = true
|
||||
dynamicGasPriceService._disabled = true
|
||||
l1DynamicGasPriceCapService.disabled = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
package net.consensys.zkevm.coordinator.app.config
|
||||
|
||||
import com.sksamuel.hoplite.ConfigAlias
|
||||
import net.consensys.linea.ethereum.gaspricing.BoundableFeeCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.ExtraDataV1UpdaterImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.FeeHistoryFetcherImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.GasPriceUpdaterImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.GasUsageRatioWeightedAverageFeesCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.MinerExtraDataV1CalculatorImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.TransactionCostCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.VariableFeesCalculator
|
||||
import net.consensys.toKWeiUInt
|
||||
import net.consensys.zkevm.coordinator.app.L2NetworkGasPricingService
|
||||
import java.net.URL
|
||||
import java.time.Duration
|
||||
import kotlin.time.toKotlinDuration
|
||||
|
||||
// Defaults to a compressed plain transfer transaction
|
||||
data class SampleTransactionGasPricingTomlDto(
|
||||
val plainTransferCostMultiplier: Double = 1.0,
|
||||
val compressedTxSize: Int = 125,
|
||||
val expectedGas: Int = 21000
|
||||
)
|
||||
|
||||
data class LegacyGasPricingTomlDto(
|
||||
val type: Type,
|
||||
|
||||
val naiveGasPricing: NaiveGasPricingTomlDto?,
|
||||
val sampleTransactionGasPricing: SampleTransactionGasPricingTomlDto = SampleTransactionGasPricingTomlDto(),
|
||||
val gasPriceUpperBound: ULong,
|
||||
val gasPriceLowerBound: ULong
|
||||
) {
|
||||
enum class Type {
|
||||
Naive,
|
||||
SampleTransaction
|
||||
}
|
||||
|
||||
init {
|
||||
if (type == Type.Naive && naiveGasPricing == null) {
|
||||
throw IllegalStateException("LegacyGasPricing $type configuration is null.")
|
||||
}
|
||||
|
||||
require(gasPriceUpperBound >= gasPriceLowerBound) {
|
||||
"gasPriceUpperBound must be greater than or equal to gasPriceLowerBound"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class NaiveGasPricingTomlDto(
|
||||
val baseFeeCoefficient: Double,
|
||||
val priorityFeeCoefficient: Double,
|
||||
val baseFeeBlobCoefficient: Double
|
||||
)
|
||||
|
||||
data class VariableCostPricingTomlDto(
|
||||
val gasPriceFixedCost: ULong,
|
||||
val legacyFeesMultiplier: Double,
|
||||
val margin: Double,
|
||||
val variableCostUpperBound: ULong,
|
||||
val variableCostLowerBound: ULong
|
||||
) {
|
||||
init {
|
||||
require(variableCostUpperBound >= variableCostLowerBound) {
|
||||
"variableCostUpperBound must be greater than or equal to variableCostLowerBound"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class JsonRpcPricingPropagationTomlDto(
|
||||
override var disabled: Boolean = false,
|
||||
val gethGasPriceUpdateRecipients: List<URL>,
|
||||
val besuGasPriceUpdateRecipients: List<URL>
|
||||
) : FeatureToggleable {
|
||||
init {
|
||||
require(disabled || (gethGasPriceUpdateRecipients.isNotEmpty() || besuGasPriceUpdateRecipients.isNotEmpty())) {
|
||||
"There is no point of enabling JSON RPC pricing propagation if there are no " +
|
||||
"gethGasPriceUpdateRecipients or besuGasPriceUpdateRecipients defined"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ExtraDataPricingPropagationTomlDto(
|
||||
override var disabled: Boolean = false,
|
||||
val extraDataUpdateRecipient: URL
|
||||
) : FeatureToggleable
|
||||
|
||||
data class L2NetworkGasPricingTomlDto(
|
||||
override var disabled: Boolean = false,
|
||||
override val requestRetry: RequestRetryConfigTomlFriendly,
|
||||
|
||||
val priceUpdateInterval: Duration,
|
||||
val feeHistoryBlockCount: Int,
|
||||
val feeHistoryRewardPercentile: Double,
|
||||
|
||||
val blobSubmissionExpectedExecutionGas: Int,
|
||||
@ConfigAlias("bytesPerDataSubmission") val _bytesPerDataSubmission: Int?,
|
||||
val l1BlobGas: Int,
|
||||
|
||||
val legacy: LegacyGasPricingTomlDto,
|
||||
val variableCostPricing: VariableCostPricingTomlDto,
|
||||
val jsonRpcPricingPropagation: JsonRpcPricingPropagationTomlDto,
|
||||
val extraDataPricingPropagation: ExtraDataPricingPropagationTomlDto
|
||||
) : FeatureToggleable, RequestRetryConfigurable {
|
||||
init {
|
||||
require(feeHistoryBlockCount > 0) { "feeHistoryBlockCount must be greater than 0" }
|
||||
require(blobSubmissionExpectedExecutionGas > 0) { "blobSubmissionExpectedExecutionGas must be greater than 0" }
|
||||
require(l1BlobGas > 0) { "l1BlobGas must be greater than 0" }
|
||||
|
||||
require(disabled || (jsonRpcPricingPropagation.enabled || extraDataPricingPropagation.enabled)) {
|
||||
"There is no point of enabling L2 network gas pricing if " +
|
||||
"both jsonRpcPricingPropagation and extraDataPricingPropagation are disabled"
|
||||
}
|
||||
}
|
||||
|
||||
private val bytesPerDataSubmission = _bytesPerDataSubmission ?: l1BlobGas
|
||||
|
||||
fun reified(): L2NetworkGasPricingService.Config {
|
||||
val legacyGasPricingConfig = when (legacy.type) {
|
||||
LegacyGasPricingTomlDto.Type.Naive -> {
|
||||
L2NetworkGasPricingService.LegacyGasPricingCalculatorConfig(
|
||||
transactionCostCalculatorConfig = null,
|
||||
naiveGasPricingCalculatorConfig = GasUsageRatioWeightedAverageFeesCalculator.Config(
|
||||
baseFeeCoefficient = legacy.naiveGasPricing!!.baseFeeCoefficient,
|
||||
priorityFeeCoefficient = legacy.naiveGasPricing.priorityFeeCoefficient,
|
||||
baseFeeBlobCoefficient = legacy.naiveGasPricing.baseFeeBlobCoefficient,
|
||||
blobSubmissionExpectedExecutionGas = blobSubmissionExpectedExecutionGas,
|
||||
expectedBlobGas = l1BlobGas
|
||||
),
|
||||
legacyGasPricingCalculatorBounds = BoundableFeeCalculator.Config(
|
||||
legacy.gasPriceUpperBound.toDouble(),
|
||||
legacy.gasPriceLowerBound.toDouble(),
|
||||
0.0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
LegacyGasPricingTomlDto.Type.SampleTransaction -> {
|
||||
L2NetworkGasPricingService.LegacyGasPricingCalculatorConfig(
|
||||
transactionCostCalculatorConfig = TransactionCostCalculator.Config(
|
||||
sampleTransactionCostMultiplier = legacy.sampleTransactionGasPricing.plainTransferCostMultiplier,
|
||||
fixedCostWei = variableCostPricing.gasPriceFixedCost,
|
||||
compressedTxSize = legacy.sampleTransactionGasPricing.compressedTxSize,
|
||||
expectedGas = legacy.sampleTransactionGasPricing.expectedGas
|
||||
),
|
||||
naiveGasPricingCalculatorConfig = null,
|
||||
legacyGasPricingCalculatorBounds = BoundableFeeCalculator.Config(
|
||||
legacy.gasPriceUpperBound.toDouble(),
|
||||
legacy.gasPriceLowerBound.toDouble(),
|
||||
0.0
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return L2NetworkGasPricingService.Config(
|
||||
feeHistoryFetcherConfig = FeeHistoryFetcherImpl.Config(
|
||||
feeHistoryBlockCount = feeHistoryBlockCount.toUInt(),
|
||||
feeHistoryRewardPercentile = feeHistoryRewardPercentile
|
||||
),
|
||||
jsonRpcPricingPropagationEnabled = jsonRpcPricingPropagation.enabled,
|
||||
legacy = legacyGasPricingConfig,
|
||||
jsonRpcGasPriceUpdaterConfig = GasPriceUpdaterImpl.Config(
|
||||
gethEndpoints = jsonRpcPricingPropagation.gethGasPriceUpdateRecipients,
|
||||
besuEndPoints = jsonRpcPricingPropagation.besuGasPriceUpdateRecipients,
|
||||
retryConfig = requestRetryConfig
|
||||
),
|
||||
jsonRpcPriceUpdateInterval = priceUpdateInterval.toKotlinDuration(),
|
||||
extraDataPricingPropagationEnabled = extraDataPricingPropagation.enabled,
|
||||
extraDataUpdateInterval = priceUpdateInterval.toKotlinDuration(),
|
||||
variableFeesCalculatorConfig = VariableFeesCalculator.Config(
|
||||
blobSubmissionExpectedExecutionGas = blobSubmissionExpectedExecutionGas.toUInt(),
|
||||
bytesPerDataSubmission = l1BlobGas.toUInt(),
|
||||
expectedBlobGas = bytesPerDataSubmission.toUInt(),
|
||||
margin = variableCostPricing.margin
|
||||
),
|
||||
variableFeesCalculatorBounds = BoundableFeeCalculator.Config(
|
||||
feeUpperBound = variableCostPricing.variableCostUpperBound.toDouble(),
|
||||
feeLowerBound = variableCostPricing.variableCostLowerBound.toDouble(),
|
||||
feeMargin = 0.0
|
||||
),
|
||||
extraDataCalculatorConfig = MinerExtraDataV1CalculatorImpl.Config(
|
||||
fixedCostInKWei = variableCostPricing.gasPriceFixedCost.toKWeiUInt(),
|
||||
ethGasPriceMultiplier = variableCostPricing.legacyFeesMultiplier
|
||||
),
|
||||
extraDataUpdaterConfig = ExtraDataV1UpdaterImpl.Config(
|
||||
extraDataPricingPropagation.extraDataUpdateRecipient,
|
||||
requestRetryConfig
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,21 @@ import com.github.michaelbull.result.onFailure
|
||||
import com.github.michaelbull.result.onSuccess
|
||||
import com.sksamuel.hoplite.Masked
|
||||
import net.consensys.linea.BlockParameter
|
||||
import net.consensys.linea.ethereum.gaspricing.BoundableFeeCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.ExtraDataV1UpdaterImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.FeeHistoryFetcherImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.GasPriceUpdaterImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.MinerExtraDataV1CalculatorImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.TransactionCostCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.VariableFeesCalculator
|
||||
import net.consensys.linea.jsonrpc.client.RequestRetryConfig
|
||||
import net.consensys.linea.traces.TracesCountersV1
|
||||
import net.consensys.linea.traces.TracesCountersV2
|
||||
import net.consensys.linea.traces.TracingModuleV1
|
||||
import net.consensys.linea.traces.TracingModuleV2
|
||||
import net.consensys.linea.web3j.SmartContractErrors
|
||||
import net.consensys.zkevm.coordinator.app.CoordinatorAppCli
|
||||
import net.consensys.zkevm.coordinator.app.L2NetworkGasPricingService
|
||||
import net.consensys.zkevm.coordinator.clients.prover.FileBasedProverConfig
|
||||
import net.consensys.zkevm.coordinator.clients.prover.ProverConfig
|
||||
import net.consensys.zkevm.coordinator.clients.prover.ProversConfig
|
||||
@@ -28,7 +37,6 @@ import java.nio.file.Path
|
||||
import java.time.Duration
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.toJavaDuration
|
||||
|
||||
class CoordinatorConfigTest {
|
||||
companion object {
|
||||
@@ -399,39 +407,65 @@ class CoordinatorConfigTest {
|
||||
maxMessagesToAnchor = 100U
|
||||
)
|
||||
|
||||
private val dynamicGasPriceServiceConfig = DynamicGasPriceServiceConfig(
|
||||
priceUpdateInterval = Duration.parse("PT12S"),
|
||||
feeHistoryBlockCount = 50,
|
||||
feeHistoryRewardPercentile = 15.0,
|
||||
baseFeeCoefficient = 0.1,
|
||||
priorityFeeCoefficient = 1.0,
|
||||
baseFeeBlobCoefficient = 0.1,
|
||||
blobSubmissionExpectedExecutionGas = 213_000.0,
|
||||
expectedBlobGas = 131072.0,
|
||||
gasPriceUpperBound = 10_000_000_000u,
|
||||
gasPriceLowerBound = 90_000_000u,
|
||||
gasPriceFixedCost = 3000000u,
|
||||
gethGasPriceUpdateRecipients = listOf(
|
||||
URI("http://traces-node:8545/").toURL(),
|
||||
URI("http://l2-node:8545/").toURL()
|
||||
private val l2NetworkGasPricingRequestRetryConfig = RequestRetryConfig(
|
||||
maxRetries = 3u,
|
||||
timeout = 6.seconds,
|
||||
backoffDelay = 1.seconds,
|
||||
failuresWarningThreshold = 2u
|
||||
)
|
||||
|
||||
private val l2NetworkGasPricingServiceConfig = L2NetworkGasPricingService.Config(
|
||||
feeHistoryFetcherConfig = FeeHistoryFetcherImpl.Config(
|
||||
feeHistoryBlockCount = 50U,
|
||||
feeHistoryRewardPercentile = 15.0
|
||||
),
|
||||
besuGasPriceUpdateRecipients = listOf(
|
||||
URI("http://sequencer:8545/").toURL()
|
||||
jsonRpcPricingPropagationEnabled = true,
|
||||
legacy = L2NetworkGasPricingService.LegacyGasPricingCalculatorConfig(
|
||||
legacyGasPricingCalculatorBounds = BoundableFeeCalculator.Config(
|
||||
feeUpperBound = 10_000_000_000.0,
|
||||
feeLowerBound = 90_000_000.0,
|
||||
feeMargin = 0.0
|
||||
),
|
||||
transactionCostCalculatorConfig = TransactionCostCalculator.Config(
|
||||
sampleTransactionCostMultiplier = 1.0,
|
||||
fixedCostWei = 3000000u,
|
||||
compressedTxSize = 125,
|
||||
expectedGas = 21000
|
||||
),
|
||||
naiveGasPricingCalculatorConfig = null
|
||||
),
|
||||
requestRetry = RequestRetryConfigTomlFriendly(
|
||||
maxRetries = 3,
|
||||
timeout = 6.seconds.toJavaDuration(),
|
||||
backoffDelay = 1.seconds.toJavaDuration(),
|
||||
failuresWarningThreshold = 2
|
||||
jsonRpcGasPriceUpdaterConfig = GasPriceUpdaterImpl.Config(
|
||||
gethEndpoints = listOf(
|
||||
URI("http://traces-node:8545/").toURL(),
|
||||
URI("http://l2-node:8545/").toURL()
|
||||
),
|
||||
besuEndPoints = listOf(
|
||||
URI("http://sequencer:8545/").toURL()
|
||||
),
|
||||
retryConfig = l2NetworkGasPricingRequestRetryConfig
|
||||
),
|
||||
extraDataEnabled = true,
|
||||
minMineableFeesEnabled = true,
|
||||
legacyFeesMultiplier = 1.2,
|
||||
margin = 4.0,
|
||||
extraDataUpdateRecipient = URI("http://sequencer:8545/").toURL(),
|
||||
variableCostUpperBound = 10_000_000_001u,
|
||||
variableCostLowerBound = 90_000_001u,
|
||||
_bytesPerDataSubmission = null
|
||||
jsonRpcPriceUpdateInterval = 12.seconds,
|
||||
extraDataPricingPropagationEnabled = true,
|
||||
extraDataUpdateInterval = 12.seconds,
|
||||
variableFeesCalculatorConfig = VariableFeesCalculator.Config(
|
||||
blobSubmissionExpectedExecutionGas = 213_000u,
|
||||
bytesPerDataSubmission = 131072u,
|
||||
expectedBlobGas = 131072u,
|
||||
margin = 4.0
|
||||
),
|
||||
variableFeesCalculatorBounds = BoundableFeeCalculator.Config(
|
||||
feeUpperBound = 10_000_000_001.0,
|
||||
feeLowerBound = 90_000_001.0,
|
||||
feeMargin = 0.0
|
||||
),
|
||||
extraDataCalculatorConfig = MinerExtraDataV1CalculatorImpl.Config(
|
||||
fixedCostInKWei = 3000u,
|
||||
ethGasPriceMultiplier = 1.2
|
||||
),
|
||||
extraDataUpdaterConfig = ExtraDataV1UpdaterImpl.Config(
|
||||
sequencerEndpoint = URI(/* str = */ "http://sequencer:8545/").toURL(),
|
||||
retryConfig = l2NetworkGasPricingRequestRetryConfig
|
||||
)
|
||||
)
|
||||
|
||||
private val l1DynamicGasPriceCapServiceConfig = L1DynamicGasPriceCapServiceConfig(
|
||||
@@ -648,7 +682,7 @@ class CoordinatorConfigTest {
|
||||
api = apiConfig,
|
||||
l2Signer = l2SignerConfig,
|
||||
messageAnchoringService = messageAnchoringServiceConfig,
|
||||
dynamicGasPriceService = dynamicGasPriceServiceConfig,
|
||||
l2NetworkGasPricingService = l2NetworkGasPricingServiceConfig,
|
||||
l1DynamicGasPriceCapService = l1DynamicGasPriceCapServiceConfig,
|
||||
proversConfig = proversConfig
|
||||
)
|
||||
|
||||
@@ -0,0 +1,363 @@
|
||||
package net.consensys.zkevm.coordinator.app.config
|
||||
|
||||
import com.sksamuel.hoplite.ConfigLoaderBuilder
|
||||
import com.sksamuel.hoplite.toml.TomlPropertySource
|
||||
import net.consensys.linea.ethereum.gaspricing.BoundableFeeCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.ExtraDataV1UpdaterImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.FeeHistoryFetcherImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.GasPriceUpdaterImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.GasUsageRatioWeightedAverageFeesCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.MinerExtraDataV1CalculatorImpl
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.TransactionCostCalculator
|
||||
import net.consensys.linea.ethereum.gaspricing.staticcap.VariableFeesCalculator
|
||||
import net.consensys.linea.jsonrpc.client.RequestRetryConfig
|
||||
import net.consensys.zkevm.coordinator.app.L2NetworkGasPricingService
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.net.URI
|
||||
import java.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.toJavaDuration
|
||||
|
||||
class L2NetworkGasPricingConfigTest {
|
||||
data class Config(
|
||||
val l2NetworkGasPricing: L2NetworkGasPricingTomlDto
|
||||
)
|
||||
|
||||
private fun parseConfig(toml: String): L2NetworkGasPricingTomlDto {
|
||||
return ConfigLoaderBuilder
|
||||
.default()
|
||||
.addSource(TomlPropertySource(toml))
|
||||
.build()
|
||||
.loadConfigOrThrow<Config>().l2NetworkGasPricing
|
||||
}
|
||||
|
||||
private val naiveL2NetworkGasPricingServiceConfigToml = """
|
||||
[l2-network-gas-pricing]
|
||||
disabled = false
|
||||
price-update-interval = "PT12S"
|
||||
|
||||
fee-history-block-count = 50
|
||||
fee-history-reward-percentile = 15
|
||||
|
||||
blob-submission-expected-execution-gas = 213000.0 # Lower to 120k as we improve efficiency
|
||||
# Defaults to expected-blob-gas
|
||||
#bytes-per-data-submission=131072.0 # 2^17
|
||||
l1-blob-gas = 131072 # 2^17
|
||||
|
||||
[l2-network-gas-pricing.request-retry]
|
||||
max-retries = 3
|
||||
timeout = "PT6S"
|
||||
backoff-delay = "PT1S"
|
||||
failures-warning-threshold = 2
|
||||
|
||||
[l2-network-gas-pricing.variable-cost-pricing]
|
||||
gas-price-fixed-cost = 3000000
|
||||
legacy-fees-multiplier = 1.2
|
||||
margin = 4.0
|
||||
variable-cost-upper-bound = 10000000001 # ~10 GWEI
|
||||
variable-cost-lower-bound = 90000001 # ~0.09 GWEI
|
||||
|
||||
[l2-network-gas-pricing.extra-data-pricing-propagation]
|
||||
extra-data-update-recipient = "http://sequencer:8545/"
|
||||
|
||||
[l2-network-gas-pricing.legacy]
|
||||
type="Naive"
|
||||
gas-price-upper-bound = 10000000000 # 10 GWEI
|
||||
gas-price-lower-bound = 90000000 # 0.09 GWEI
|
||||
|
||||
[l2-network-gas-pricing.legacy.naive-gas-pricing]
|
||||
base-fee-coefficient = 0.1
|
||||
priority-fee-coefficient = 1.0
|
||||
base-fee-blob-coefficient = 0.1
|
||||
|
||||
|
||||
[l2-network-gas-pricing.json-rpc-pricing-propagation]
|
||||
geth-gas-price-update-recipients = [
|
||||
"http://traces-node:8545/",
|
||||
"http://l2-node:8545/"
|
||||
]
|
||||
besu-gas-price-update-recipients = [
|
||||
"http://sequencer:8545/"
|
||||
]
|
||||
""".trimIndent()
|
||||
|
||||
private val sampleTransactionL2NetworkGasPricingServiceConfigToml = """
|
||||
[l2-network-gas-pricing]
|
||||
disabled = false
|
||||
price-update-interval = "PT12S"
|
||||
|
||||
fee-history-block-count = 50
|
||||
fee-history-reward-percentile = 15
|
||||
|
||||
blob-submission-expected-execution-gas = 213000.0 # Lower to 120k as we improve efficiency
|
||||
# Defaults to expected-blob-gas
|
||||
#bytes-per-data-submission=131072.0 # 2^17
|
||||
l1-blob-gas = 131072 # 2^17
|
||||
|
||||
[l2-network-gas-pricing.request-retry]
|
||||
max-retries = 3
|
||||
timeout = "PT6S"
|
||||
backoff-delay = "PT1S"
|
||||
failures-warning-threshold = 2
|
||||
|
||||
[l2-network-gas-pricing.variable-cost-pricing]
|
||||
gas-price-fixed-cost = 3000000
|
||||
legacy-fees-multiplier = 1.2
|
||||
margin = 4.0
|
||||
variable-cost-upper-bound = 10000000001 # ~10 GWEI
|
||||
variable-cost-lower-bound = 90000001 # ~0.09 GWEI
|
||||
|
||||
[l2-network-gas-pricing.extra-data-pricing-propagation]
|
||||
extra-data-update-recipient = "http://sequencer:8545/"
|
||||
|
||||
[l2-network-gas-pricing.legacy]
|
||||
type="SampleTransaction"
|
||||
gas-price-upper-bound = 10000000000 # 10 GWEI
|
||||
gas-price-lower-bound = 90000000 # 0.09 GWEI
|
||||
|
||||
[l2-network-gas-pricing.json-rpc-pricing-propagation]
|
||||
geth-gas-price-update-recipients = [
|
||||
"http://traces-node:8545/",
|
||||
"http://l2-node:8545/"
|
||||
]
|
||||
besu-gas-price-update-recipients = [
|
||||
"http://sequencer:8545/"
|
||||
]
|
||||
""".trimIndent()
|
||||
|
||||
@Test
|
||||
fun `dto with naive legacy gas calculator is parseable`() {
|
||||
val config = parseConfig(naiveL2NetworkGasPricingServiceConfigToml)
|
||||
assertThat(config).isEqualTo(
|
||||
L2NetworkGasPricingTomlDto(
|
||||
requestRetry = RequestRetryConfigTomlFriendly(
|
||||
maxRetries = 3,
|
||||
timeout = 6.seconds.toJavaDuration(),
|
||||
backoffDelay = 1.seconds.toJavaDuration(),
|
||||
failuresWarningThreshold = 2
|
||||
),
|
||||
|
||||
priceUpdateInterval = Duration.parse("PT12S"),
|
||||
feeHistoryBlockCount = 50,
|
||||
feeHistoryRewardPercentile = 15.0,
|
||||
|
||||
blobSubmissionExpectedExecutionGas = 213_000,
|
||||
_bytesPerDataSubmission = null,
|
||||
l1BlobGas = 131072,
|
||||
legacy = LegacyGasPricingTomlDto(
|
||||
type = LegacyGasPricingTomlDto.Type.Naive,
|
||||
gasPriceUpperBound = 10_000_000_000u,
|
||||
gasPriceLowerBound = 90_000_000u,
|
||||
naiveGasPricing = NaiveGasPricingTomlDto(
|
||||
baseFeeCoefficient = 0.1,
|
||||
priorityFeeCoefficient = 1.0,
|
||||
baseFeeBlobCoefficient = 0.1
|
||||
)
|
||||
),
|
||||
variableCostPricing = VariableCostPricingTomlDto(
|
||||
gasPriceFixedCost = 3000000u,
|
||||
legacyFeesMultiplier = 1.2,
|
||||
margin = 4.0,
|
||||
variableCostUpperBound = 10_000_000_001u,
|
||||
variableCostLowerBound = 90_000_001u
|
||||
),
|
||||
jsonRpcPricingPropagation = JsonRpcPricingPropagationTomlDto(
|
||||
gethGasPriceUpdateRecipients = listOf(
|
||||
URI("http://traces-node:8545/").toURL(),
|
||||
URI("http://l2-node:8545/").toURL()
|
||||
),
|
||||
besuGasPriceUpdateRecipients = listOf(
|
||||
URI("http://sequencer:8545/").toURL()
|
||||
)
|
||||
),
|
||||
extraDataPricingPropagation = ExtraDataPricingPropagationTomlDto(
|
||||
extraDataUpdateRecipient = URI("http://sequencer:8545/").toURL()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `dto with sample transaction legacy gas calculator is parseable`() {
|
||||
val config = parseConfig(sampleTransactionL2NetworkGasPricingServiceConfigToml)
|
||||
assertThat(config).isEqualTo(
|
||||
L2NetworkGasPricingTomlDto(
|
||||
requestRetry = RequestRetryConfigTomlFriendly(
|
||||
maxRetries = 3,
|
||||
timeout = 6.seconds.toJavaDuration(),
|
||||
backoffDelay = 1.seconds.toJavaDuration(),
|
||||
failuresWarningThreshold = 2
|
||||
),
|
||||
|
||||
priceUpdateInterval = Duration.parse("PT12S"),
|
||||
feeHistoryBlockCount = 50,
|
||||
feeHistoryRewardPercentile = 15.0,
|
||||
|
||||
blobSubmissionExpectedExecutionGas = 213_000,
|
||||
_bytesPerDataSubmission = null,
|
||||
l1BlobGas = 131072,
|
||||
legacy = LegacyGasPricingTomlDto(
|
||||
type = LegacyGasPricingTomlDto.Type.SampleTransaction,
|
||||
gasPriceUpperBound = 10_000_000_000u,
|
||||
gasPriceLowerBound = 90_000_000u,
|
||||
naiveGasPricing = null
|
||||
),
|
||||
variableCostPricing = VariableCostPricingTomlDto(
|
||||
gasPriceFixedCost = 3000000u,
|
||||
legacyFeesMultiplier = 1.2,
|
||||
margin = 4.0,
|
||||
variableCostUpperBound = 10_000_000_001u,
|
||||
variableCostLowerBound = 90_000_001u
|
||||
),
|
||||
jsonRpcPricingPropagation = JsonRpcPricingPropagationTomlDto(
|
||||
gethGasPriceUpdateRecipients = listOf(
|
||||
URI("http://traces-node:8545/").toURL(),
|
||||
URI("http://l2-node:8545/").toURL()
|
||||
),
|
||||
besuGasPriceUpdateRecipients = listOf(
|
||||
URI("http://sequencer:8545/").toURL()
|
||||
)
|
||||
),
|
||||
extraDataPricingPropagation = ExtraDataPricingPropagationTomlDto(
|
||||
extraDataUpdateRecipient = URI("http://sequencer:8545/").toURL()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reification is correct`() {
|
||||
val config = parseConfig(naiveL2NetworkGasPricingServiceConfigToml).reified()
|
||||
val l2NetworkGasPricingRequestretryConfig = RequestRetryConfig(
|
||||
maxRetries = 3u,
|
||||
timeout = 6.seconds,
|
||||
backoffDelay = 1.seconds,
|
||||
failuresWarningThreshold = 2u
|
||||
)
|
||||
|
||||
assertThat(config).isEqualTo(
|
||||
L2NetworkGasPricingService.Config(
|
||||
feeHistoryFetcherConfig = FeeHistoryFetcherImpl.Config(
|
||||
feeHistoryBlockCount = 50U,
|
||||
feeHistoryRewardPercentile = 15.0
|
||||
),
|
||||
jsonRpcPricingPropagationEnabled = true,
|
||||
legacy = L2NetworkGasPricingService.LegacyGasPricingCalculatorConfig(
|
||||
naiveGasPricingCalculatorConfig = GasUsageRatioWeightedAverageFeesCalculator.Config(
|
||||
baseFeeCoefficient = 0.1,
|
||||
priorityFeeCoefficient = 1.0,
|
||||
baseFeeBlobCoefficient = 0.1,
|
||||
blobSubmissionExpectedExecutionGas = 213_000,
|
||||
expectedBlobGas = 131072
|
||||
),
|
||||
legacyGasPricingCalculatorBounds = BoundableFeeCalculator.Config(
|
||||
10_000_000_000.0,
|
||||
90_000_000.0,
|
||||
0.0
|
||||
),
|
||||
transactionCostCalculatorConfig = null
|
||||
),
|
||||
jsonRpcGasPriceUpdaterConfig = GasPriceUpdaterImpl.Config(
|
||||
gethEndpoints = listOf(
|
||||
URI("http://traces-node:8545/").toURL(),
|
||||
URI("http://l2-node:8545/").toURL()
|
||||
),
|
||||
besuEndPoints = listOf(
|
||||
URI("http://sequencer:8545/").toURL()
|
||||
),
|
||||
retryConfig = l2NetworkGasPricingRequestretryConfig
|
||||
),
|
||||
jsonRpcPriceUpdateInterval = 12.seconds,
|
||||
extraDataPricingPropagationEnabled = true,
|
||||
extraDataUpdateInterval = 12.seconds,
|
||||
variableFeesCalculatorConfig = VariableFeesCalculator.Config(
|
||||
blobSubmissionExpectedExecutionGas = 213_000u,
|
||||
bytesPerDataSubmission = 131072u,
|
||||
expectedBlobGas = 131072u,
|
||||
margin = 4.0
|
||||
),
|
||||
variableFeesCalculatorBounds = BoundableFeeCalculator.Config(
|
||||
feeUpperBound = 10_000_000_001.0,
|
||||
feeLowerBound = 90_000_001.0,
|
||||
feeMargin = 0.0
|
||||
),
|
||||
extraDataCalculatorConfig = MinerExtraDataV1CalculatorImpl.Config(
|
||||
fixedCostInKWei = 3000u,
|
||||
ethGasPriceMultiplier = 1.2
|
||||
),
|
||||
extraDataUpdaterConfig = ExtraDataV1UpdaterImpl.Config(
|
||||
sequencerEndpoint = URI(/* str = */ "http://sequencer:8545/").toURL(),
|
||||
retryConfig = l2NetworkGasPricingRequestretryConfig
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Sample transaction reification is correct`() {
|
||||
val config = parseConfig(sampleTransactionL2NetworkGasPricingServiceConfigToml).reified()
|
||||
val l2NetworkGasPricingRequestretryConfig = RequestRetryConfig(
|
||||
maxRetries = 3u,
|
||||
timeout = 6.seconds,
|
||||
backoffDelay = 1.seconds,
|
||||
failuresWarningThreshold = 2u
|
||||
)
|
||||
|
||||
assertThat(config).isEqualTo(
|
||||
L2NetworkGasPricingService.Config(
|
||||
feeHistoryFetcherConfig = FeeHistoryFetcherImpl.Config(
|
||||
feeHistoryBlockCount = 50U,
|
||||
feeHistoryRewardPercentile = 15.0
|
||||
),
|
||||
jsonRpcPricingPropagationEnabled = true,
|
||||
legacy = L2NetworkGasPricingService.LegacyGasPricingCalculatorConfig(
|
||||
naiveGasPricingCalculatorConfig = null,
|
||||
legacyGasPricingCalculatorBounds = BoundableFeeCalculator.Config(
|
||||
10_000_000_000.0,
|
||||
90_000_000.0,
|
||||
0.0
|
||||
),
|
||||
transactionCostCalculatorConfig = TransactionCostCalculator.Config(
|
||||
sampleTransactionCostMultiplier = 1.0,
|
||||
fixedCostWei = 3000000u,
|
||||
compressedTxSize = 125,
|
||||
expectedGas = 21000
|
||||
)
|
||||
),
|
||||
jsonRpcGasPriceUpdaterConfig = GasPriceUpdaterImpl.Config(
|
||||
gethEndpoints = listOf(
|
||||
URI("http://traces-node:8545/").toURL(),
|
||||
URI("http://l2-node:8545/").toURL()
|
||||
),
|
||||
besuEndPoints = listOf(
|
||||
URI("http://sequencer:8545/").toURL()
|
||||
),
|
||||
retryConfig = l2NetworkGasPricingRequestretryConfig
|
||||
),
|
||||
jsonRpcPriceUpdateInterval = 12.seconds,
|
||||
extraDataPricingPropagationEnabled = true,
|
||||
extraDataUpdateInterval = 12.seconds,
|
||||
variableFeesCalculatorConfig = VariableFeesCalculator.Config(
|
||||
blobSubmissionExpectedExecutionGas = 213_000u,
|
||||
bytesPerDataSubmission = 131072u,
|
||||
expectedBlobGas = 131072u,
|
||||
margin = 4.0
|
||||
),
|
||||
variableFeesCalculatorBounds = BoundableFeeCalculator.Config(
|
||||
feeUpperBound = 10_000_000_001.0,
|
||||
feeLowerBound = 90_000_001.0,
|
||||
feeMargin = 0.0
|
||||
),
|
||||
extraDataCalculatorConfig = MinerExtraDataV1CalculatorImpl.Config(
|
||||
fixedCostInKWei = 3000u,
|
||||
ethGasPriceMultiplier = 1.2
|
||||
),
|
||||
extraDataUpdaterConfig = ExtraDataV1UpdaterImpl.Config(
|
||||
sequencerEndpoint = URI(/* str = */ "http://sequencer:8545/").toURL(),
|
||||
retryConfig = l2NetworkGasPricingRequestretryConfig
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -5,22 +5,22 @@ import net.consensys.zkevm.domain.BlockInterval
|
||||
import tech.pegasys.teku.infrastructure.async.SafeFuture
|
||||
|
||||
class StartBlockNumberBasedSwitchPredicate<ProofRequest>(
|
||||
val switchStartBlockNumberInclusive: ULong
|
||||
private val switchStartBlockNumberInclusive: ULong
|
||||
) where ProofRequest : BlockInterval {
|
||||
fun invoke(proofRequest: ProofRequest): Boolean = proofRequest.startBlockNumber >= switchStartBlockNumberInclusive
|
||||
}
|
||||
|
||||
class ABProverClientRouter<ProofRequest, ProofResponse>(
|
||||
val proverA: ProverClient<ProofRequest, ProofResponse>,
|
||||
val proverB: ProverClient<ProofRequest, ProofResponse>,
|
||||
val switchToProverBPredicate: (ProofRequest) -> Boolean
|
||||
private val proverA: ProverClient<ProofRequest, ProofResponse>,
|
||||
private val proverB: ProverClient<ProofRequest, ProofResponse>,
|
||||
private val switchToProverBPredicate: (ProofRequest) -> Boolean
|
||||
) : ProverClient<ProofRequest, ProofResponse> {
|
||||
|
||||
override fun requestProof(proofRequest: ProofRequest): SafeFuture<ProofResponse> {
|
||||
if (switchToProverBPredicate(proofRequest)) {
|
||||
return proverB.requestProof(proofRequest)
|
||||
return if (switchToProverBPredicate(proofRequest)) {
|
||||
proverB.requestProof(proofRequest)
|
||||
} else {
|
||||
return proverA.requestProof(proofRequest)
|
||||
proverA.requestProof(proofRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,6 @@ class FileBasedExecutionProverClientV2(
|
||||
override fun parseResponse(
|
||||
responseFilePath: Path,
|
||||
proofIndex: ProofIndex
|
||||
|
||||
): SafeFuture<BatchExecutionProofResponse> {
|
||||
return SafeFuture.completedFuture(
|
||||
BatchExecutionProofResponse(
|
||||
|
||||
@@ -138,7 +138,7 @@ open class GenericFileBasedProverClient<Request, Response, RequestDto, ResponseD
|
||||
)
|
||||
}
|
||||
|
||||
open fun parseResponse(
|
||||
protected open fun parseResponse(
|
||||
responseFilePath: Path,
|
||||
proofIndex: ProofIndex
|
||||
): SafeFuture<Response> {
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.web3j.protocol.Web3j
|
||||
class ProverClientFactory(
|
||||
private val vertx: Vertx,
|
||||
private val config: ProversConfig,
|
||||
private val metricsFacade: MetricsFacade
|
||||
metricsFacade: MetricsFacade
|
||||
) {
|
||||
private val executionWaitingResponsesMetric = GaugeAggregator()
|
||||
private val blobWaitingResponsesMetric = GaugeAggregator()
|
||||
|
||||
@@ -10,7 +10,7 @@ interface FeesFetcher {
|
||||
fun getL1EthGasPriceData(): SafeFuture<FeeHistory>
|
||||
}
|
||||
|
||||
interface FeesCalculator {
|
||||
fun interface FeesCalculator {
|
||||
fun calculateFees(feeHistory: FeeHistory): Double
|
||||
}
|
||||
|
||||
|
||||
@@ -91,8 +91,8 @@ class MinMineableFeesPricerServiceIntegrationTest {
|
||||
baseFeeCoefficient = 0.1,
|
||||
priorityFeeCoefficient = 0.1,
|
||||
baseFeeBlobCoefficient = 0.1,
|
||||
blobSubmissionExpectedExecutionGas = 131_000.0,
|
||||
expectedBlobGas = 120_000.0
|
||||
blobSubmissionExpectedExecutionGas = 131_000,
|
||||
expectedBlobGas = 120_000
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ class GasPriceUpdaterImpl(
|
||||
private val httpJsonRpcClientFactory: VertxHttpJsonRpcClientFactory,
|
||||
private val config: Config
|
||||
) : GasPriceUpdater {
|
||||
class Config(
|
||||
data class Config(
|
||||
val gethEndpoints: List<URL>,
|
||||
val besuEndPoints: List<URL>,
|
||||
val retryConfig: RequestRetryConfig
|
||||
|
||||
@@ -19,8 +19,8 @@ class GasUsageRatioWeightedAverageFeesCalculator(
|
||||
val baseFeeCoefficient: Double,
|
||||
val priorityFeeCoefficient: Double,
|
||||
val baseFeeBlobCoefficient: Double,
|
||||
val blobSubmissionExpectedExecutionGas: Double,
|
||||
val expectedBlobGas: Double
|
||||
val blobSubmissionExpectedExecutionGas: Int,
|
||||
val expectedBlobGas: Int
|
||||
)
|
||||
|
||||
private val log: Logger = LogManager.getLogger(this::class.java)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.consensys.linea.ethereum.gaspricing.staticcap
|
||||
|
||||
import net.consensys.linea.FeeHistory
|
||||
import net.consensys.linea.ethereum.gaspricing.FeesCalculator
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
|
||||
/**
|
||||
* This calculator is supposed to compute cost of a plain transfer transaction and multiply it by a constant
|
||||
* Cost of a plain transfer transaction should be computed the same way as on Sequencer
|
||||
* @see <a href=”https://github.com/Consensys/linea-sequencer/blob/main/sequencer/src/main/java/net/consensys/linea/bl/TransactionProfitabilityCalculator.java#L38”>this</a>
|
||||
* */
|
||||
class TransactionCostCalculator(
|
||||
private val dataCostCalculator: FeesCalculator,
|
||||
private val config: Config
|
||||
) : FeesCalculator {
|
||||
data class Config(
|
||||
val sampleTransactionCostMultiplier: Double,
|
||||
val fixedCostWei: ULong,
|
||||
val compressedTxSize: Int = 125,
|
||||
val expectedGas: Int = 21000
|
||||
)
|
||||
|
||||
private val log: Logger = LogManager.getLogger(this::class.java)
|
||||
|
||||
override fun calculateFees(feeHistory: FeeHistory): Double {
|
||||
val dataCostCost = dataCostCalculator.calculateFees(feeHistory)
|
||||
log.trace("Data cost: $dataCostCost")
|
||||
return config.sampleTransactionCostMultiplier *
|
||||
((dataCostCost * config.compressedTxSize / config.expectedGas) + config.fixedCostWei.toDouble())
|
||||
}
|
||||
}
|
||||
@@ -18,16 +18,12 @@ class VariableFeesCalculator(
|
||||
val averageWeightedBlobBaseFeesCalculator: FeesCalculator = AverageWeightedBlobBaseFeesCalculator
|
||||
) : FeesCalculator {
|
||||
data class Config(
|
||||
val blobSubmissionExpectedExecutionGas: Double,
|
||||
val bytesPerDataSubmission: Double,
|
||||
val expectedBlobGas: Double,
|
||||
val blobSubmissionExpectedExecutionGas: UInt,
|
||||
val bytesPerDataSubmission: UInt,
|
||||
val expectedBlobGas: UInt,
|
||||
val margin: Double
|
||||
)
|
||||
|
||||
init {
|
||||
require(config.bytesPerDataSubmission > 0.0)
|
||||
}
|
||||
|
||||
private val log = LogManager.getLogger(this::class.java)
|
||||
|
||||
override fun calculateFees(feeHistory: FeeHistory): Double {
|
||||
@@ -36,11 +32,11 @@ class VariableFeesCalculator(
|
||||
val averageWeightedBlobBaseFees = averageWeightedBlobBaseFeesCalculator.calculateFees(feeHistory)
|
||||
|
||||
val executionFee = (averageWeightedBaseFees + averageWeightedPriorityFees) *
|
||||
config.blobSubmissionExpectedExecutionGas
|
||||
config.blobSubmissionExpectedExecutionGas.toDouble()
|
||||
|
||||
val blobFee = averageWeightedBlobBaseFees * config.expectedBlobGas
|
||||
val blobFee = averageWeightedBlobBaseFees * config.expectedBlobGas.toDouble()
|
||||
|
||||
val variableFee = ((executionFee + blobFee) * config.margin) / config.bytesPerDataSubmission
|
||||
val variableFee = ((executionFee + blobFee) * config.margin) / config.bytesPerDataSubmission.toDouble()
|
||||
|
||||
log.debug(
|
||||
"Calculated variableFee={} wei executionFee={} wei blobFee={} wei bytesPerDataSubmission={} l1Blocks={}",
|
||||
|
||||
@@ -9,8 +9,8 @@ class GasUsageRatioWeightedAverageFeesCalculatorTest {
|
||||
baseFeeCoefficient = 0.1,
|
||||
priorityFeeCoefficient = 1.2,
|
||||
baseFeeBlobCoefficient = 0.1,
|
||||
blobSubmissionExpectedExecutionGas = 120_000.0,
|
||||
expectedBlobGas = 131_000.0
|
||||
blobSubmissionExpectedExecutionGas = 120_000,
|
||||
expectedBlobGas = 131_000
|
||||
)
|
||||
private val feesCalculator = GasUsageRatioWeightedAverageFeesCalculator(config)
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package net.consensys.linea.ethereum.gaspricing.staticcap
|
||||
|
||||
import net.consensys.linea.FeeHistory
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.math.abs
|
||||
|
||||
class TransactionCostCalculatorTest {
|
||||
private val config = TransactionCostCalculator.Config(1.0, 30000000U)
|
||||
private val oldCalculatorConfig = GasUsageRatioWeightedAverageFeesCalculator.Config(
|
||||
// We may want to price L2 gas cheaper than L1 gas
|
||||
baseFeeCoefficient = 0.02,
|
||||
priorityFeeCoefficient = 0.02,
|
||||
baseFeeBlobCoefficient = 0.02,
|
||||
blobSubmissionExpectedExecutionGas = 69000,
|
||||
expectedBlobGas = 131_000
|
||||
)
|
||||
private val legacyFeesCalculator = GasUsageRatioWeightedAverageFeesCalculator(oldCalculatorConfig)
|
||||
|
||||
private val variableFeesCalculatorConfig = VariableFeesCalculator.Config(
|
||||
margin = 1.2,
|
||||
bytesPerDataSubmission = 131_000u,
|
||||
blobSubmissionExpectedExecutionGas = 69000u,
|
||||
expectedBlobGas = 131_000u
|
||||
)
|
||||
private val variableFeesCalculator = VariableFeesCalculator(variableFeesCalculatorConfig)
|
||||
private val transactionCostCalculator = TransactionCostCalculator(variableFeesCalculator, config)
|
||||
|
||||
private val gWei = 1000000000UL
|
||||
|
||||
@Test
|
||||
fun transactionCostCalculatorIsLessSusceptibleToGasSpikes() {
|
||||
val regularL1Fees = FeeHistory(
|
||||
oldestBlock = 100uL,
|
||||
baseFeePerGas = listOf(gWei),
|
||||
reward = listOf(listOf(1000UL)), // not a big impact
|
||||
gasUsedRatio = listOf(0.25),
|
||||
baseFeePerBlobGas = listOf(100UL),
|
||||
blobGasUsedRatio = listOf(0.25)
|
||||
)
|
||||
|
||||
val legacyGasPriceUnderRegularConditions = legacyFeesCalculator.calculateFees(regularL1Fees)
|
||||
val transactionCostUnderRegularConditions = transactionCostCalculator.calculateFees(regularL1Fees)
|
||||
|
||||
// Under regular conditions calculators are comparable
|
||||
assertThat(differenceInPercentage(legacyGasPriceUnderRegularConditions, transactionCostUnderRegularConditions))
|
||||
.isLessThan(1.0)
|
||||
|
||||
val blobGasSpikeL1Fees =
|
||||
regularL1Fees.copy(baseFeePerBlobGas = regularL1Fees.baseFeePerBlobGas.map { 1000UL * gWei })
|
||||
val legacyGasPriceDuringGasSpike = legacyFeesCalculator.calculateFees(blobGasSpikeL1Fees)
|
||||
val transactionCostDuringGasSpike = transactionCostCalculator.calculateFees(blobGasSpikeL1Fees)
|
||||
|
||||
// But during gas spike legacy gas calculator becomes less stable
|
||||
assertThat(legacyGasPriceDuringGasSpike / transactionCostDuringGasSpike).isGreaterThan(2.0)
|
||||
}
|
||||
|
||||
private fun differenceInPercentage(a: Double, b: Double) = abs(a - b) / b
|
||||
}
|
||||
@@ -11,9 +11,9 @@ class VariableFeesCalculatorTest {
|
||||
|
||||
private val config = VariableFeesCalculator.Config(
|
||||
margin = 1.1,
|
||||
bytesPerDataSubmission = 200_000.0,
|
||||
blobSubmissionExpectedExecutionGas = 120_000.0,
|
||||
expectedBlobGas = 131_000.0
|
||||
bytesPerDataSubmission = 200_000u,
|
||||
blobSubmissionExpectedExecutionGas = 120_000u,
|
||||
expectedBlobGas = 131_000u
|
||||
)
|
||||
|
||||
@Test
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"scenarioType": "SelfTransactionWithPayload",
|
||||
"wallet": "source",
|
||||
"nbTransfers": 1,
|
||||
"payload": "custom payload"
|
||||
"payload": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user